Added support for setting specific founder public key in
[silc.git] / apps / irssi / src / silc / core / client_ops.c
index 732812b889a79648df2bdce38efc324e1e718bf0..9a397ddd508b85afc399775cea5dd9ced2b71bd2 100644 (file)
 #include "signals.h"
 #include "levels.h"
 #include "settings.h"
+#include "ignore.h"
 #include "fe-common/core/printtext.h"
 #include "fe-common/core/fe-channels.h"
 #include "fe-common/core/keyboard.h"
+#include "fe-common/core/window-items.h"
 #include "fe-common/silc/module-formats.h"
 
 #include "core.h"
-#include "blob.h"
 
 static void 
 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
@@ -82,6 +83,47 @@ static void silc_get_umode_string(SilcUInt32 mode, char *buf,
     strcat(buf, " [blocks invites]");
 }
 
+/* print "nick appears as" message to every channel of a server */
+static void 
+silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
+                             const char *newnick, const char *oldnick,
+                             const char *address)
+{
+  if (ignore_check(SERVER(server), oldnick, address,
+                  channel, newnick, MSGLEVEL_NICKS))
+    return;
+  
+  printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
+                    SILCTXT_CHANNEL_APPEARS,
+                    oldnick, newnick, channel, address);
+}
+
+static void
+silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
+                      const char *oldnick, const char *address)
+{
+  GSList *tmp, *windows;
+
+  /* Print to each channel/query where the nick is.
+     Don't print more than once to the same window. */
+  windows = NULL;
+    
+  for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
+    CHANNEL_REC *channel = tmp->data;
+    WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
+
+    if (nicklist_find(channel, newnick) == NULL ||
+       g_slist_find(windows, window) != NULL)
+      continue;
+
+    windows = g_slist_append(windows, window);
+    silc_print_nick_change_channel(server, channel->visible_name,
+                                  newnick, oldnick, address);
+  }
+
+  g_slist_free(windows);
+}
+
 void silc_say(SilcClient client, SilcClientConnection conn,
              SilcClientMessageType type, char *msg, ...)
 {
@@ -111,20 +153,6 @@ void silc_say_error(char *msg, ...)
   va_end(va);
 }
 
-void silc_emit_mime_sig(SILC_SERVER_REC *server, SILC_CHANNEL_REC *channel,
-                       const char *data, SilcUInt32 data_len,
-                       const char *encoding, const char *type,
-                       const char *nick)
-{
-  BLOB_REC blob;
-
-  blob_fill(&blob);
-  blob.octets = data_len;
-  blob.data = (char *)data;
-
-  signal_emit("mime", 6, server, channel, &blob, encoding, type, nick);
-}
-
 /* Message for a channel. The `sender' is the nickname of the sender 
    received in the packet. The `channel_name' is the name of the channel. */
 
@@ -173,8 +201,9 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
       /* It is something textual, display it */
       message = (const unsigned char *)data;
     } else {
-      silc_emit_mime_sig(server, chanrec, data, data_len, 
-                        enc, type, nick->nick);
+      printformat_module("fe-common/silc", server, channel->channel_name,
+                        MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
+                        nick == NULL ? "[<unknown>]" : nick->nick, type);
       message = NULL;
     }
   }
@@ -255,8 +284,10 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
       /* It is something textual, display it */
       message = (const unsigned char *)data;
     } else {
-      silc_emit_mime_sig(server, NULL, data, data_len, 
-                        enc, type, sender->nickname);
+      printformat_module("fe-common/silc", server, NULL,
+                        MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
+                        sender->nickname ? sender->nickname : "[<unknown>]",
+                        type);
       message = NULL;
     }
   }
@@ -509,7 +540,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
 
     tmp = silc_client_chmode(mode,
                             channel->channel_key ? 
-                            channel->channel_key->cipher->name : "",
+                            silc_cipher_get_name(channel->channel_key) : "",
                             channel->hmac ? 
                             silc_hmac_get_name(channel->hmac) : "");
     
@@ -946,12 +977,13 @@ void silc_command(SilcClient client, SilcClientConnection conn,
   switch (command) {
 
   case SILC_COMMAND_INVITE:
-    printformat_module("fe-common/silc", server, NULL,
-                      MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
-                      cmd_context->argv[2], 
-                      (cmd_context->argv[1][0] == '*' ?
-                       (char *)conn->current_channel->channel_name :
-                       (char *)cmd_context->argv[1]));
+    if (cmd_context->argc > 2)
+      printformat_module("fe-common/silc", server, NULL,
+                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
+                        cmd_context->argv[2], 
+                        (cmd_context->argv[1][0] == '*' ?
+                         (char *)conn->current_channel->channel_name :
+                         (char *)cmd_context->argv[1]));
     break;
 
   case SILC_COMMAND_DETACH:
@@ -1010,8 +1042,6 @@ static void silc_client_join_get_users(SilcClient client,
                       MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC,
                       channel->channel_name, chanrec->topic);
 
-  fe_channels_nicklist(CHANNEL(chanrec), CHANNEL_NICKLIST_FLAG_ALL);
-
   if (founder) {
     if (founder == conn->local_entry)
       printformat_module("fe-common/silc", 
@@ -1044,10 +1074,11 @@ void silc_getkey_cb(bool success, void *context)
 
   if (success) {
     printformat_module("fe-common/silc", NULL, NULL,
-                      MSGLEVEL_CRAP, SILCTXT_GETKEY_VERIFIED, entity, name);
+                      MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, entity, name);
   } else {
     printformat_module("fe-common/silc", NULL, NULL,
-                      MSGLEVEL_CRAP, SILCTXT_GETKEY_DISCARD, entity, name);
+                      MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED,
+                      entity, name);
   }
 
   silc_free(getkey->fingerprint);
@@ -1203,7 +1234,8 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       }
 
       if (attrs)
-       silc_query_attributes_print(server, silc_client, conn, attrs);
+       silc_query_attributes_print(server, silc_client, conn, attrs,
+                                   client_entry);
     }
     break;
     
@@ -1327,7 +1359,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
 
       chanrec = silc_channel_find(server, channel);
       if (!chanrec)
-       chanrec = silc_channel_create(server, channel, TRUE);
+       chanrec = silc_channel_create(server, channel, channel, TRUE);
 
       if (topic) {
        g_free_not_null(chanrec->topic);
@@ -1337,7 +1369,8 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
 
       mode = silc_client_chmode(modei, 
                                channel_entry->channel_key ? 
-                               channel_entry->channel_key->cipher->name : "",
+                               silc_cipher_get_name(channel_entry->
+                                                    channel_key) : "",
                                channel_entry->hmac ? 
                                silc_hmac_get_name(channel_entry->hmac) : "");
       g_free_not_null(chanrec->mode);
@@ -1355,16 +1388,37 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
   case SILC_COMMAND_NICK: 
     {
       char *old;
-      SilcClientEntry client = va_arg(vp, SilcClientEntry);
+      SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
+      GSList *nicks;
       
       if (!success)
        return;
 
+      nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
+      if (nicks != NULL) {
+       char buf[512];
+       SilcClientEntry collider, old;
+
+       old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
+       collider = silc_client_get_client_by_id(client, conn,
+                                               old->id);
+       
+        memset(buf, 0, sizeof(buf));
+        snprintf(buf, sizeof(buf) - 1, "%s@%s",
+                collider->username, collider->hostname);
+       nicklist_rename_unique(SERVER(server),
+                              old, old->nickname,
+                              collider, collider->nickname);
+       silc_print_nick_change(server, collider->nickname,
+                              client_entry->nickname, buf);
+       g_slist_free(nicks);
+      }
+
       old = g_strdup(server->nick);
-      server_change_nick(SERVER(server), client->nickname);
+      server_change_nick(SERVER(server), client_entry->nickname);
       nicklist_rename_unique(SERVER(server),
                             server->conn->local_entry, server->nick,
-                            client, client->nickname);
+                            client_entry, client_entry->nickname);
       signal_emit("message own_nick", 4, server, server->nick, old, "");
       g_free(old);
       break;
@@ -1375,6 +1429,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       char *topic, *name;
       int usercount;
       char users[20];
+      char tmp[256], *cp, *dm = NULL;
       
       if (!success)
        return;
@@ -1383,6 +1438,20 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       name = va_arg(vp, char *);
       topic = va_arg(vp, char *);
       usercount = va_arg(vp, int);
+
+      if (topic && !silc_term_utf8() &&
+         silc_utf8_valid(topic, strlen(topic))) {
+       memset(tmp, 0, sizeof(tmp));
+       cp = tmp;
+       if (strlen(topic) > sizeof(tmp) - 1) {
+         dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
+         cp = dm;
+       }
+
+       silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
+                        cp, strlen(topic));
+       topic = cp;
+      }
       
       if (status == SILC_STATUS_LIST_START ||
          status == SILC_STATUS_OK)
@@ -1396,12 +1465,14 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_LIST,
                         name, users, topic ? topic : "");
+      silc_free(dm);
     }
     break;
     
   case SILC_COMMAND_UMODE:
     {
       SilcUInt32 mode;
+      char *reason;
       
       if (!success)
        return;
@@ -1418,6 +1489,20 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        printformat_module("fe-common/silc", server, NULL,
                           MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
 
+      if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
+       if (mode & SILC_UMODE_GONE) {      
+         if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
+           reason = g_strdup(server->away_reason);
+         else
+           reason = g_strdup("away");
+       } else
+         reason = g_strdup("");
+
+       silc_set_away(reason, server);
+
+       g_free(reason);
+      }
+
       server->umode = mode;
       signal_emit("user mode changed", 2, server, NULL);
     }
@@ -1564,7 +1649,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        silc_free(pk);
       } else {
        printformat_module("fe-common/silc", server, NULL,
-                          MSGLEVEL_CRAP, SILCTXT_GETKEY_NOKEY);
+                          MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOKEY);
       }
     }
     break;
@@ -1594,13 +1679,28 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     {
       SilcChannelEntry channel;
       char *topic;
+      char tmp[256], *cp, *dm = NULL;
       
       if (!success)
        return;
       
       channel = va_arg(vp, SilcChannelEntry);
       topic = va_arg(vp, char *);
-      
+
+      if (topic && !silc_term_utf8() &&
+         silc_utf8_valid(topic, strlen(topic))) {
+       memset(tmp, 0, sizeof(tmp));
+       cp = tmp;
+       if (strlen(topic) > sizeof(tmp) - 1) {
+         dm = silc_calloc(strlen(topic) + 1, sizeof(*dm));
+         cp = dm;
+       }
+
+       silc_utf8_decode(topic, strlen(topic), SILC_STRING_LANGUAGE,
+                        cp, strlen(topic));
+       topic = cp;
+      }
+
       if (topic) {
        chanrec = silc_channel_find_entry(server, channel);
        if (chanrec) {
@@ -1616,6 +1716,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
                           MSGLEVEL_CRAP, SILCTXT_CHANNEL_TOPIC_NOT_SET,
                           channel->channel_name);
       }
+      silc_free(dm);
     }
     break;
 
@@ -1890,8 +1991,7 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   verify->entity_name = (conn_type != SILC_SOCKET_TYPE_CLIENT ?
                         (name ? strdup(name) : strdup(conn->sock->hostname))
                         : NULL);
-  verify->pk = silc_calloc(pk_len, sizeof(*verify->pk));
-  memcpy(verify->pk, pk, pk_len);
+  verify->pk = silc_memdup(pk, pk_len);
   verify->pk_len = pk_len;
   verify->pk_type = pk_type;
   verify->completion = completion;
@@ -1999,6 +2099,11 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
     if (completion)
       completion(TRUE, context);
     silc_free(fingerprint);
+    silc_free(verify->filename);
+    silc_free(verify->entity);
+    silc_free(verify->entity_name);
+    silc_free(verify->pk);
+    silc_free(verify);
   }
 }
 
@@ -2070,9 +2175,20 @@ static void silc_get_auth_method_callback(SilcClient client,
     (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
     break;
   case SILC_AUTH_PASSWORD:
-    /* Do not ask the passphrase from user, the library will ask it if
-       we do not provide it here. */
-    (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
+    {
+      /* Check whether we find the password for this server in our
+        configuration.  If not, then don't provide so library will ask
+        it from the user. */
+      SERVER_SETUP_REC *setup = server_setup_find_port(conn->remote_host,
+                                                      conn->remote_port);
+      if (!setup || !setup->password) {
+       (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
+       break;
+      }
+      
+      (*internal->completion)(TRUE, auth_meth, setup->password,
+                             strlen(setup->password), internal->context);
+    }
     break;
   case SILC_AUTH_PUBLIC_KEY:
     /* Do not get the authentication data now, the library will generate
@@ -2100,9 +2216,6 @@ void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
 
   SILC_LOG_DEBUG(("Start"));
 
-  /* XXX must resolve from configuration whether this connection has
-     any specific authentication data */
-
   /* If we do not have this connection configured by the user in a
      configuration file then resolve the authentication method from the
      server for this session. */
@@ -2175,10 +2288,10 @@ void silc_failure(SilcClient client, SilcClientConnection conn,
    desired (application may start it later by calling the function
    silc_client_perform_key_agreement). */
 
-int silc_key_agreement(SilcClient client, SilcClientConnection conn,
-                      SilcClientEntry client_entry, const char *hostname,
-                      SilcUInt16 port, SilcKeyAgreementCallback *completion,
-                      void **context)
+bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
+                       SilcClientEntry client_entry, const char *hostname,
+                       SilcUInt16 port, SilcKeyAgreementCallback *completion,
+                       void **context)
 {
   char portstr[12];
 
@@ -2217,18 +2330,29 @@ void silc_ftp(SilcClient client, SilcClientConnection conn,
 {
   SILC_SERVER_REC *server;
   char portstr[12];
-  FtpSession ftp = silc_calloc(1, sizeof(*ftp));
+  FtpSession ftp = NULL;
 
   SILC_LOG_DEBUG(("Start"));
 
   server = conn->context;
 
-  ftp->client_entry = client_entry;
-  ftp->session_id = session_id;
-  ftp->send = FALSE;
-  ftp->conn = conn;
-  silc_dlist_add(server->ftp_sessions, ftp);
-  server->current_session = ftp;
+  silc_dlist_start(server->ftp_sessions);
+  while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
+    if (ftp->client_entry == client_entry &&
+       ftp->session_id == session_id) {
+      server->current_session = ftp;
+      break;
+    }
+  }
+  if (ftp == SILC_LIST_END) {
+    ftp = silc_calloc(1, sizeof(*ftp));
+    ftp->client_entry = client_entry;
+    ftp->session_id = session_id;
+    ftp->send = FALSE;
+    ftp->conn = conn;
+    silc_dlist_add(server->ftp_sessions, ftp);
+    server->current_session = ftp;
+  }
 
   if (hostname) 
     snprintf(portstr, sizeof(portstr) - 1, "%d", port);