updates.
[silc.git] / apps / silcd / command.c
index d60bf2c65553fe572b17e0007257b260b9f075b1..25b642f4ec18016c9c4cfdbb0dfed33d87bf5105 100644 (file)
@@ -181,7 +181,8 @@ void silc_server_command_process(SilcServer server,
   ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
   
   /* Parse the command payload in the packet */
-  ctx->payload = silc_command_payload_parse(packet->buffer);
+  ctx->payload = silc_command_payload_parse(packet->buffer->data,
+                                           packet->buffer->len);
   if (!ctx->payload) {
     SILC_LOG_ERROR(("Bad command payload, packet dropped"));
     silc_buffer_free(packet->buffer);
@@ -675,6 +676,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   uint16 ident = silc_command_get_ident(cmd->payload);
   char nh[256], uh[256];
   unsigned char idle[4], mode[4];
+  unsigned char *fingerprint;
   SilcSocketConnection hsock;
 
   len = 0;
@@ -772,6 +774,11 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
     }
 
     channels = silc_server_get_client_channel_list(server, entry);
+
+    if (entry->data.fingerprint[0] != 0 && entry->data.fingerprint[1] != 0)
+      fingerprint = entry->data.fingerprint;
+    else
+      fingerprint = NULL;
       
     SILC_PUT32_MSB(entry->mode, mode);
 
@@ -779,29 +786,21 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
       SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
     }
 
-    if (channels)
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                                   status, ident, 7, 
-                                                   2, idp->data, idp->len,
-                                                   3, nh, strlen(nh),
-                                                   4, uh, strlen(uh),
-                                                   5, entry->userinfo, 
-                                                   strlen(entry->userinfo),
-                                                   6, channels->data,
-                                                   channels->len,
-                                                   7, mode, 4,
-                                                   8, idle, 4);
-    else
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
-                                                   status, ident, 6, 
-                                                   2, idp->data, idp->len,
-                                                   3, nh, strlen(nh),
-                                                   4, uh, strlen(uh),
-                                                   5, entry->userinfo, 
-                                                   strlen(entry->userinfo),
-                                                   7, mode, 4,
-                                                   8, idle, 4);
-    
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+                                          status, ident, 8, 
+                                          2, idp->data, idp->len,
+                                          3, nh, strlen(nh),
+                                          4, uh, strlen(uh),
+                                          5, entry->userinfo, 
+                                          strlen(entry->userinfo),
+                                          6, channels ? channels->data : NULL,
+                                          channels ? channels->len : 0,
+                                          7, mode, 4,
+                                          8, idle, 4,
+                                          9, fingerprint,
+                                          fingerprint ? 20 : 0);
+
     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                            0, packet->data, packet->len, FALSE);
     
@@ -837,7 +836,7 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
     uint16 old_ident;
 
     old_ident = silc_command_get_ident(cmd->payload);
-    silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+    silc_command_set_ident(cmd->payload, ++server->cmd_ident);
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
     /* Send WHOIS command to our router */
@@ -1021,7 +1020,7 @@ silc_server_command_whowas_check(SilcServerCommandContext cmd,
        continue;
       
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       /* Send WHOWAS command */
@@ -1119,23 +1118,15 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
       strcat(uh, "*private*");
     }
       
-    if (entry->userinfo)
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
-                                            status, ident, 4, 
-                                            2, idp->data, idp->len,
-                                            3, nh, strlen(nh),
-                                            4, uh, strlen(uh),
-                                            5, entry->userinfo, 
-                                            strlen(entry->userinfo));
-    else
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
-                                            status, ident, 3, 
-                                            2, idp->data, idp->len,
-                                            3, nh, strlen(nh),
-                                            4, uh, strlen(uh));
-
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_WHOWAS,
+                                          status, ident, 4, 
+                                          2, idp->data, idp->len,
+                                          3, nh, strlen(nh),
+                                          4, uh, strlen(uh),
+                                          5, entry->userinfo, 
+                                          entry->userinfo ? 
+                                          strlen(entry->userinfo) : 0);
     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                            0, packet->data, packet->len, FALSE);
     
@@ -1172,7 +1163,7 @@ silc_server_command_whowas_process(SilcServerCommandContext cmd)
     uint16 old_ident;
 
     old_ident = silc_command_get_ident(cmd->payload);
-    silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+    silc_command_set_ident(cmd->payload, ++server->cmd_ident);
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
     /* Send WHOWAS command to our router */
@@ -1341,7 +1332,7 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       entry = silc_idlist_find_server_by_name(server->local_list,
                                              tmp, TRUE, NULL);
       if (!entry && check_global)
-       entry = silc_idlist_find_server_by_name(server->local_list,
+       entry = silc_idlist_find_server_by_name(server->global_list,
                                                tmp, TRUE, NULL);
       if (entry) {
        *servers = silc_realloc(*servers, sizeof(**servers) * 
@@ -1363,7 +1354,7 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       entry = silc_idlist_find_channel_by_name(server->local_list,
                                               tmp, NULL);
       if (!entry && check_global)
-       entry = silc_idlist_find_channel_by_name(server->local_list,
+       entry = silc_idlist_find_channel_by_name(server->global_list,
                                                 tmp, NULL);
       if (entry) {
        *channels = silc_realloc(*channels, sizeof(**channels) * 
@@ -1396,7 +1387,7 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       if (!tmp)
        continue;
       
-      idp = silc_id_payload_parse_data(tmp, len);
+      idp = silc_id_payload_parse(tmp, len);
       if (!idp) {
        silc_free(*clients);
        silc_free(*servers);
@@ -1765,19 +1756,13 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       
       /* Send IDENTIFY reply */
       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
-      if (entry->server_name) {
-       packet = 
-         silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                              status, ident, 2,
-                                              2, idp->data, idp->len, 
-                                              3, entry->server_name, 
-                                              strlen(entry->server_name));
-      } else {
-       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                                     status, ident, 1,
-                                                     2, idp->data, idp->len);
-      }
-      
+      packet = 
+       silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+                                            status, ident, 2,
+                                            2, idp->data, idp->len, 
+                                            3, entry->server_name, 
+                                            entry->server_name ? 
+                                            strlen(entry->server_name) : 0);
       silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                              0, packet->data, packet->len, FALSE);
       
@@ -1811,19 +1796,13 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
       
       /* Send IDENTIFY reply */
       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
-      if (entry->channel_name) {
-       packet = 
-         silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                              status, ident, 2,
-                                              2, idp->data, idp->len, 
-                                              3, entry->channel_name, 
-                                              strlen(entry->channel_name));
-      } else {
-       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
-                                                     status, ident, 1,
-                                                     2, idp->data, idp->len);
-      }
-      
+      packet = 
+       silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+                                            status, ident, 2,
+                                            2, idp->data, idp->len, 
+                                            3, entry->channel_name, 
+                                            entry->channel_name ? 
+                                            strlen(entry->channel_name): 0);
       silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                              0, packet->data, packet->len, FALSE);
       
@@ -1857,7 +1836,7 @@ silc_server_command_identify_process(SilcServerCommandContext cmd)
     uint16 old_ident;
 
     old_ident = silc_command_get_ident(cmd->payload);
-    silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+    silc_command_set_ident(cmd->payload, ++server->cmd_ident);
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
     /* Send IDENTIFY command to our router */
@@ -1937,13 +1916,11 @@ static int silc_server_command_bad_chars(char *nick)
   for (i = 0; i < strlen(nick); i++) {
     if (!isascii(nick[i]))
       return TRUE;
+    if (nick[i] <= 32) return TRUE;
     if (nick[i] == ' ') return TRUE;
-    if (nick[i] == '\\') return TRUE;
-    if (nick[i] == '\"') return TRUE;
     if (nick[i] == '*') return TRUE;
     if (nick[i] == '?') return TRUE;
     if (nick[i] == ',') return TRUE;
-    if (nick[i] == '@') return TRUE;
   }
 
   return FALSE;
@@ -1958,7 +1935,7 @@ SILC_SERVER_CMD_FUNC(nick)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   SilcServer server = cmd->server;
-  SilcBuffer packet, nidp, oidp;
+  SilcBuffer packet, nidp, oidp = NULL;
   SilcClientID *new_id;
   char *nick;
   uint16 ident = silc_command_get_ident(cmd->payload);
@@ -1980,6 +1957,12 @@ SILC_SERVER_CMD_FUNC(nick)
   if (strlen(nick) > 128)
     nick[128] = '\0';
 
+  /* Check for same nickname */
+  if (!strcmp(client->nickname, nick)) {
+    nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+    goto send_reply;
+  }
+
   /* Create new Client ID */
   while (!silc_id_create_client_id(cmd->server, cmd->server->id, 
                                   cmd->server->rng, 
@@ -2024,6 +2007,7 @@ SILC_SERVER_CMD_FUNC(nick)
                                      oidp->data, oidp->len, 
                                      nidp->data, nidp->len);
 
+ send_reply:
   /* Send the new Client ID as reply command back to client */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
                                                SILC_STATUS_OK, ident, 1, 
@@ -2033,7 +2017,8 @@ SILC_SERVER_CMD_FUNC(nick)
 
   silc_buffer_free(packet);
   silc_buffer_free(nidp);
-  silc_buffer_free(oidp);
+  if (oidp)
+    silc_buffer_free(oidp);
   
  out:
   silc_server_command_free(cmd);
@@ -2071,16 +2056,12 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
   /* Local list */
   for (i = 0; i < lch_count; i++) {
     entry = lch[i];
-
     if (!entry)
       continue;
 
     if (i >= 1)
       status = SILC_STATUS_LIST_ITEM;
-
-    if (i == lch_count - 1 && gch_count)
-      break;
-    if (lch_count > 1 && i == lch_count - 1)
+    if (i >= 1 && i == lch_count - 1 && !gch_count)
       status = SILC_STATUS_LIST_END;
 
     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
@@ -2095,23 +2076,14 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     }
 
     /* Send the reply */
-    if (topic)
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
-                                            status, ident, 4, 
-                                            2, idp->data, idp->len,
-                                            3, entry->channel_name, 
-                                            strlen(entry->channel_name),
-                                            4, topic, strlen(topic),
-                                            5, usercount, 4);
-    else
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
-                                            status, ident, 3, 
-                                            2, idp->data, idp->len,
-                                            3, entry->channel_name, 
-                                            strlen(entry->channel_name),
-                                            5, usercount, 4);
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
+                                          status, ident, 4,
+                                          2, idp->data, idp->len,
+                                          3, entry->channel_name, 
+                                          strlen(entry->channel_name),
+                                          4, topic, topic ? strlen(topic) : 0,
+                                          5, usercount, 4);
     silc_server_packet_send(cmd->server, cmd->sock, 
                            SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
                            packet->len, FALSE);
@@ -2119,19 +2091,15 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     silc_buffer_free(idp);
   }
 
-  status = i ? SILC_STATUS_LIST_ITEM : SILC_STATUS_OK;
-
   /* Global list */
   for (i = 0; i < gch_count; i++) {
     entry = gch[i];
-
     if (!entry)
       continue;
 
     if (i >= 1)
       status = SILC_STATUS_LIST_ITEM;
-
-    if (gch_count > 1 && i == lch_count - 1)
+    if (i >= 1 && i == gch_count - 1)
       status = SILC_STATUS_LIST_END;
 
     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
@@ -2146,23 +2114,14 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     }
 
     /* Send the reply */
-    if (topic)
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
-                                            status, ident, 4, 
-                                            2, idp->data, idp->len,
-                                            3, entry->channel_name, 
-                                            strlen(entry->channel_name),
-                                            4, topic, strlen(topic),
-                                            5, usercount, 4);
-    else
-      packet = 
-       silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
-                                            status, ident, 3, 
-                                            2, idp->data, idp->len,
-                                            3, entry->channel_name, 
-                                            strlen(entry->channel_name),
-                                            5, usercount, 4);
+    packet = 
+      silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
+                                          status, ident, 4,
+                                          2, idp->data, idp->len,
+                                          3, entry->channel_name, 
+                                          strlen(entry->channel_name),
+                                          4, topic, topic ? strlen(topic) : 0,
+                                          5, usercount, 4);
     silc_server_packet_send(cmd->server, cmd->sock, 
                            SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
                            packet->len, FALSE);
@@ -2184,7 +2143,33 @@ SILC_SERVER_CMD_FUNC(list)
   SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
   uint32 lch_count = 0, gch_count = 0;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 2);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LIST, cmd, 0, 1);
+
+  /* If we are normal server, send the command to router, since we
+     want to know all channels in the network. */
+  if (!cmd->pending && server->server_type == SILC_SERVER && 
+      !server->standalone) {
+    SilcBuffer tmpbuf;
+    uint16 old_ident;
+    
+    old_ident = silc_command_get_ident(cmd->payload);
+    silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+    tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+    silc_server_packet_send(server, server->router->connection,
+                           SILC_PACKET_COMMAND, cmd->packet->flags,
+                           tmpbuf->data, tmpbuf->len, TRUE);
+
+    /* Reprocess this packet after received reply from router */
+    silc_server_command_pending(server, SILC_COMMAND_LIST, 
+                               silc_command_get_ident(cmd->payload),
+                               silc_server_command_destructor,
+                               silc_server_command_list, 
+                               silc_server_command_dup(cmd));
+    cmd->pending = TRUE;
+    silc_command_set_ident(cmd->payload, old_ident);
+    silc_buffer_free(tmpbuf);
+    return;
+  }
 
   /* Get Channel ID */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -2201,10 +2186,9 @@ SILC_SERVER_CMD_FUNC(list)
   lchannels = silc_idlist_get_channels(server->local_list, channel_id,
                                       &lch_count);
   
-  /* Get the channels from global list if we are router */
-  if (server->server_type != SILC_SERVER) 
-    gchannels = silc_idlist_get_channels(server->global_list, channel_id,
-                                        &gch_count);
+  /* Get the channels from global list */
+  gchannels = silc_idlist_get_channels(server->global_list, channel_id,
+                                      &gch_count);
 
   /* Send the reply */
   silc_server_command_list_send_reply(cmd, lchannels, lch_count, 
@@ -2315,16 +2299,12 @@ SILC_SERVER_CMD_FUNC(topic)
 
   /* Send the topic to client as reply packet */
   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
-  if (channel->topic)
-    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
-                                                 SILC_STATUS_OK, ident, 2, 
-                                                 2, idp->data, idp->len,
-                                                 3, channel->topic, 
-                                                 strlen(channel->topic));
-  else
-    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
-                                                 SILC_STATUS_OK, ident, 1, 
-                                                 2, idp->data, idp->len);
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
+                                               SILC_STATUS_OK, ident, 2, 
+                                               2, idp->data, idp->len,
+                                               3, channel->topic, 
+                                               channel->topic ? 
+                                               strlen(channel->topic) : 0);
   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                          0, packet->data, packet->len, FALSE);
 
@@ -2822,7 +2802,7 @@ SILC_SERVER_CMD_FUNC(info)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, entry->connection,
@@ -2847,7 +2827,7 @@ SILC_SERVER_CMD_FUNC(info)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, server->router->connection,
@@ -2881,20 +2861,14 @@ SILC_SERVER_CMD_FUNC(info)
   server_name = entry->server_name;
 
   /* Send the reply */
-  if (server_info)
-    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
-                                                 SILC_STATUS_OK, ident, 3,
-                                                 2, idp->data, idp->len,
-                                                 3, server_name, 
-                                                 strlen(server_name),
-                                                 4, server_info, 
-                                                 strlen(server_info));
-  else
-    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
-                                                 SILC_STATUS_OK, ident, 2,
-                                                 2, idp->data, idp->len,
-                                                 3, server_name, 
-                                                 strlen(server_name));
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+                                               SILC_STATUS_OK, ident, 3,
+                                               2, idp->data, idp->len,
+                                               3, server_name, 
+                                               strlen(server_name),
+                                               4, server_info, 
+                                               server_info ? 
+                                               strlen(server_info) : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
@@ -2952,7 +2926,8 @@ static void silc_server_command_join_channel(SilcServer server,
                                             SilcServerCommandContext cmd,
                                             SilcChannelEntry channel,
                                             SilcClientID *client_id,
-                                            int created,
+                                            bool created,
+                                            bool create_key,
                                             uint32 umode)
 {
   SilcSocketConnection sock = cmd->sock;
@@ -3033,7 +3008,8 @@ static void silc_server_command_join_channel(SilcServer server,
      username and/or hostname is in the ban list the access to the
      channel is denied. */
   if (channel->ban_list) {
-    if (silc_string_match(channel->ban_list, check) ||
+    if (!channel->ban_list ||
+        silc_string_match(channel->ban_list, check) ||
        silc_string_match(channel->ban_list, check2)) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                              SILC_STATUS_ERR_BANNED_FROM_CHANNEL);
@@ -3050,8 +3026,9 @@ static void silc_server_command_join_channel(SilcServer server,
   
   /* Check the channel passphrase if set. */
   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
-    if (!passphrase || memcmp(channel->passphrase, passphrase,
-                             strlen(channel->passphrase))) {
+    if (!passphrase || !channel->passphrase ||
+        memcmp(channel->passphrase, passphrase,
+               strlen(channel->passphrase))) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                            SILC_STATUS_ERR_BAD_PASSWORD);
       goto out;
@@ -3080,17 +3057,17 @@ static void silc_server_command_join_channel(SilcServer server,
   }
 
   /* Generate new channel key as protocol dictates */
-  if ((!created && silc_hash_table_count(channel->user_list) > 0) || 
-      !channel->channel_key)
+  if (create_key) {
     if (!silc_server_create_channel_key(server, channel, 0))
       goto out;
 
-  /* Send the channel key. This is broadcasted to the channel but is not
-     sent to the client who is joining to the channel. */
-  if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
-    silc_server_send_channel_key(server, NULL, channel, 
-                                server->server_type == SILC_ROUTER ? 
-                                FALSE : !server->standalone);
+    /* Send the channel key. This is broadcasted to the channel but is not
+       sent to the client who is joining to the channel. */
+    if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+      silc_server_send_channel_key(server, NULL, channel, 
+                                  server->server_type == SILC_ROUTER ? 
+                                  FALSE : !server->standalone);
+  }
 
   /* Join the client to the channel by adding it to channel's user list.
      Add also the channel to client entry's channels list for fast cross-
@@ -3145,8 +3122,9 @@ static void silc_server_command_join_channel(SilcServer server,
                                         10, channel->topic,
                                         channel->topic ?
                                         strlen(channel->topic) : 0,
-                                        11, channel->hmac->hmac->name,
-                                        strlen(channel->hmac->hmac->name),
+                                        11, silc_hmac_get_name(channel->hmac),
+                                        strlen(silc_hmac_get_name(channel->
+                                                                  hmac)),
                                         12, tmp3, 4,
                                         13, user_list->data, user_list->len,
                                         14, mode_list->data, 
@@ -3202,7 +3180,7 @@ SILC_SERVER_CMD_FUNC(join)
   char *tmp, *channel_name = NULL, *cipher, *hmac;
   SilcChannelEntry channel;
   uint32 umode = 0;
-  int created = FALSE;
+  bool created = FALSE, create_key = TRUE;
   SilcClientID *client_id;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 1, 4);
@@ -3259,7 +3237,7 @@ SILC_SERVER_CMD_FUNC(join)
       }
     }
 
-    if (!channel || !channel->id) {
+    if (!channel || channel->disabled) {
       /* Channel not found */
 
       /* If we are standalone server we don't have a router, we just create 
@@ -3269,13 +3247,14 @@ SILC_SERVER_CMD_FUNC(join)
                                                 hmac, channel_name, TRUE);
        if (!channel) {
          silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                    SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
          goto out;
        }
-
+       
        umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
        created = TRUE;
-
+       create_key = FALSE;
+       
       } else {
 
        /* The channel does not exist on our server. If we are normal server 
@@ -3293,7 +3272,7 @@ SILC_SERVER_CMD_FUNC(join)
            goto out;
          
          old_ident = silc_command_get_ident(cmd->payload);
-         silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+         silc_command_set_ident(cmd->payload, ++server->cmd_ident);
          tmpbuf = silc_command_payload_encode_payload(cmd->payload);
          
          /* Send JOIN command to our router */
@@ -3328,6 +3307,7 @@ SILC_SERVER_CMD_FUNC(join)
 
          umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
          created = TRUE;
+         create_key = FALSE;
        }
       }
     }
@@ -3358,21 +3338,30 @@ SILC_SERVER_CMD_FUNC(join)
 
        umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
        created = TRUE;
+       create_key = FALSE;
       }
     }
   }
 
-  /* If the channel does not have global users and is also empty it means the
-     channel was created globally (by our router) and the client will be the
-     channel founder and operator. */
-  if (!channel->global_users && !silc_hash_table_count(channel->user_list)) {
-    umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
-    created = TRUE;            /* Created globally by our router */
+  /* Check whether the channel was created by our router */
+  if (cmd->pending && context2) {
+    SilcServerCommandReplyContext reply = 
+      (SilcServerCommandReplyContext)context2;
+    if (silc_command_get(reply->payload) == SILC_COMMAND_JOIN) {
+      tmp = silc_argument_get_arg_type(reply->args, 6, NULL);
+      SILC_GET32_MSB(created, tmp);
+      create_key = FALSE;      /* Router returned the key already */
+    }
   }
 
+  /* If the channel does not have global users and is also empty the client
+     will be the channel founder and operator. */
+  if (!channel->global_users && !silc_hash_table_count(channel->user_list))
+    umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+
   /* Join to the channel */
   silc_server_command_join_channel(server, cmd, channel, client_id,
-                                  created, umode);
+                                  created, create_key, umode);
 
   silc_free(client_id);
 
@@ -3410,7 +3399,7 @@ SILC_SERVER_CMD_FUNC(motd)
     if (server->config && server->config->motd && 
        server->config->motd->motd_file) {
       /* Send motd */
-      motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+      motd = silc_file_readfile(server->config->motd->motd_file, &motd_len);
       if (!motd)
        goto out;
       
@@ -3419,7 +3408,6 @@ SILC_SERVER_CMD_FUNC(motd)
                                                    SILC_STATUS_OK, ident, 2,
                                                    2, idp, idp->len,
                                                    3, motd, motd_len);
-      goto out;
     } else {
       /* No motd */
       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
@@ -3449,7 +3437,7 @@ SILC_SERVER_CMD_FUNC(motd)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, entry->connection,
@@ -3474,7 +3462,7 @@ SILC_SERVER_CMD_FUNC(motd)
       uint16 old_ident;
 
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
 
       silc_server_packet_send(server, server->router->connection,
@@ -3500,18 +3488,12 @@ SILC_SERVER_CMD_FUNC(motd)
     }
 
     idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
-
-    if (entry->motd)
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                   SILC_STATUS_OK, ident, 2,
-                                                   2, idp, idp->len,
-                                                   3, entry->motd,
-                                                   strlen(entry->motd));
-    else
-      packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                   SILC_STATUS_OK, ident, 1,
-                                                   2, idp, idp->len);
-
+    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+                                                 SILC_STATUS_OK, ident, 2,
+                                                 2, idp, idp->len,
+                                                 3, entry->motd,
+                                                 entry->motd ? 
+                                                 strlen(entry->motd) : 0);
     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                            packet->data, packet->len, FALSE);
     silc_buffer_free(packet);
@@ -3628,8 +3610,9 @@ int silc_server_check_cmode_rights(SilcChannelEntry channel,
      modes are available automatically for channel operator. */
 
   if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
-    if (is_op && !is_fo)
-      return FALSE;
+    if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
+      if (is_op && !is_fo)
+       return FALSE;
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
       if (is_op && !is_fo)
@@ -3638,8 +3621,9 @@ int silc_server_check_cmode_rights(SilcChannelEntry channel,
   }
   
   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
-    if (is_op && !is_fo)
-      return FALSE;
+    if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE))
+      if (is_op && !is_fo)
+       return FALSE;
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
       if (is_op && !is_fo)
@@ -3648,8 +3632,9 @@ int silc_server_check_cmode_rights(SilcChannelEntry channel,
   }
 
   if (mode & SILC_CHANNEL_MODE_CIPHER) {
-    if (is_op && !is_fo)
-      return FALSE;
+    if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER))
+      if (is_op && !is_fo)
+       return FALSE;
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
       if (is_op && !is_fo)
@@ -3658,8 +3643,9 @@ int silc_server_check_cmode_rights(SilcChannelEntry channel,
   }
   
   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
-    if (is_op && !is_fo)
-      return FALSE;
+    if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH))
+      if (is_op && !is_fo)
+       return FALSE;
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
       if (is_op && !is_fo)
@@ -3768,7 +3754,7 @@ SILC_SERVER_CMD_FUNC(cmode)
                                   FALSE : !server->standalone);
 
       cipher = channel->channel_key->cipher->name;
-      hmac = channel->hmac->hmac->name;
+      hmac = (char *)silc_hmac_get_name(channel->hmac);
     }
   }
   
@@ -3822,6 +3808,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
     if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
       /* Cipher to use protect the traffic */
+      SilcCipher newkey, oldkey;
 
       /* Get cipher */
       cipher = silc_argument_get_arg_type(cmd->args, 5, NULL);
@@ -3832,17 +3819,25 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
 
       /* Delete old cipher and allocate the new one */
-      silc_cipher_free(channel->channel_key);
-      if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
+      if (!silc_cipher_alloc(cipher, &newkey)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
        goto out;
       }
 
+      oldkey = channel->channel_key;
+      channel->channel_key = newkey;
+
       /* Re-generate channel key */
-      if (!silc_server_create_channel_key(server, channel, 0))
+      if (!silc_server_create_channel_key(server, channel, 0)) {
+       /* We don't have new key, revert to old one */
+       channel->channel_key = oldkey;
        goto out;
-    
+      }
+
+      /* Remove old channel key for good */
+      silc_cipher_free(oldkey);
+
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
       silc_server_send_channel_key(server, NULL, channel, 
@@ -3853,21 +3848,29 @@ SILC_SERVER_CMD_FUNC(cmode)
     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
       /* Cipher mode is unset. Remove the cipher and revert back to 
         default cipher */
+      SilcCipher newkey, oldkey;
       cipher = channel->cipher;
 
       /* Delete old cipher and allocate default one */
-      silc_cipher_free(channel->channel_key);
-      if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER, 
-                            &channel->channel_key)) {
+      if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER, &newkey)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                   SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
        goto out;
       }
 
+      oldkey = channel->channel_key;
+      channel->channel_key = newkey;
+
       /* Re-generate channel key */
-      if (!silc_server_create_channel_key(server, channel, 0))
+      if (!silc_server_create_channel_key(server, channel, 0)) {
+       /* We don't have new key, revert to old one */
+       channel->channel_key = oldkey;
        goto out;
+      }
       
+      /* Remove old channel key for good */
+      silc_cipher_free(oldkey);
+
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
       silc_server_send_channel_key(server, NULL, channel, 
@@ -3880,6 +3883,7 @@ SILC_SERVER_CMD_FUNC(cmode)
     if (!(channel->mode & SILC_CHANNEL_MODE_HMAC)) {
       /* HMAC to use protect the traffic */
       unsigned char hash[32];
+      SilcHmac newhmac;
 
       /* Get hmac */
       hmac = silc_argument_get_arg_type(cmd->args, 6, NULL);
@@ -3890,43 +3894,49 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
 
       /* Delete old hmac and allocate the new one */
-      silc_hmac_free(channel->hmac);
-      if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
+      if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
        goto out;
       }
 
+      silc_hmac_free(channel->hmac);
+      channel->hmac = newhmac;
+
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8
-                    hash);
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key
+                    channel->key_len / 8, hash);
       silc_hmac_set_key(channel->hmac, hash, 
-                       silc_hash_len(channel->hmac->hash));
+                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_HMAC) {
       /* Hmac mode is unset. Remove the hmac and revert back to 
         default hmac */
+      SilcHmac newhmac;
       unsigned char hash[32];
       hmac = channel->hmac_name;
 
       /* Delete old hmac and allocate default one */
       silc_hmac_free(channel->hmac);
-      if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL, 
-                          &channel->hmac)) {
+      if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL, &newhmac)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
        goto out;
       }
 
+      silc_hmac_free(channel->hmac);
+      channel->hmac = newhmac;
+
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8, 
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
+                    channel->key_len / 8, 
                     hash);
       silc_hmac_set_key(channel->hmac, hash, 
-                       silc_hash_len(channel->hmac->hash));
+                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
   }
@@ -4164,7 +4174,9 @@ SILC_SERVER_CMD_FUNC(cumode)
       }
 
       if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
-         !channel->founder_key) {
+         !channel->founder_key || !idata->public_key ||
+         !silc_pkcs_public_key_compare(channel->founder_key, 
+                                       idata->public_key)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
                                              SILC_STATUS_ERR_NOT_YOU);
        goto out;
@@ -4176,7 +4188,7 @@ SILC_SERVER_CMD_FUNC(cumode)
                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
        goto out;
       }
-      
+
       auth = (channel->founder_method == SILC_AUTH_PASSWORD ?
              (void *)channel->founder_passwd : (void *)channel->founder_key);
       auth_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
@@ -4287,8 +4299,8 @@ SILC_SERVER_CMD_FUNC(kick)
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcBuffer idp;
-  uint32 tmp_len;
-  unsigned char *tmp, *comment;
+  uint32 tmp_len, target_idp_len;
+  unsigned char *tmp, *comment, *target_idp;
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_LEAVE, cmd, 1, 3);
 
@@ -4335,13 +4347,13 @@ SILC_SERVER_CMD_FUNC(kick)
   }
   
   /* Get target Client ID */
-  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
-  if (!tmp) {
+  target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
+  if (!target_idp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
                                          SILC_STATUS_ERR_NO_CLIENT_ID);
     goto out;
   }
-  client_id = silc_id_payload_parse_id(tmp, tmp_len);
+  client_id = silc_id_payload_parse_id(target_idp, target_idp_len);
   if (!client_id) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
                                          SILC_STATUS_ERR_NO_CLIENT_ID);
@@ -4383,12 +4395,12 @@ SILC_SERVER_CMD_FUNC(kick)
                                        SILC_STATUS_OK);
 
   /* Send KICKED notify to local clients on the channel */
-  idp = silc_id_payload_encode(target_client->id, SILC_ID_CLIENT);
+  idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                    SILC_NOTIFY_TYPE_KICKED, 
-                                    comment ? 2 : 1,
-                                    idp->data, idp->len,
-                                    comment, comment ? strlen(comment) : 0);
+                                    SILC_NOTIFY_TYPE_KICKED, 3,
+                                    target_idp, target_idp_len,
+                                    comment, comment ? strlen(comment) : 0,
+                                    idp->data, idp->len);
   silc_buffer_free(idp);
 
   /* Remove the client from the channel. If the channel does not exist
@@ -4735,19 +4747,13 @@ SILC_SERVER_CMD_FUNC(ban)
                                TRUE : FALSE, channel, add, del);
 
   /* Send the reply back to the client */
-  if (channel->ban_list)
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
-                                          SILC_STATUS_OK, ident, 2,
-                                          2, id, id_len,
-                                          3, channel->ban_list, 
-                                          strlen(channel->ban_list) - 1);
-  else
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
-                                          SILC_STATUS_OK, ident, 1,
-                                          2, id, id_len);
-
+  packet = 
+    silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
+                                        SILC_STATUS_OK, ident, 2,
+                                        2, id, id_len,
+                                        3, channel->ban_list, 
+                                        channel->ban_list ? 
+                                        strlen(channel->ban_list) - 1 : 0);
   silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
                          packet->data, packet->len, FALSE);
     
@@ -4799,6 +4805,9 @@ SILC_SERVER_CMD_FUNC(close)
 
   server_entry = silc_idlist_find_server_by_conn(server->local_list,
                                                 name, port, FALSE, NULL);
+  if (!server_entry)
+    server_entry = silc_idlist_find_server_by_conn(server->global_list,
+                                                  name, port, FALSE, NULL);
   if (!server_entry) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
                                          SILC_STATUS_ERR_NO_SERVER_ID);
@@ -4991,12 +5000,12 @@ SILC_SERVER_CMD_FUNC(users)
     channel = silc_idlist_find_channel_by_name(server->local_list, 
                                               channel_name, NULL);
 
-  if (!channel) {
+  if (!channel || channel->disabled) {
     if (server->server_type != SILC_ROUTER && !server->standalone &&
        !cmd->pending) {
       SilcBuffer tmpbuf;
       
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
       
       /* Send USERS command */
@@ -5107,7 +5116,7 @@ SILC_SERVER_CMD_FUNC(getkey)
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  idp = silc_id_payload_parse_data(tmp, tmp_len);
+  idp = silc_id_payload_parse(tmp, tmp_len);
   if (!idp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -5139,7 +5148,7 @@ SILC_SERVER_CMD_FUNC(getkey)
        goto out;
       
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
       
       silc_server_packet_send(server, dest_sock,
@@ -5205,7 +5214,7 @@ SILC_SERVER_CMD_FUNC(getkey)
       uint16 old_ident;
       
       old_ident = silc_command_get_ident(cmd->payload);
-      silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+      silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
       
       silc_server_packet_send(server, server->router->connection,