updates.
[silc.git] / apps / silcd / command.c
index 64fa02a22f1021eb648a5cd95f2648bb68ed844f..e9ee59679446ce6942d3a17a1944803a7c91246d 100644 (file)
@@ -35,7 +35,7 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
                                     SilcCommand command,
                                     SilcCommandStatus status,
                                     uint32 arg_type,
-                                    unsigned char *arg,
+                                    const unsigned char *arg,
                                     uint32 arg_len);
 static bool
 silc_server_command_pending_error_check(SilcServerCommandContext cmd,
@@ -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);
@@ -401,7 +402,7 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
                                     SilcCommand command,
                                     SilcCommandStatus status,
                                     uint32 arg_type,
-                                    unsigned char *arg,
+                                    const unsigned char *arg,
                                     uint32 arg_len)
 {
   SilcBuffer buffer;
@@ -438,8 +439,16 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd,
       status != SILC_STATUS_LIST_START &&
       status != SILC_STATUS_LIST_ITEM &&
       status != SILC_STATUS_LIST_END) {
-    /* Send the error message */
-    silc_server_command_send_status_reply(cmd, command, status);
+    SilcBuffer buffer;
+
+    /* Send the same command reply payload */
+    silc_command_set_ident(cmdr->payload, 
+                          silc_command_get_ident(cmd->payload));
+    buffer = silc_command_payload_encode_payload(cmdr->payload);
+    silc_server_packet_send(cmd->server, cmd->sock,
+                           SILC_PACKET_COMMAND_REPLY, 0, 
+                           buffer->data, buffer->len, FALSE);
+    silc_buffer_free(buffer);
     return TRUE;
   }
 
@@ -546,12 +555,23 @@ silc_server_command_whois_check(SilcServerCommandContext cmd,
 
   for (i = 0; i < clients_count; i++) {
     entry = clients[i];
-
-    if (!entry || (entry->nickname && entry->username && entry->userinfo) ||
-       !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
-       !entry->router)
+    if (!entry)
       continue;
 
+    if ((entry->nickname && entry->username && entry->userinfo) ||
+       !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+      if (!entry->router)
+       continue;
+
+      /* If we are normal server, and we've not resolved this client from
+        router and it is global client, we'll check whether it is on some
+        channel.  If not then we cannot be sure about its validity, and
+        we'll resolve it from router. */
+      if (cmd->server->server_type != SILC_SERVER || cmd->pending ||
+         entry->connection || silc_hash_table_count(entry->channels))
+       continue;
+    }
+
     /* We need to resolve this entry since it is not complete */
 
     if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
@@ -664,11 +684,13 @@ static void
 silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
                                     SilcClientEntry *clients,
                                     uint32 clients_count,
-                                    int count)
+                                    int count,
+                                    const char *nickname,
+                                    SilcClientID **client_ids)
 {
   SilcServer server = cmd->server;
   char *tmp;
-  int i, k, len;
+  int i, k, len, valid_count;
   SilcBuffer packet, idp, channels;
   SilcClientEntry entry;
   SilcCommandStatus status;
@@ -678,71 +700,60 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   unsigned char *fingerprint;
   SilcSocketConnection hsock;
 
-  len = 0;
-  for (i = 0; i < clients_count; i++)
+  /* Process only valid clients and ignore those that are not registered. */
+  valid_count = 0;
+  for (i = 0; i < clients_count; i++) {
     if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
-      len++;
+      valid_count++;
+    else
+      clients[i] = NULL;
+  }
 
-  if (len == 0 && clients_count) {
-    entry = clients[0];
-    if (entry->nickname) {
+  if (!valid_count) {
+    /* No valid clients found, send error reply */
+    if (nickname) {
       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
                                           SILC_STATUS_ERR_NO_SUCH_NICK,
-                                          3, entry->nickname, 
-                                          strlen(entry->nickname));
-    } else {
-      SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+                                          3, nickname, strlen(nickname));
+    } else if (client_ids && client_ids[0]) {
+      SilcBuffer idp = silc_id_payload_encode(client_ids[0], SILC_ID_CLIENT);
       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
                                           2, idp->data, idp->len);
       silc_buffer_free(idp);
     }
-
     return;
   }
 
-  status = SILC_STATUS_OK;
-  if (len > 1)
+  /* Start processing found clients. */
+  if (valid_count > 1)
     status = SILC_STATUS_LIST_START;
+  else
+    status = SILC_STATUS_OK;
 
   for (i = 0, k = 0; i < clients_count; i++) {
     entry = clients[i];
+    if (!entry)
+      continue;
 
-    if (!(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-      if (clients_count == 1) {
-       if (entry->nickname) {
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
-                                              SILC_STATUS_ERR_NO_SUCH_NICK,
-                                              3, entry->nickname, 
-                                              strlen(entry->nickname));
-       } else {
-         SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
-                                    SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                              2, idp->data, idp->len);
-         silc_buffer_free(idp);
-       }
-      }
+#if 1
+    /* XXX REMOVE */
+    /* Sanity check, however these should never fail. However, as
+       this sanity check has been added here they have failed. */
+    if (!entry->nickname || !entry->username || !entry->userinfo) {
+      SILC_LOG_ERROR(("********* if (!entry->nickname || !entry->username "
+                     "|| !entry->userinfo) triggered: should have not!"));
       continue;
     }
+#endif
 
     if (k >= 1)
       status = SILC_STATUS_LIST_ITEM;
-
-    if (clients_count > 1 && k == clients_count - 1)
+    if (valid_count > 1 && k == valid_count - 1)
       status = SILC_STATUS_LIST_END;
-
     if (count && k - 1 == count)
       status = SILC_STATUS_LIST_END;
 
-    if (count && k - 1 > count)
-      break;
-
-    /* Sanity check, however these should never fail. However, as
-       this sanity check has been added here they have failed. */
-    if (!entry->nickname || !entry->username || !entry->userinfo)
-      continue;
-      
     /* Send WHOIS reply */
     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
     tmp = silc_argument_get_first_arg(cmd->args, NULL);
@@ -812,6 +823,34 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd,
   }
 }
 
+static void 
+silc_server_command_whois_send_router(SilcServerCommandContext cmd)
+{
+  SilcServer server = cmd->server;
+  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);
+
+  /* Send WHOIS command to our router */
+  silc_server_packet_send(server, (SilcSocketConnection)
+                         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_WHOIS, 
+                             silc_command_get_ident(cmd->payload),
+                             silc_server_command_destructor,
+                             silc_server_command_whois,
+                             silc_server_command_dup(cmd));
+  cmd->pending = TRUE;
+  silc_command_set_ident(cmd->payload, old_ident);
+  silc_buffer_free(tmpbuf);
+}
+
 static int
 silc_server_command_whois_process(SilcServerCommandContext cmd)
 {
@@ -824,55 +863,29 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
   int i, ret = 0;
   bool check_global = FALSE;
 
-  /* Protocol dictates that we must always send the received WHOIS request
-     to our router if we are normal server, so let's do it now unless we
-     are standalone. We will not send any replies to the client until we
-     have received reply from the router. */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
-      server->server_type == SILC_SERVER && !cmd->pending && 
-      !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);
-
-    /* Send WHOIS command to our router */
-    silc_server_packet_send(server, (SilcSocketConnection)
-                           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_WHOIS, 
-                               silc_command_get_ident(cmd->payload),
-                               silc_server_command_destructor,
-                               silc_server_command_whois,
-                               silc_server_command_dup(cmd));
-    cmd->pending = TRUE;
-
-    silc_command_set_ident(cmd->payload, old_ident);
+  /* Parse the whois request */
+  if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
+                                      &nick, &server_name, &count,
+                                      SILC_COMMAND_WHOIS))
+    return 0;
 
-    silc_buffer_free(tmpbuf);
+  /* Send the WHOIS request to the router only if it included nickname.
+     Since nicknames can be expanded into many clients we need to send it
+     to router.  If the WHOIS included only client ID's we will check them
+     first locally since we just might have them. */
+  if (nick && !client_id_count && cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+      server->server_type == SILC_SERVER && !cmd->pending &&
+      !server->standalone) {
+    silc_server_command_whois_send_router(cmd);
     ret = -1;
     goto out;
   }
 
-  /* We are ready to process the command request. Let's search for the
-     requested client and send reply to the requesting client. */
-
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
     check_global = TRUE;
   else if (server->server_type != SILC_SERVER)
     check_global = TRUE;
 
-  /* Parse the whois request */
-  if (!silc_server_command_whois_parse(cmd, &client_id, &client_id_count, 
-                                      &nick, &server_name, &count,
-                                      SILC_COMMAND_WHOIS))
-    return 0;
-
   /* Get all clients matching that ID or nickname from local list */
   if (client_id_count) {
     /* Check all Client ID's received in the command packet */
@@ -886,9 +899,20 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
        clients = silc_realloc(clients, sizeof(*clients) * 
                               (clients_count + 1));
        clients[clients_count++] = entry;
+      } else {
+       /* If we are normal server and did not send the request first to router
+          do it now, since we do not have the Client ID information. */
+       if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+           server->server_type == SILC_SERVER && !cmd->pending && 
+           !server->standalone) {
+         silc_server_command_whois_send_router(cmd);
+         ret = -1;
+         goto out;
+       }
       }
     }
   } else {
+    /* Find by nickname */
     if (!silc_idlist_get_clients_by_hash(server->local_list, 
                                         nick, server->md5hash,
                                         &clients, &clients_count))
@@ -906,6 +930,16 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
   }
   
   if (!clients) {
+    /* If we are normal server and did not send the request first to router
+       do it now, since we do not have the information. */
+    if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
+       server->server_type == SILC_SERVER && !cmd->pending && 
+       !server->standalone) {
+      silc_server_command_whois_send_router(cmd);
+      ret = -1;
+      goto out;
+    }
+
     /* Such client(s) really does not exist in the SILC network. */
     if (!client_id_count) {
       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
@@ -933,7 +967,7 @@ silc_server_command_whois_process(SilcServerCommandContext cmd)
 
   /* Send the command reply */
   silc_server_command_whois_send_reply(cmd, clients, clients_count,
-                                      count);
+                                      count, nick, client_id);
 
  out:
   if (client_id_count) {
@@ -1070,9 +1104,7 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
     /* We will take only clients that are not valid anymore. They are the
        ones that are not registered anymore but still have a ID. They
        have disconnected us, and thus valid for WHOWAS. */
-    if (entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
-      continue;
-    if (entry->id == NULL)
+    if (entry->data.status & SILC_IDLIST_STATUS_REGISTERED || !entry->id)
       continue;
 
     if (count && i - 1 == count)
@@ -1082,19 +1114,31 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd,
 
     if (clients_count > 2)
       status = SILC_STATUS_LIST_ITEM;
-
     if (clients_count > 1 && i == clients_count - 1)
       status = SILC_STATUS_LIST_END;
 
     /* Sanity check, however these should never fail. However, as
        this sanity check has been added here they have failed. */
-    if (!entry->nickname || !entry->username)
+    if (!entry->nickname || !entry->username || !entry->userinfo) {
+      SILC_LOG_ERROR(("********* if (!entry->nickname || !entry->username "
+                     "|| !entry->userinfo) triggered: should have not!"));
+      continue;
+    }
+
+#if 1
+    /* XXX REMOVE */
+    /* Sanity check, however these should never fail. However, as
+       this sanity check has been added here they have failed. */
+    if (!entry->nickname || !entry->username) {
+      SILC_LOG_ERROR(("********* if (!entry->nickname || !entry->username) "
+                     "triggered: should have not!"));
       continue;
+    }
+#endif
       
     /* Send WHOWAS reply */
     idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
     tmp = silc_argument_get_first_arg(cmd->args, NULL);
-    
     memset(uh, 0, sizeof(uh));
     memset(nh, 0, sizeof(nh));
 
@@ -1117,23 +1161,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);
     
@@ -1269,7 +1305,35 @@ SILC_SERVER_CMD_FUNC(whowas)
 
 ******************************************************************************/
 
-static bool
+static void 
+silc_server_command_identify_send_router(SilcServerCommandContext cmd)
+{
+  SilcServer server = cmd->server;
+  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);
+
+  /* Send IDENTIFY command to our router */
+  silc_server_packet_send(server, (SilcSocketConnection)
+                         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_IDENTIFY, 
+                             silc_command_get_ident(cmd->payload),
+                             silc_server_command_destructor,
+                             silc_server_command_identify,
+                             silc_server_command_dup(cmd));
+  cmd->pending = TRUE;
+  silc_command_set_ident(cmd->payload, old_ident);
+  silc_buffer_free(tmpbuf);
+}
+
+static int
 silc_server_command_identify_parse(SilcServerCommandContext cmd,
                                   SilcClientEntry **clients,
                                   uint32 *clients_count,
@@ -1299,6 +1363,15 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
   if (!tmp) {
     /* No ID, get the names. */
 
+    /* If we are normal server and have not resolved information from
+       router yet, do so now. */
+    if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
+       server->server_type == SILC_SERVER && !cmd->pending && 
+       !server->standalone) {
+      silc_server_command_identify_send_router(cmd);
+      return -1;
+    }
+
     /* Try to get nickname@server. */
     tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
     if (tmp) {
@@ -1326,10 +1399,11 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       silc_free(nick_server);
 
       if (!(*clients)) {
+       /* the nickname does not exist, send error reply */
        silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
                                             SILC_STATUS_ERR_NO_SUCH_NICK,
                                             3, tmp, strlen(tmp));
-       return FALSE;
+       return 0;
       }
     }
 
@@ -1348,10 +1422,11 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       }
 
       if (!(*servers)) {
+       /* the server does not exist, send error reply */
        silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
                                             SILC_STATUS_ERR_NO_SUCH_SERVER,
                                             3, tmp, strlen(tmp));
-       return FALSE;
+       return 0;
       }
     }
 
@@ -1370,17 +1445,18 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
       }
 
       if (!(*channels)) {
+       /* The channel does not exist, send error reply */
        silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
                                             SILC_STATUS_ERR_NO_SUCH_CHANNEL,
                                             3, tmp, strlen(tmp));
-       return FALSE;
+       return 0;
       }
     }
 
     if (!(*clients) && !(*servers) && !(*channels)) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-      return FALSE;
+      return 0;
     }
   } else {
     /* Command includes ID, we must use that.  Also check whether the command
@@ -1394,14 +1470,15 @@ 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);
        silc_free(*channels);
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
-                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-       return FALSE;
+       silc_server_command_send_status_reply(
+                                      cmd, SILC_COMMAND_IDENTIFY,
+                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       return 0;
       }
 
       id = silc_id_payload_get_id(idp);
@@ -1419,10 +1496,23 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
                                  (*clients_count + 1));
          (*clients)[(*clients_count)++] = (SilcClientEntry)entry;
        } else {
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+         /* If we are normal server and have not resolved information from
+            router yet, do so now. */
+         if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
+             server->server_type == SILC_SERVER && !cmd->pending && 
+             !server->standalone) {
+           silc_server_command_identify_send_router(cmd);
+           silc_free(*clients);
+           silc_free(*servers);
+           silc_free(*channels);
+           return -1;
+         } else {
+           silc_server_command_send_status_data(
+                                       cmd, SILC_COMMAND_IDENTIFY,
                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                              2, tmp, len);
-         error = TRUE;
+                                       2, tmp, len);
+           error = TRUE;
+         }
        }
 
        break;
@@ -1438,10 +1528,23 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
                                  (*servers_count + 1));
          (*servers)[(*servers_count)++] = (SilcServerEntry)entry;
        } else {
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                       SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
-                                              2, tmp, len);
-         error = TRUE;
+         /* If we are normal server and have not resolved information from
+            router yet, do so now. */
+         if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
+             server->server_type == SILC_SERVER && !cmd->pending && 
+             !server->standalone) {
+           silc_server_command_identify_send_router(cmd);
+           silc_free(*clients);
+           silc_free(*servers);
+           silc_free(*channels);
+           return -1;
+         } else {
+           silc_server_command_send_status_data(
+                                        cmd, SILC_COMMAND_IDENTIFY,
+                                        SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
+                                        2, tmp, len);
+           error = TRUE;
+         }
        }
        break;
        
@@ -1456,10 +1559,23 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
                                   (*channels_count + 1));
          (*channels)[(*channels_count)++] = (SilcChannelEntry)entry;
        } else {
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                       SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
-                                              2, tmp, len);
-         error = TRUE;
+         /* If we are normal server and have not resolved information from
+            router yet, do so now. */
+         if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
+             server->server_type == SILC_SERVER && !cmd->pending && 
+             !server->standalone) {
+           silc_server_command_identify_send_router(cmd);
+           silc_free(*clients);
+           silc_free(*servers);
+           silc_free(*channels);
+           return -1;
+         } else {
+           silc_server_command_send_status_data(
+                                        cmd, SILC_COMMAND_IDENTIFY,
+                                        SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+                                        2, tmp, len);
+           error = TRUE;
+         }
        }
        break;
       }
@@ -1482,7 +1598,7 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd,
   else
     *count = 0;
 
-  return TRUE;
+  return 1;
 }
 
 /* Checks that all mandatory fields in client entry are present. If not
@@ -1503,12 +1619,23 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd,
 
   for (i = 0; i < clients_count; i++) {
     entry = clients[i];
-
-    if (!entry || entry->nickname || 
-       !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED) ||
-       !entry->router)
+    if (!entry)
       continue;
 
+    if (entry->nickname || 
+       !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
+      if (!entry->router)
+       continue;
+
+      /* If we are normal server, and we've not resolved this client from
+        router and it is global client, we'll check whether it is on some
+        channel.  If not then we cannot be sure about its validity, and
+        we'll resolve it from router. */
+      if (cmd->server->server_type != SILC_SERVER || cmd->pending ||
+         entry->connection || silc_hash_table_count(entry->channels))
+       continue;
+    }
+
     /* We need to resolve this entry since it is not complete */
 
     if (!cmd->pending && entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
@@ -1628,7 +1755,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
                                        int count)
 {
   SilcServer server = cmd->server;
-  int i, k, len;
+  int i, k, len, valid_count;
   SilcBuffer packet, idp;
   SilcCommandStatus status;
   uint16 ident = silc_command_get_ident(cmd->payload);
@@ -1640,62 +1767,58 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
   if (clients) {
     SilcClientEntry entry;
 
-    len = 0;
-    for (i = 0; i < clients_count; i++)
+    /* Process only valid entries. */
+    valid_count = 0;
+    for (i = 0; i < clients_count; i++) {
       if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED)
-       len++;
+       valid_count++;
+      else
+       clients[i] = NULL;
+    }
+
+    if (!valid_count) {
+      /* No valid entries found at all, just send error */
+      unsigned char *tmp;
 
-    if (len == 0 && clients_count) {
-      entry = clients[0];
-      if (entry->nickname) {
+      tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+      if (tmp) {
        silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
                                             SILC_STATUS_ERR_NO_SUCH_NICK,
-                                            3, entry->nickname, 
-                                            strlen(entry->nickname));
+                                            3, tmp, strlen(tmp));
       } else {
-       SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+       tmp = silc_argument_get_arg_type(cmd->args, 5, (uint32 *)&len);
        silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
                                             SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                            2, idp->data, idp->len);
-       silc_buffer_free(idp);
+                                            2, tmp, len);
       }
-      
       return;
     }
 
+    /* Process all valid client entries and send command replies */
+
     if (len > 1)
       status = SILC_STATUS_LIST_START;
 
     for (i = 0, k = 0; i < clients_count; i++) {
       entry = clients[i];
-      
-      if (!(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
-       if (clients_count == 1) {
-         SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-         silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
-                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                              2, idp->data, idp->len);
-         silc_buffer_free(idp);
-       }
+      if (!entry)
        continue;
-      }
-      
+
       if (k >= 1)
        status = SILC_STATUS_LIST_ITEM;
-      if (clients_count > 1 && k == clients_count - 1 
+      if (valid_count > 1 && k == valid_count - 1 
          && !servers_count && !channels_count)
        status = SILC_STATUS_LIST_END;
       if (count && k - 1 == count)
        status = SILC_STATUS_LIST_END;
       if (count && k - 1 > count)
        break;
-      
+
       /* Send IDENTIFY reply */
+
       idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
-      
       memset(uh, 0, sizeof(uh));
       memset(nh, 0, sizeof(nh));
-      
       strncat(nh, entry->nickname, strlen(entry->nickname));
       if (!strchr(entry->nickname, '@')) {
        strncat(nh, "@", 1);
@@ -1708,7 +1831,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
                  server->server_name, len);
        }
       }
-      
+
       if (!entry->username) {
        packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
                                                      status, ident, 2,
@@ -1740,9 +1863,6 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
     }
   }
 
-  status = (status == SILC_STATUS_LIST_ITEM ? 
-           SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
-
   if (servers) {
     SilcServerEntry entry;
 
@@ -1763,19 +1883,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);
       
@@ -1786,9 +1900,6 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
     }
   }
 
-  status = (status == SILC_STATUS_LIST_ITEM ? 
-           SILC_STATUS_LIST_ITEM : SILC_STATUS_OK);
-
   if (channels) {
     SilcChannelEntry entry;
 
@@ -1809,19 +1920,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);
       
@@ -1836,7 +1941,6 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd,
 static int
 silc_server_command_identify_process(SilcServerCommandContext cmd)
 {
-  SilcServer server = cmd->server;
   uint32 count = 0;
   int ret = 0;
   SilcClientEntry *clients = NULL;
@@ -1844,51 +1948,14 @@ silc_server_command_identify_process(SilcServerCommandContext cmd)
   SilcChannelEntry *channels = NULL;
   uint32 clients_count = 0, servers_count = 0, channels_count = 0;
 
-  /* Protocol dictates that we must always send the received IDENTIFY request
-     to our router if we are normal server, so let's do it now unless we
-     are standalone. We will not send any replies to the client until we
-     have received reply from the router. */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && 
-      server->server_type == SILC_SERVER && !cmd->pending && 
-      !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);
-
-    /* Send IDENTIFY command to our router */
-    silc_server_packet_send(server, (SilcSocketConnection)
-                           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_IDENTIFY, 
-                               silc_command_get_ident(cmd->payload),
-                               silc_server_command_destructor,
-                               silc_server_command_identify,
-                               silc_server_command_dup(cmd));
-    cmd->pending = TRUE;
-
-    silc_command_set_ident(cmd->payload, old_ident);
-
-    silc_buffer_free(tmpbuf);
-    ret = -1;
-    goto out;
-  }
-
-  /* We are ready to process the command request. Let's search for the
-     requested client and send reply to the requesting client. */
-
   /* Parse the IDENTIFY request */
-  if (!silc_server_command_identify_parse(cmd,
-                                         &clients, &clients_count,
-                                         &servers, &servers_count,
-                                         &channels, &channels_count,
-                                         &count))
-    return 0;
+  ret = silc_server_command_identify_parse(cmd,
+                                          &clients, &clients_count,
+                                          &servers, &servers_count,
+                                          &channels, &channels_count,
+                                          &count);
+  if (ret < 1)
+    return ret;
 
   /* Check that all mandatory fields are present and request those data
      from the server who owns the client if necessary. */
@@ -1909,7 +1976,6 @@ silc_server_command_identify_process(SilcServerCommandContext cmd)
   silc_free(clients);
   silc_free(servers);
   silc_free(channels);
-
   return ret;
 }
 
@@ -1937,22 +2003,9 @@ static int silc_server_command_bad_chars(char *nick)
       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;
-    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;
-    if (nick[i] == '}') return TRUE;
-    if (nick[i] == '<') return TRUE;
-    if (nick[i] == '>') return TRUE;
   }
 
   return FALSE;
@@ -2029,7 +2082,7 @@ SILC_SERVER_CMD_FUNC(nick)
 
   /* Update client cache */
   silc_idcache_add(server->local_list->clients, client->nickname, 
-                  client->id, (void *)client, FALSE);
+                  client->id, (void *)client, 0, NULL);
 
   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
@@ -2088,14 +2141,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 (lch_count > 1 && i == lch_count - 1 && !gch_count)
+    if (i >= 1 && i == lch_count - 1 && !gch_count)
       status = SILC_STATUS_LIST_END;
 
     idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
@@ -2110,23 +2161,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);
@@ -2134,19 +2176,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);
@@ -2161,23 +2199,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);
@@ -2250,6 +2279,9 @@ SILC_SERVER_CMD_FUNC(list)
   silc_server_command_list_send_reply(cmd, lchannels, lch_count, 
                                      gchannels, gch_count);
 
+  silc_free(lchannels);
+  silc_free(gchannels);
+
  out:
   silc_server_command_free(cmd);
 }
@@ -2340,13 +2372,14 @@ SILC_SERVER_CMD_FUNC(topic)
     if (!server->standalone)
       silc_server_send_notify_topic_set(server, server->router->connection,
                                        server->server_type == SILC_ROUTER ?
-                                       TRUE : FALSE, channel, client->id,
+                                       TRUE : FALSE, channel, 
+                                       client->id, SILC_ID_CLIENT,
                                        channel->topic);
 
     idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
     /* Send notify about topic change to all clients on the channel */
-    silc_server_send_notify_to_channel(server, NULL, channel, TRUE,
+    silc_server_send_notify_to_channel(server, NULL, channel, TRUE, 
                                       SILC_NOTIFY_TYPE_TOPIC_SET, 2,
                                       idp->data, idp->len,
                                       channel->topic, strlen(channel->topic));
@@ -2355,16 +2388,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);
 
@@ -2921,20 +2950,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);
     
@@ -2994,7 +3017,9 @@ static void silc_server_command_join_channel(SilcServer server,
                                             SilcClientID *client_id,
                                             bool created,
                                             bool create_key,
-                                            uint32 umode)
+                                            uint32 umode,
+                                            const unsigned char *auth,
+                                            uint32 auth_len)
 {
   SilcSocketConnection sock = cmd->sock;
   unsigned char *tmp;
@@ -3005,6 +3030,7 @@ static void silc_server_command_join_channel(SilcServer server,
   SilcBuffer reply, chidp, clidp, keyp = NULL, user_list, mode_list;
   uint16 ident = silc_command_get_ident(cmd->payload);
   char check[512], check2[512];
+  bool founder = FALSE;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -3034,64 +3060,104 @@ static void silc_server_command_join_channel(SilcServer server,
   }
 
   /*
-   * Check channel modes
+   * Check founder auth payload if provided.  If client can gain founder
+   * privileges it can override various conditions on joining the channel,
+   * and can have directly the founder mode set on the channel.
    */
-
-  memset(check, 0, sizeof(check));
-  memset(check2, 0, sizeof(check2));
-  strncat(check, client->nickname, strlen(client->nickname));
-  strncat(check, "!", 1);
-  strncat(check, client->username, strlen(client->username));
-  if (!strchr(client->username, '@')) {
-    strncat(check, "@", 1);
-    strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
+  if (auth && auth_len && channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+    SilcIDListData idata = (SilcIDListData)client;
+
+    if (channel->founder_key && idata->public_key &&
+       silc_pkcs_public_key_compare(channel->founder_key, 
+                                    idata->public_key)) {
+      void *auth_data = (channel->founder_method == SILC_AUTH_PASSWORD ?
+                        (void *)channel->founder_passwd : 
+                        (void *)channel->founder_key);
+      uint32 auth_data_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
+                             channel->founder_passwd_len : 0);
+
+      /* Check whether the client is to become founder */
+      if (silc_auth_verify_data(auth, auth_len, channel->founder_method, 
+                               auth_data, auth_data_len,
+                               idata->hash, client->id, SILC_ID_CLIENT)) {
+       umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
+       founder = TRUE;
+      }
+    }
   }
 
-  strncat(check2, client->nickname, strlen(client->nickname));
-  if (!strchr(client->nickname, '@')) {
-    strncat(check2, "@", 1);
-    strncat(check2, server->server_name, strlen(server->server_name));
-  }
-  strncat(check2, "!", 1);
-  strncat(check2, client->username, strlen(client->username));
-  if (!strchr(client->username, '@')) {
-    strncat(check2, "@", 1);
-    strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
-  }
+  /*
+   * Check channel modes
+   */
 
-  /* Check invite list if channel is invite-only channel */
-  if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
-    if (!channel->invite_list ||
-       (!silc_string_match(channel->invite_list, check) &&
-        !silc_string_match(channel->invite_list, check2))) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                           SILC_STATUS_ERR_NOT_INVITED);
-      goto out;
+  if (!umode) {
+    memset(check, 0, sizeof(check));
+    memset(check2, 0, sizeof(check2));
+    strncat(check, client->nickname, strlen(client->nickname));
+    strncat(check, "!", 1);
+    strncat(check, client->username, strlen(client->username));
+    if (!strchr(client->username, '@')) {
+      strncat(check, "@", 1);
+      strncat(check, cmd->sock->hostname, strlen(cmd->sock->hostname));
     }
-  }
 
-  /* Check ban list if it exists. If the client's nickname, server,
-     username and/or hostname is in the ban list the access to the
-     channel is denied. */
-  if (channel->ban_list) {
-    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);
-      goto out;
+    strncat(check2, client->nickname, strlen(client->nickname));
+    if (!strchr(client->nickname, '@')) {
+      strncat(check2, "@", 1);
+      strncat(check2, server->server_name, strlen(server->server_name));
+    }
+    strncat(check2, "!", 1);
+    strncat(check2, client->username, strlen(client->username));
+    if (!strchr(client->username, '@')) {
+      strncat(check2, "@", 1);
+      strncat(check2, cmd->sock->hostname, strlen(cmd->sock->hostname));
+    }
+    
+    /* Check invite list if channel is invite-only channel */
+    if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+      if (!channel->invite_list ||
+         (!silc_string_match(channel->invite_list, check) &&
+          !silc_string_match(channel->invite_list, check2))) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                             SILC_STATUS_ERR_NOT_INVITED);
+       goto out;
+      }
     }
-  }
 
-  /* Get passphrase */
-  tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
-  if (tmp) {
-    passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
-    memcpy(passphrase, tmp, tmp_len);
+    /* Check ban list if it exists. If the client's nickname, server,
+       username and/or hostname is in the ban list the access to the
+       channel is denied. */
+    if (channel->ban_list) {
+      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);
+       goto out;
+      }
+    }
+    
+    /* Check user count limit if set. */
+    if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
+      if (silc_hash_table_count(channel->user_list) + 1 > 
+         channel->user_limit) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                             SILC_STATUS_ERR_CHANNEL_IS_FULL);
+       goto out;
+      }
+    }
   }
-  
+
   /* Check the channel passphrase if set. */
   if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+    /* Get passphrase */
+    tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+    if (tmp) {
+      passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
+      memcpy(passphrase, tmp, tmp_len);
+    }
+  
     if (!passphrase || !channel->passphrase ||
         memcmp(channel->passphrase, passphrase,
                strlen(channel->passphrase))) {
@@ -3101,16 +3167,6 @@ static void silc_server_command_join_channel(SilcServer server,
     }
   }
 
-  /* Check user count limit if set. */
-  if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
-    if (silc_hash_table_count(channel->user_list) + 1 > 
-       channel->user_limit) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                           SILC_STATUS_ERR_CHANNEL_IS_FULL);
-      goto out;
-    }
-  }
-
   /*
    * Client is allowed to join to the channel. Make it happen.
    */
@@ -3206,7 +3262,7 @@ static void silc_server_command_join_channel(SilcServer server,
      we'll ignore it (in packet_receive.c) so we must send it here. If
      we are router then this will send it to local clients and local
      servers. */
-  silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+  silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
                                     SILC_NOTIFY_TYPE_JOIN, 2,
                                     clidp->data, clidp->len,
                                     chidp->data, chidp->len);
@@ -3222,6 +3278,24 @@ static void silc_server_command_join_channel(SilcServer server,
       /* Distribute the channel key to all backup routers. */
       silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
                              keyp->data, keyp->len, FALSE, TRUE);
+
+    /* If client became founder by providing correct founder auth data
+       notify the mode change to the channel. */
+    if (founder) {
+      SILC_PUT32_MSB(chl->mode, mode);
+      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
+                                        SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+                                        clidp->data, clidp->len,
+                                        mode, 4, clidp->data, clidp->len);
+      
+      /* Set CUMODE notify type to network */
+      if (!server->standalone)
+       silc_server_send_notify_cumode(server, server->router->connection,
+                                      server->server_type == SILC_ROUTER ? 
+                                      TRUE : FALSE, channel,
+                                      chl->mode, client->id, SILC_ID_CLIENT,
+                                      client->id);
+    }
   }
 
   silc_buffer_free(reply);
@@ -3242,14 +3316,15 @@ SILC_SERVER_CMD_FUNC(join)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  uint32 tmp_len;
+  unsigned char *auth;
+  uint32 tmp_len, auth_len;
   char *tmp, *channel_name = NULL, *cipher, *hmac;
   SilcChannelEntry channel;
   uint32 umode = 0;
   bool created = FALSE, create_key = TRUE;
   SilcClientID *client_id;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 1, 4);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 6);
 
   /* Get channel name */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -3283,9 +3358,10 @@ SILC_SERVER_CMD_FUNC(join)
     goto out;
   }
 
-  /* Get cipher and hmac name */
+  /* Get cipher, hmac name and auth payload */
   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
   hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
+  auth = silc_argument_get_arg_type(cmd->args, 6, &auth_len);
 
   /* See if the channel exists */
   channel = silc_idlist_find_channel_by_name(server->local_list, 
@@ -3427,7 +3503,8 @@ SILC_SERVER_CMD_FUNC(join)
 
   /* Join to the channel */
   silc_server_command_join_channel(server, cmd, channel, client_id,
-                                  created, create_key, umode);
+                                  created, create_key, umode,
+                                  auth, auth_len);
 
   silc_free(client_id);
 
@@ -3554,18 +3631,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);
@@ -3741,7 +3812,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcChannelClientEntry chl;
   SilcBuffer packet, cidp;
   unsigned char *tmp, *tmp_id, *tmp_mask;
-  char *cipher = NULL, *hmac = NULL;
+  char *cipher = NULL, *hmac = NULL, *passphrase = NULL;
   uint32 mode_mask, tmp_len, tmp_len2;
   uint16 ident = silc_command_get_ident(cmd->payload);
 
@@ -3865,7 +3936,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
 
       /* Save the passphrase */
-      channel->passphrase = strdup(tmp);
+      passphrase = channel->passphrase = strdup(tmp);
     }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
@@ -4076,14 +4147,16 @@ SILC_SERVER_CMD_FUNC(cmode)
   /* Finally, set the mode */
   channel->mode = mode_mask;
 
-  /* Send CMODE_CHANGE notify */
+  /* Send CMODE_CHANGE notify. */
   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
   silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 4,
+                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 5,
                                     cidp->data, cidp->len, 
                                     tmp_mask, 4,
                                     cipher, cipher ? strlen(cipher) : 0,
-                                    hmac, hmac ? strlen(hmac) : 0);
+                                    hmac, hmac ? strlen(hmac) : 0,
+                                    passphrase, passphrase ? 
+                                    strlen(passphrase) : 0);
 
   /* Set CMODE notify type to network */
   if (!server->standalone)
@@ -4091,7 +4164,7 @@ SILC_SERVER_CMD_FUNC(cmode)
                                  server->server_type == SILC_ROUTER ? 
                                  TRUE : FALSE, channel,
                                  mode_mask, client->id, SILC_ID_CLIENT,
-                                 cipher, hmac);
+                                 cipher, hmac, passphrase);
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
@@ -4103,7 +4176,7 @@ SILC_SERVER_CMD_FUNC(cmode)
     
   silc_buffer_free(packet);
   silc_free(channel_id);
-  silc_free(cidp);
+  silc_buffer_free(cidp);
 
  out:
   silc_server_command_free(cmd);
@@ -4324,7 +4397,7 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
-    silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
                                       SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
                                       idp->data, idp->len,
                                       tmp_mask, 4, 
@@ -4371,8 +4444,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);
 
@@ -4419,13 +4492,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);
@@ -4467,12 +4540,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
@@ -4819,19 +4892,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);
     
@@ -5194,7 +5261,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);