Integer type name change.
[silc.git] / apps / irssi / src / silc / core / client_ops.c
index 9d7d7d86828499030bb7d5826a2a91dc28a42464..6d8e905bb4ee7b5359bfe2af424f1e618fbff608 100644 (file)
@@ -40,8 +40,9 @@
 
 static void 
 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
-                               SilcSocketType conn_type, unsigned char *pk, 
-                               uint32 pk_len, SilcSKEPKType pk_type,
+                               const char *name, SilcSocketType conn_type, 
+                               unsigned char *pk, SilcUInt32 pk_len, 
+                               SilcSKEPKType pk_type,
                                SilcVerifyPublicKey completion, void *context);
 
 void silc_say(SilcClient client, SilcClientConnection conn,
@@ -86,6 +87,9 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
   
   SILC_LOG_DEBUG(("Start"));
 
+  if (!msg)
+    return;
+
   server = conn == NULL ? NULL : conn->context;
   chanrec = silc_channel_find_entry(server, channel);
   if (!chanrec)
@@ -94,15 +98,9 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
   nick = silc_nicklist_find(chanrec, sender);
   if (!nick) {
     /* We didn't find client but it clearly exists, add it. */
-    SilcChannelUser chu;
-
-    silc_list_start(channel->clients);
-    while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
-      if (chu->client == sender) {
-       nick = silc_nicklist_insert(chanrec, chu, FALSE);
-       break;
-      }
-    }
+    SilcChannelUser chu = silc_client_on_channel(channel, sender);
+    if (chu)
+      nick = silc_nicklist_insert(chanrec, chu, FALSE);
   }
 
   if (flags & SILC_MESSAGE_FLAG_ACTION)
@@ -150,54 +148,409 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
    for channel the channel entry is sent to application (even if server
    does not send it). */
 
-typedef struct {
-  int type;
-  const char *name;
-} NOTIFY_REC;
-
-#define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0]))
-static NOTIFY_REC notifies[] = {
-  { SILC_NOTIFY_TYPE_NONE,             NULL },
-  { SILC_NOTIFY_TYPE_INVITE,           "invite" },
-  { SILC_NOTIFY_TYPE_JOIN,             "join" },
-  { SILC_NOTIFY_TYPE_LEAVE,            "leave" },
-  { SILC_NOTIFY_TYPE_SIGNOFF,          "signoff" },
-  { SILC_NOTIFY_TYPE_TOPIC_SET,                "topic" },
-  { SILC_NOTIFY_TYPE_NICK_CHANGE,      "nick" },
-  { SILC_NOTIFY_TYPE_CMODE_CHANGE,     "cmode" },
-  { SILC_NOTIFY_TYPE_CUMODE_CHANGE,    "cumode" },
-  { SILC_NOTIFY_TYPE_MOTD,             "motd" },
-  { SILC_NOTIFY_TYPE_CHANNEL_CHANGE,   "channel_change" },
-  { SILC_NOTIFY_TYPE_SERVER_SIGNOFF,   "server_signoff" },
-  { SILC_NOTIFY_TYPE_KICKED,           "kick" },
-  { SILC_NOTIFY_TYPE_KILLED,           "kill" },
-  { SILC_NOTIFY_TYPE_UMODE_CHANGE,      "umode" },
-  { SILC_NOTIFY_TYPE_BAN,               "ban" },
-};
-
 void silc_notify(SilcClient client, SilcClientConnection conn,
                 SilcNotifyType type, ...)
 {
-  SILC_SERVER_REC *server;
   va_list va;
-  
+  SILC_SERVER_REC *server;
+  SILC_CHANNEL_REC *chanrec;
+  SILC_NICK_REC *nickrec;
+  SilcClientEntry client_entry, client_entry2;
+  SilcChannelEntry channel;
+  SilcServerEntry server_entry;
+  SilcIdType idtype;
+  void *entry;
+  SilcUInt32 mode;
+  char userhost[512];
+  char *name, *tmp;
+  GSList *list1, *list_tmp;
+
   SILC_LOG_DEBUG(("Start"));
 
-  server = conn == NULL ? NULL : conn->context;
   va_start(va, type);
+
+  server = conn == NULL ? NULL : conn->context;
   
-  if (type == SILC_NOTIFY_TYPE_NONE) {
+  switch(type) {
+  case SILC_NOTIFY_TYPE_NONE:
     /* Some generic notice from server */
     printtext(server, NULL, MSGLEVEL_CRAP, "%s", (char *)va_arg(va, char *));
-  } else if (type < MAX_NOTIFY) {
-    /* Send signal about the notify event */
-    char signal[50];
-    g_snprintf(signal, sizeof(signal), "silc event %s", notifies[type].name);
-    signal_emit(signal, 2, server, va);
-  } else {
+    break;
+
+  case SILC_NOTIFY_TYPE_INVITE:
+    /*
+     * Invited or modified invite list.
+     */
+
+    SILC_LOG_DEBUG(("Notify: INVITE"));
+
+    channel = va_arg(va, SilcChannelEntry);
+    name = va_arg(va, char *);
+    client_entry = va_arg(va, SilcClientEntry);
+
+    memset(userhost, 0, sizeof(userhost));
+    snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
+            client_entry->username, client_entry->hostname);
+    signal_emit("message invite", 4, server, channel ? channel->channel_name :
+               name, client_entry->nickname, userhost);
+    break;
+
+  case SILC_NOTIFY_TYPE_JOIN:
+    /*
+     * Joined channel.
+     */
+    SILC_LOG_DEBUG(("Notify: JOIN"));
+
+    client_entry = va_arg(va, SilcClientEntry);
+    channel = va_arg(va, SilcChannelEntry);
+
+    if (client_entry == server->conn->local_entry) {
+      /* You joined to channel */
+      chanrec = silc_channel_find(server, channel->channel_name);
+      if (chanrec != NULL && !chanrec->joined)
+       chanrec->entry = channel;
+    } else {
+      chanrec = silc_channel_find_entry(server, channel);
+      if (chanrec != NULL) {
+       SilcChannelUser chu = silc_client_on_channel(channel, client_entry);
+       if (chu)
+         nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
+      }
+    }
+    
+    memset(userhost, 0, sizeof(userhost));
+    if (client_entry->username)
+    snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
+            client_entry->username, client_entry->hostname);
+    signal_emit("message join", 4, server, channel->channel_name,
+               client_entry->nickname,
+               client_entry->username == NULL ? "" : userhost);
+    break;
+
+  case SILC_NOTIFY_TYPE_LEAVE:
+    /*
+     * Left a channel.
+     */
+
+    SILC_LOG_DEBUG(("Notify: LEAVE"));
+
+    client_entry = va_arg(va, SilcClientEntry);
+    channel = va_arg(va, SilcChannelEntry);
+    
+    memset(userhost, 0, sizeof(userhost));
+    if (client_entry->username)
+      snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
+              client_entry->username, client_entry->hostname);
+    signal_emit("message part", 5, server, channel->channel_name,
+               client_entry->nickname,  client_entry->username ? 
+               userhost : "", client_entry->nickname);
+    
+    chanrec = silc_channel_find_entry(server, channel);
+    if (chanrec != NULL) {
+      nickrec = silc_nicklist_find(chanrec, client_entry);
+      if (nickrec != NULL)
+       nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
+    }
+    break;
+
+  case SILC_NOTIFY_TYPE_SIGNOFF:
+    /*
+     * Left the network.
+     */
+
+    SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+
+    client_entry = va_arg(va, SilcClientEntry);
+    tmp = va_arg(va, char *);
+    
+    silc_server_free_ftp(server, client_entry);
+    
+    memset(userhost, 0, sizeof(userhost));
+    if (client_entry->username)
+      snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
+              client_entry->username, client_entry->hostname);
+    signal_emit("message quit", 4, server, client_entry->nickname,
+               client_entry->username ? userhost : "", 
+               tmp ? tmp : "");
+    
+    list1 = nicklist_get_same_unique(SERVER(server), client_entry);
+    for (list_tmp = list1; list_tmp != NULL; list_tmp = 
+          list_tmp->next->next) {
+      CHANNEL_REC *channel = list_tmp->data;
+      NICK_REC *nickrec = list_tmp->next->data;
+      
+      nicklist_remove(channel, nickrec);
+    }
+    break;
+
+  case SILC_NOTIFY_TYPE_TOPIC_SET:
+    /*
+     * Changed topic.
+     */
+
+    SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
+
+    idtype = va_arg(va, int);
+    entry = va_arg(va, void *);
+    tmp = va_arg(va, char *);
+    channel = va_arg(va, SilcChannelEntry);
+    
+    chanrec = silc_channel_find_entry(server, channel);
+    if (chanrec != NULL) {
+      g_free_not_null(chanrec->topic);
+      chanrec->topic = *tmp == '\0' ? NULL : g_strdup(tmp);
+      signal_emit("channel topic changed", 1, chanrec);
+    }
+    
+    if (idtype == SILC_ID_CLIENT) {
+      client_entry = (SilcClientEntry)entry;
+      memset(userhost, 0, sizeof(userhost));
+      snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
+              client_entry->username, client_entry->hostname);
+      signal_emit("message topic", 5, server, channel->channel_name,
+                 tmp, client_entry->nickname, userhost);
+    } else if (idtype == SILC_ID_SERVER) {
+      server_entry = (SilcServerEntry)entry;
+      signal_emit("message topic", 5, server, channel->channel_name,
+                 tmp, server_entry->server_name, 
+                 server_entry->server_name);
+    } else {
+      channel = (SilcChannelEntry)entry;
+      signal_emit("message topic", 5, server, channel->channel_name,
+                 tmp, channel->channel_name, channel->channel_name);
+    }
+    break;
+
+  case SILC_NOTIFY_TYPE_NICK_CHANGE:
+    /*
+     * Changed nickname.
+     */
+
+    SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
+
+    client_entry = va_arg(va, SilcClientEntry);
+    client_entry2 = va_arg(va, SilcClientEntry);
+    
+    memset(userhost, 0, sizeof(userhost));
+    snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
+            client_entry2->username, client_entry2->hostname);
+    nicklist_rename_unique(SERVER(server),
+                          client_entry, client_entry->nickname,
+                          client_entry2, client_entry2->nickname);
+    signal_emit("message nick", 4, server, client_entry2->nickname, 
+               client_entry->nickname, userhost);
+    break;
+
+  case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+    /*
+     * Changed channel mode.
+     */
+
+    SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
+
+    idtype = va_arg(va, int);
+    entry = va_arg(va, void *);
+    mode = va_arg(va, SilcUInt32);
+    (void)va_arg(va, char *);
+    (void)va_arg(va, char *);
+    channel = va_arg(va, SilcChannelEntry);
+
+    tmp = silc_client_chmode(mode,
+                            channel->channel_key ? 
+                            channel->channel_key->cipher->name : "",
+                            channel->hmac ? 
+                            silc_hmac_get_name(channel->hmac) : "");
+    
+    chanrec = silc_channel_find_entry(server, channel);
+    if (chanrec != NULL) {
+      g_free_not_null(chanrec->mode);
+      chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
+      signal_emit("channel mode changed", 1, chanrec);
+    }
+    
+    if (idtype == SILC_ID_CLIENT) {
+      client_entry = (SilcClientEntry)entry;
+      printformat_module("fe-common/silc", server, channel->channel_name,
+                        MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
+                        channel->channel_name, tmp ? tmp : "removed all",
+                        client_entry->nickname);
+    } else if (idtype == SILC_ID_SERVER) {
+      server_entry = (SilcServerEntry)entry;
+      printformat_module("fe-common/silc", server, channel->channel_name,
+                        MSGLEVEL_MODES, SILCTXT_CHANNEL_CMODE,
+                        channel->channel_name, tmp ? tmp : "removed all",
+                        server_entry->server_name);
+    }
+
+    silc_free(tmp);
+    break;
+
+  case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+    /*
+     * Changed user's mode on channel.
+     */
+
+    SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
+
+    client_entry = va_arg(va, SilcClientEntry);
+    mode = va_arg(va, SilcUInt32);
+    client_entry2 = va_arg(va, SilcClientEntry);
+    channel = va_arg(va, SilcChannelEntry);
+    
+    tmp = silc_client_chumode(mode);
+    chanrec = silc_channel_find_entry(server, channel);
+    if (chanrec != NULL) {
+      SILC_NICK_REC *nick;
+      
+      if (client_entry2 == server->conn->local_entry)
+       chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
+      
+      nick = silc_nicklist_find(chanrec, client_entry2);
+      if (nick != NULL) {
+       nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
+       nick->founder = (mode & SILC_CHANNEL_UMODE_CHANFO) != 0;
+       signal_emit("nick mode changed", 2, chanrec, nick);
+      }
+    }
+  
+    printformat_module("fe-common/silc", server, channel->channel_name,
+                      MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
+                      channel->channel_name, client_entry2->nickname, 
+                      tmp ? tmp : "removed all",
+                      client_entry->nickname);
+
+    if (mode & SILC_CHANNEL_UMODE_CHANFO)
+      printformat_module("fe-common/silc", 
+                        server, channel->channel_name, MSGLEVEL_CRAP,
+                        SILCTXT_CHANNEL_FOUNDER,
+                        channel->channel_name, client_entry2->nickname);
+    
+    silc_free(tmp);
+    break;
+
+  case SILC_NOTIFY_TYPE_MOTD:
+    /*
+     * Received MOTD.
+     */
+
+    SILC_LOG_DEBUG(("Notify: MOTD"));
+
+    tmp = va_arg(va, char *);
+
+    if (!settings_get_bool("skip_motd"))
+      printtext_multiline(server, NULL, MSGLEVEL_CRAP, "%s", tmp);
+    break;
+
+  case SILC_NOTIFY_TYPE_KICKED:
+    /*
+     * Someone was kicked from channel.
+     */
+
+    SILC_LOG_DEBUG(("Notify: KICKED"));
+
+    client_entry = va_arg(va, SilcClientEntry);
+    tmp = va_arg(va, char *);
+    client_entry2 = va_arg(va, SilcClientEntry);
+    channel = va_arg(va, SilcChannelEntry);
+
+    chanrec = silc_channel_find_entry(server, channel);
+  
+    if (client_entry == conn->local_entry) {
+      printformat_module("fe-common/silc", server, channel->channel_name,
+                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU, 
+                        channel->channel_name, client_entry2->nickname,
+                        tmp ? tmp : "");
+      if (chanrec) {
+       chanrec->kicked = TRUE;
+       channel_destroy((CHANNEL_REC *)chanrec);
+      }
+    } else {
+      printformat_module("fe-common/silc", server, channel->channel_name,
+                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED, 
+                        client_entry->nickname, channel->channel_name, 
+                        client_entry2->nickname, tmp ? tmp : "");
+
+      if (chanrec) {
+       SILC_NICK_REC *nickrec = silc_nicklist_find(chanrec, client_entry);
+       if (nickrec != NULL)
+         nicklist_remove(CHANNEL(chanrec), NICK(nickrec));
+      }
+    }
+    break;
+
+  case SILC_NOTIFY_TYPE_KILLED:
+    /*
+     * Someone was killed from the network.
+     */
+
+    SILC_LOG_DEBUG(("Notify: KILLED"));
+
+    client_entry = va_arg(va, SilcClientEntry);
+    tmp = va_arg(va, char *);
+  
+    if (client_entry == conn->local_entry) {
+      printformat_module("fe-common/silc", server, NULL,
+                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU, 
+                        tmp ? tmp : "");
+    } else {
+      list1 = nicklist_get_same_unique(SERVER(server), client_entry);
+      for (list_tmp = list1; list_tmp != NULL; list_tmp = 
+            list_tmp->next->next) {
+       CHANNEL_REC *channel = list_tmp->data;
+       NICK_REC *nickrec = list_tmp->next->data;
+       nicklist_remove(channel, nickrec);
+      }
+
+      printformat_module("fe-common/silc", server, NULL,
+                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED, 
+                        client_entry->nickname,
+                        tmp ? tmp : "");
+    }
+    break;
+
+  case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
+    {
+      /*
+       * Server has quit the network.
+       */
+      int i;
+      SilcClientEntry *clients;
+      SilcUInt32 clients_count;
+
+      SILC_LOG_DEBUG(("Notify: SIGNOFF"));
+      
+      (void)va_arg(va, void *);
+      clients = va_arg(va, SilcClientEntry *);
+      clients_count = va_arg(va, SilcUInt32);
+  
+      for (i = 0; i < clients_count; i++) {
+       memset(userhost, 0, sizeof(userhost));
+       if (clients[i]->username)
+         snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
+                  clients[i]->username, clients[i]->hostname);
+       signal_emit("message quit", 4, server, clients[i]->nickname,
+                   clients[i]->username ? userhost : "", 
+                   "server signoff");
+
+       silc_server_free_ftp(server, clients[i]);
+       
+       list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
+       for (list_tmp = list1; list_tmp != NULL; list_tmp = 
+              list_tmp->next->next) {
+         CHANNEL_REC *channel = list_tmp->data;
+         NICK_REC *nickrec = list_tmp->next->data;
+         nicklist_remove(channel, nickrec);
+       }
+      }
+    }
+    break;
+
+  default:
     /* Unknown notify */
     printformat_module("fe-common/silc", server, NULL,
                       MSGLEVEL_CRAP, SILCTXT_UNKNOWN_NOTIFY, type);
+    break;
   }
 
   va_end(va);
@@ -221,7 +574,8 @@ void silc_connect(SilcClient client, SilcClientConnection conn, int success)
     signal_emit("event connected", 1, server);
   } else {
     server->connection_lost = TRUE;
-    server->conn->context = NULL;
+    if (server->conn)
+      server->conn->context = NULL;
     server_disconnect(SERVER(server));
   }
 }
@@ -234,7 +588,7 @@ void silc_disconnect(SilcClient client, SilcClientConnection conn)
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (server->conn) {
+  if (server->conn && server->conn->local_entry) {
     nicklist_rename_unique(SERVER(server),
                           server->conn->local_entry, server->nick,
                           server->conn->local_entry, 
@@ -288,10 +642,11 @@ void silc_command(SilcClient client, SilcClientConnection conn,
 static void silc_client_join_get_users(SilcClient client,
                                       SilcClientConnection conn,
                                       SilcClientEntry *clients,
-                                      uint32 clients_count,
+                                      SilcUInt32 clients_count,
                                       void *context)
 {
   SilcChannelEntry channel = (SilcChannelEntry)context;
+  SilcHashTableList htl;
   SilcChannelUser chu;
   SILC_SERVER_REC *server = conn->context;
   SILC_CHANNEL_REC *chanrec;
@@ -305,14 +660,15 @@ static void silc_client_join_get_users(SilcClient client,
   if (chanrec == NULL)
     return;
 
-  silc_list_start(channel->clients);
-  while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+  silc_hash_table_list(channel->user_list, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
     if (!chu->client->nickname)
       continue;
     if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
       founder = chu->client;
     silc_nicklist_insert(chanrec, chu, FALSE);
   }
+  silc_hash_table_list_reset(&htl);
 
   ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry));
   nicklist_set_own(CHANNEL(chanrec), ownnick);
@@ -402,19 +758,38 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     {
       char buf[1024], *nickname, *username, *realname, *nick;
       unsigned char *fingerprint;
-      uint32 idle, mode;
+      SilcUInt32 idle, mode;
       SilcBuffer channels;
       SilcClientEntry client_entry;
       
-      if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
-         status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
-       char *tmp;
-       tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
-                                        3, NULL);
+      if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+       /* Print the unknown nick for user */
+       unsigned char *tmp =
+         silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+                                    3, NULL);
        if (tmp)
          silc_say_error("%s: %s", tmp, 
                         silc_client_command_status_message(status));
        break;
+      } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+       /* Try to find the entry for the unknown client ID, since we
+          might have, and print the nickname of it for user. */
+       SilcUInt32 tmp_len;
+       unsigned char *tmp =
+         silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+                                    2, &tmp_len);
+       if (tmp) {
+         SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
+         if (client_id) {
+           client_entry = silc_client_get_client_by_id(client, conn,
+                                                       client_id);
+           if (client_entry && client_entry->nickname)
+             silc_say_error("%s: %s", client_entry->nickname,
+                            silc_client_command_status_message(status));
+           silc_free(client_id);
+         }
+       }
+       break;
       }
       
       if (!success)
@@ -425,8 +800,8 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       username = va_arg(vp, char *);
       realname = va_arg(vp, char *);
       channels = va_arg(vp, SilcBuffer);
-      mode = va_arg(vp, uint32);
-      idle = va_arg(vp, uint32);
+      mode = va_arg(vp, SilcUInt32);
+      idle = va_arg(vp, SilcUInt32);
       fingerprint = va_arg(vp, unsigned char *);
       
       silc_parse_userfqdn(nickname, &nick, NULL);
@@ -447,7 +822,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
          silc_dlist_start(list);
          while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
            char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
-           uint32 name_len;
+           SilcUInt32 name_len;
            char *name = silc_channel_get_name(entry, &name_len);
            
            if (m)
@@ -499,6 +874,43 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     }
     break;
     
+  case SILC_COMMAND_IDENTIFY:
+    {
+      SilcClientEntry client_entry;
+      
+      if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+       /* Print the unknown nick for user */
+       unsigned char *tmp =
+         silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+                                    3, NULL);
+       if (tmp)
+         silc_say_error("%s: %s", tmp, 
+                        silc_client_command_status_message(status));
+       break;
+      } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+       /* Try to find the entry for the unknown client ID, since we
+          might have, and print the nickname of it for user. */
+       SilcUInt32 tmp_len;
+       unsigned char *tmp =
+         silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
+                                    2, &tmp_len);
+       if (tmp) {
+         SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
+         if (client_id) {
+           client_entry = silc_client_get_client_by_id(client, conn,
+                                                       client_id);
+           if (client_entry && client_entry->nickname)
+             silc_say_error("%s: %s", client_entry->nickname,
+                            silc_client_command_status_message(status));
+           silc_free(client_id);
+         }
+       }
+       break;
+      }
+
+      break;
+    }
+
   case SILC_COMMAND_WHOWAS:
     {
       char *nickname, *username, *realname;
@@ -559,24 +971,24 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
   case SILC_COMMAND_JOIN: 
     {
       char *channel, *mode, *topic;
-      uint32 modei;
+      SilcUInt32 modei;
       SilcChannelEntry channel_entry;
       SilcBuffer client_id_list;
-      uint32 list_count;
+      SilcUInt32 list_count;
 
       if (!success)
        return;
 
       channel = va_arg(vp, char *);
       channel_entry = va_arg(vp, SilcChannelEntry);
-      modei = va_arg(vp, uint32);
-      (void)va_arg(vp, uint32);
+      modei = va_arg(vp, SilcUInt32);
+      (void)va_arg(vp, SilcUInt32);
       (void)va_arg(vp, unsigned char *);
       (void)va_arg(vp, unsigned char *);
       (void)va_arg(vp, unsigned char *);
       topic = va_arg(vp, char *);
       (void)va_arg(vp, unsigned char *);
-      list_count = va_arg(vp, uint32);
+      list_count = va_arg(vp, SilcUInt32);
       client_id_list = va_arg(vp, SilcBuffer);
 
       chanrec = silc_channel_find(server, channel);
@@ -602,6 +1014,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
                                      silc_client_join_get_users, 
                                      channel_entry);
+
       break;
     }
 
@@ -618,7 +1031,6 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       nicklist_rename_unique(SERVER(server),
                             server->conn->local_entry, server->nick,
                             client, client->nickname);
-      
       signal_emit("message own_nick", 4, server, server->nick, old, "");
       g_free(old);
       break;
@@ -655,20 +1067,24 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     
   case SILC_COMMAND_UMODE:
     {
-      uint32 mode;
+      SilcUInt32 mode;
       
       if (!success)
        return;
       
-      mode = va_arg(vp, uint32);
+      mode = va_arg(vp, SilcUInt32);
       
-      if (mode & SILC_UMODE_SERVER_OPERATOR)
+      if (mode & SILC_UMODE_SERVER_OPERATOR &&
+         !(server->umode & SILC_UMODE_SERVER_OPERATOR))
        printformat_module("fe-common/silc", server, NULL,
                           MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
 
-      if (mode & SILC_UMODE_ROUTER_OPERATOR)
+      if (mode & SILC_UMODE_ROUTER_OPERATOR &&
+         !(server->umode & SILC_UMODE_ROUTER_OPERATOR))
        printformat_module("fe-common/silc", server, NULL,
                           MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
+
+      server->umode = mode;
     }
     break;
     
@@ -690,6 +1106,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     
   case SILC_COMMAND_USERS: 
     {
+      SilcHashTableList htl;
       SilcChannelEntry channel;
       SilcChannelUser chu;
       
@@ -702,8 +1119,8 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
                         MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
                         channel->channel_name);
 
-      silc_list_start(channel->clients);
-      while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+      silc_hash_table_list(channel->user_list, &htl);
+      while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
        SilcClientEntry e = chu->client;
        char stat[5], *mode;
 
@@ -728,6 +1145,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        if (mode)
          silc_free(mode);
       }
+      silc_hash_table_list_reset(&htl);
     }
     break;
 
@@ -759,13 +1177,14 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       void *entry;
       SilcPublicKey public_key;
       unsigned char *pk;
-      uint32 pk_len;
+      SilcUInt32 pk_len;
       GetkeyContext getkey;
+      char *name;
       
       if (!success)
        return;
       
-      id_type = va_arg(vp, uint32);
+      id_type = va_arg(vp, SilcUInt32);
       entry = va_arg(vp, void *);
       public_key = va_arg(vp, SilcPublicKey);
 
@@ -778,8 +1197,12 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        getkey->client = client;
        getkey->conn = conn;
        getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
-       
-       silc_verify_public_key_internal(client, conn, 
+
+       name = (id_type == SILC_ID_CLIENT ? 
+               ((SilcClientEntry)entry)->nickname :
+               ((SilcServerEntry)entry)->server_name);
+
+       silc_verify_public_key_internal(client, conn, name,
                                        (id_type == SILC_ID_CLIENT ?
                                         SILC_SOCKET_TYPE_CLIENT :
                                         SILC_SOCKET_TYPE_SERVER),
@@ -848,16 +1271,14 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
   va_end(vp);
 }
 
-/* Internal routine to verify public key. If the `completion' is provided
-   it will be called to indicate whether public was verified or not. */
-
 typedef struct {
   SilcClient client;
   SilcClientConnection conn;
   char *filename;
   char *entity;
+  char *entity_name;
   unsigned char *pk;
-  uint32 pk_len;
+  SilcUInt32 pk_len;
   SilcSKEPKType pk_type;
   SilcVerifyPublicKey completion;
   void *context;
@@ -881,23 +1302,33 @@ static void verify_public_key_completion(const char *line, void *context)
       verify->completion(FALSE, verify->context);
 
     printformat_module("fe-common/silc", NULL, NULL,
-                      MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, verify->entity);
+                      MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, 
+                      verify->entity_name ? verify->entity_name :
+                      verify->entity);
   }
 
   silc_free(verify->filename);
   silc_free(verify->entity);
+  silc_free(verify->entity_name);
   silc_free(verify->pk);
   silc_free(verify);
 }
 
+/* Internal routine to verify public key. If the `completion' is provided
+   it will be called to indicate whether public was verified or not. For
+   server/router public key this will check for filename that includes the
+   remote host's IP address and remote host's hostname. */
+
 static void 
 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
-                               SilcSocketType conn_type, unsigned char *pk, 
-                               uint32 pk_len, SilcSKEPKType pk_type,
+                               const char *name, SilcSocketType conn_type, 
+                               unsigned char *pk, SilcUInt32 pk_len, 
+                               SilcSKEPKType pk_type,
                                SilcVerifyPublicKey completion, void *context)
 {
   int i;
-  char file[256], filename[256], *fingerprint, *babbleprint, *format;
+  char file[256], filename[256], filename2[256], *ipf, *hostf = NULL;
+  char *fingerprint, *babbleprint, *format;
   struct passwd *pw;
   struct stat st;
   char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
@@ -922,14 +1353,32 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   }
 
   memset(filename, 0, sizeof(filename));
+  memset(filename2, 0, sizeof(filename2));
   memset(file, 0, sizeof(file));
 
   if (conn_type == SILC_SOCKET_TYPE_SERVER ||
       conn_type == SILC_SOCKET_TYPE_ROUTER) {
-    snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, 
-            conn->sock->ip, conn->sock->port);
-    snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", 
-            pw->pw_dir, entity, file);
+    if (!name) {
+      snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, 
+              conn->sock->ip, conn->sock->port);
+      snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", 
+              pw->pw_dir, entity, file);
+      
+      snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, 
+              conn->sock->hostname, conn->sock->port);
+      snprintf(filename2, sizeof(filename2) - 1, "%s/.silc/%skeys/%s", 
+              pw->pw_dir, entity, file);
+      
+      ipf = filename;
+      hostf = filename2;
+    } else {
+      snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, 
+              name, conn->sock->port);
+      snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", 
+              pw->pw_dir, entity, file);
+      
+      ipf = filename;
+    }
   } else {
     /* Replace all whitespaces with `_'. */
     fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
@@ -941,6 +1390,8 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
     snprintf(filename, sizeof(filename) - 1, "%s/.silc/%skeys/%s", 
             pw->pw_dir, entity, file);
     silc_free(fingerprint);
+
+    ipf = filename;
   }
 
   /* Take fingerprint of the public key */
@@ -950,8 +1401,11 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   verify = silc_calloc(1, sizeof(*verify));
   verify->client = client;
   verify->conn = conn;
-  verify->filename = strdup(filename);
+  verify->filename = strdup(ipf);
   verify->entity = strdup(entity);
+  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_len = pk_len;
@@ -960,11 +1414,12 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   verify->context = context;
 
   /* Check whether this key already exists */
-  if (stat(filename, &st) < 0) {
+  if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
     /* Key does not exist, ask user to verify the key and save it */
 
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
-                      SILCTXT_PUBKEY_RECEIVED, entity);
+                      SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? 
+                      verify->entity_name : entity);
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
                       SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
@@ -980,35 +1435,41 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
     /* The key already exists, verify it. */
     SilcPublicKey public_key;
     unsigned char *encpk;
-    uint32 encpk_len;
-
-    /* Load the key file */
-    if (!silc_pkcs_load_public_key(filename, &public_key, 
-                                  SILC_PKCS_FILE_PEM))
-      if (!silc_pkcs_load_public_key(filename, &public_key, 
-                                    SILC_PKCS_FILE_BIN)) {
-       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
-                          SILCTXT_PUBKEY_RECEIVED, entity);
-       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
-                          SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
-       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
-                          SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
-       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
-                          SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
-       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
-                                SILCTXT_PUBKEY_ACCEPT_ANYWAY);
-       keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
-                               format, 0, verify);
-       g_free(format);
-       silc_free(fingerprint);
-       return;
-      }
-  
+    SilcUInt32 encpk_len;
+
+    /* Load the key file, try for both IP filename and hostname filename */
+    if (!silc_pkcs_load_public_key(ipf, &public_key, 
+                                  SILC_PKCS_FILE_PEM) &&
+       !silc_pkcs_load_public_key(ipf, &public_key, 
+                                  SILC_PKCS_FILE_BIN) &&
+       (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key, 
+                                              SILC_PKCS_FILE_PEM) &&
+                   !silc_pkcs_load_public_key(hostf, &public_key, 
+                                              SILC_PKCS_FILE_BIN)))) {
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+                        SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? 
+                        verify->entity_name : entity);
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+                        SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+                        SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+                        SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
+      format = format_get_text("fe-common/silc", NULL, NULL, NULL,
+                              SILCTXT_PUBKEY_ACCEPT_ANYWAY);
+      keyboard_entry_redirect((SIGNAL_FUNC)verify_public_key_completion,
+                             format, 0, verify);
+      g_free(format);
+      silc_free(fingerprint);
+      return;
+    }
+
     /* Encode the key data */
     encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
     if (!encpk) {
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
-                        SILCTXT_PUBKEY_RECEIVED, entity);
+                        SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? 
+                        verify->entity_name : entity);
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
                         SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
@@ -1027,7 +1488,8 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
     /* Compare the keys */
     if (memcmp(encpk, pk, encpk_len)) {
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
-                        SILCTXT_PUBKEY_RECEIVED, entity);
+                        SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? 
+                        verify->entity_name : entity);
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
                         SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
@@ -1064,10 +1526,10 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
 void 
 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
                       SilcSocketType conn_type, unsigned char *pk, 
-                      uint32 pk_len, SilcSKEPKType pk_type,
+                      SilcUInt32 pk_len, SilcSKEPKType pk_type,
                       SilcVerifyPublicKey completion, void *context)
 {
-  silc_verify_public_key_internal(client, conn, conn_type, pk,
+  silc_verify_public_key_internal(client, conn, NULL, conn_type, pk,
                                  pk_len, pk_type,
                                  completion, context);
 }
@@ -1145,7 +1607,7 @@ static void silc_get_auth_method_callback(SilcClient client,
    is found and FALSE if not. `conn' may be NULL. */
 
 void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
-                         char *hostname, uint16 port,
+                         char *hostname, SilcUInt16 port,
                          SilcGetAuthMeth completion, void *context)
 {
   InternalGetAuthMethod internal;
@@ -1212,7 +1674,7 @@ void silc_failure(SilcClient client, SilcClientConnection conn,
   }
 
   if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
-    uint32 err = (uint32)failure;
+    SilcUInt32 err = (SilcUInt32)failure;
 
     if (err == SILC_AUTH_FAILED)
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
@@ -1229,7 +1691,7 @@ void silc_failure(SilcClient client, SilcClientConnection conn,
 
 int silc_key_agreement(SilcClient client, SilcClientConnection conn,
                       SilcClientEntry client_entry, const char *hostname,
-                      uint16 port, SilcKeyAgreementCallback *completion,
+                      SilcUInt16 port, SilcKeyAgreementCallback *completion,
                       void **context)
 {
   char portstr[12];
@@ -1257,8 +1719,8 @@ int silc_key_agreement(SilcClient client, SilcClientConnection conn,
 }
 
 void silc_ftp(SilcClient client, SilcClientConnection conn,
-             SilcClientEntry client_entry, uint32 session_id,
-             const char *hostname, uint16 port)
+             SilcClientEntry client_entry, SilcUInt32 session_id,
+             const char *hostname, SilcUInt16 port)
 {
   SILC_SERVER_REC *server;
   char portstr[12];