Watcher list support added.
[silc.git] / apps / silcd / packet_receive.c
index 111f3b019ceaa1a0c536c41ec3070476a5cf485d..6fcbf60132326f6d577278455c7075692f9d53bd 100644 (file)
@@ -2,9 +2,9 @@
 
   packet_receive.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2002 Pekka Riikonen
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -25,8 +25,6 @@
 #include "serverincludes.h"
 #include "server_internal.h"
 
-extern char *server_version;
-
 /* Received notify packet. Server can receive notify packets from router. 
    Server then relays the notify messages to clients if needed. */
 
@@ -69,11 +67,12 @@ void silc_server_notify(SilcServer server,
 
     /* Get the route to the client */
     dst_sock = silc_server_get_client_route(server, packet->dst_id,
-                                           packet->dst_id_len, NULL, &idata);
+                                           packet->dst_id_len, NULL, 
+                                           &idata, NULL);
     if (dst_sock)
       /* Relay the packet */
       silc_server_relay_packet(server, dst_sock, idata->send_key,
-                              idata->hmac_receive, idata->psn_send++,
+                              idata->hmac_send, idata->psn_send++,
                               packet, TRUE);
   }
 
@@ -331,7 +330,7 @@ void silc_server_notify(SilcServer server,
 
     /* Update statistics */
     server->stat.clients--;
-    if (server->server_type == SILC_ROUTER)
+    if (server->stat.cell_clients)
       server->stat.cell_clients--;
     SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
     SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
@@ -339,6 +338,11 @@ void silc_server_notify(SilcServer server,
     /* Remove the client from all channels. */
     silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE);
 
+    /* Check if anyone is watching this nickname */
+    if (server->server_type == SILC_ROUTER)
+      silc_server_check_watcher_list(server, client, NULL,
+                                    SILC_NOTIFY_TYPE_SIGNOFF);
+
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
     cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
     break;
@@ -378,9 +382,6 @@ void silc_server_notify(SilcServer server,
       goto out;
     }
 
-    if (channel->topic && !strcmp(channel->topic, tmp))
-      goto out;
-
     if (!channel_id) {
       channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
                                  packet->dst_id_type);
@@ -400,12 +401,18 @@ void silc_server_notify(SilcServer server,
       }
     }
 
+    if (channel->topic && !strcmp(channel->topic, tmp))
+      goto out;
+
     /* Get user's channel entry and check that topic set is allowed. */
     if (!silc_server_client_on_channel(client, channel, &chl))
       goto out;
-    if (chl->mode == SILC_CHANNEL_UMODE_NONE && 
-       channel->mode & SILC_CHANNEL_MODE_TOPIC)
+    if (channel->mode & SILC_CHANNEL_MODE_TOPIC &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+      SILC_LOG_DEBUG(("Topic change is not allowed"));
       goto out;
+    }
 
     /* Change the topic */
     silc_free(channel->topic);
@@ -424,6 +431,8 @@ void silc_server_notify(SilcServer server,
        * Distribute the notify to local clients on the channel
        */
       unsigned char *id, *id2;
+      char *nickname;
+      SilcUInt32 nickname_len;
 
       SILC_LOG_DEBUG(("NICK CHANGE notify"));
       
@@ -448,26 +457,26 @@ void silc_server_notify(SilcServer server,
       SILC_LOG_DEBUG(("New Client ID id(%s)", 
                      silc_id_render(client_id2, SILC_ID_CLIENT)));
 
+      /* From protocol version 1.1 we also get the new nickname */
+      nickname = silc_argument_get_arg_type(args, 3, &nickname_len);;
+
       /* Replace the Client ID */
-      client = silc_idlist_replace_client_id(server->global_list, client_id,
-                                            client_id2);
+      client = silc_idlist_replace_client_id(server,
+                                            server->global_list, client_id,
+                                            client_id2, nickname);
       if (!client)
-       client = silc_idlist_replace_client_id(server->local_list, client_id, 
-                                              client_id2);
+       client = silc_idlist_replace_client_id(server,
+                                              server->local_list, client_id, 
+                                              client_id2, nickname);
 
       if (client) {
-       /* The nickname is not valid anymore, set it NULL. This causes that
-          the nickname will be queried if someone wants to know it. */
-       if (client->nickname)
-         silc_free(client->nickname);
-       client->nickname = NULL;
-
        /* Send the NICK_CHANGE notify type to local clients on the channels
           this client is joined to. */
-       silc_server_send_notify_on_channels(server, NULL, client, 
-                                           SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
-                                           id, tmp_len, 
-                                           id2, tmp_len);
+       silc_server_send_notify_on_channels(server, client, client,
+                                           SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
+                                           id, tmp_len, id2, tmp_len,
+                                           nickname, nickname ?
+                                           nickname_len : 0);
       }
 
       silc_free(client_id);
@@ -540,8 +549,10 @@ void silc_server_notify(SilcServer server,
     if (client) {
       if (!silc_server_client_on_channel(client, channel, &chl))
        goto out;
-      if (!silc_server_check_cmode_rights(server, channel, chl, mode))
+      if (!silc_server_check_cmode_rights(server, channel, chl, mode)) {
+       SILC_LOG_DEBUG(("CMODE change is not allowed"));
        goto out;
+      }
     }
 
     /* Send the same notify to the channel */
@@ -580,8 +591,7 @@ void silc_server_notify(SilcServer server,
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
       silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
-                    channel->key_len / 8, 
-                    hash);
+                    channel->key_len / 8, hash);
       silc_hmac_set_key(channel->hmac, hash, 
                        silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
@@ -591,7 +601,7 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
     if (tmp) {
       silc_free(channel->passphrase);
-      channel->passphrase = strdup(tmp);
+      channel->passphrase = silc_memdup(tmp, tmp_len);
     }
 
     break;
@@ -685,16 +695,21 @@ void silc_server_notify(SilcServer server,
        
        if (client != client2) {
          /* Sender must be operator */
-         if (chl->mode == SILC_CHANNEL_UMODE_NONE)
+         if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+             !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+           SILC_LOG_DEBUG(("CUMODE change is not allowed"));
            goto out;
+         }
 
          /* Check that target is on channel */
          if (!silc_server_client_on_channel(client2, channel, &chl))
            goto out;
 
          /* If target is founder mode change is not allowed. */
-         if (chl->mode & SILC_CHANNEL_UMODE_CHANFO)
+         if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+           SILC_LOG_DEBUG(("CUMODE change is not allowed"));
            goto out;
+         }
        }
       }
 
@@ -821,9 +836,12 @@ void silc_server_notify(SilcServer server,
     /* Get user's channel entry and check that inviting is allowed. */
     if (!silc_server_client_on_channel(client, channel, &chl))
       goto out;
-    if (chl->mode == SILC_CHANNEL_UMODE_NONE && 
-       channel->mode & SILC_CHANNEL_MODE_INVITE)
+    if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+      SILC_LOG_DEBUG(("Inviting is not allowed"));
       goto out;
+    }
 
     /* Get the added invite */
     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
@@ -1029,7 +1047,7 @@ void silc_server_notify(SilcServer server,
 
            /* Update statistics */
            server->stat.clients--;
-           if (server->server_type == SILC_ROUTER)
+           if (server->stat.cell_clients)
              server->stat.cell_clients--;
            SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
            SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
@@ -1038,6 +1056,15 @@ void silc_server_notify(SilcServer server,
            silc_server_remove_from_channels(server, NULL, client, 
                                             TRUE, NULL, FALSE);
 
+           /* Check if anyone is watching this nickname */
+           if (server->server_type == SILC_ROUTER)
+             silc_server_check_watcher_list(server, client, NULL,
+                                            SILC_NOTIFY_TYPE_SERVER_SIGNOFF);
+
+           /* Remove this client from watcher list if it is */
+           if (local)
+             silc_server_del_from_watcher_list(server, client);
+
            /* Remove the client */
            silc_idlist_del_client(local ? server->local_list :
                                   server->global_list, client);
@@ -1116,8 +1143,7 @@ void silc_server_notify(SilcServer server,
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO)
       goto out;
     
-    /* Get kicker. In protocol version 1.0 this is not mandatory argument
-       so we check it only if it is provided. */
+    /* From protocol version 1.1 we get the kicker's ID as well. */
     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
     if (tmp) {
       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
@@ -1128,8 +1154,8 @@ void silc_server_notify(SilcServer server,
       client2 = silc_idlist_find_client_by_id(server->global_list, 
                                              client_id, TRUE, NULL);
       if (!client2) {
-       client = silc_idlist_find_client_by_id(server->local_list, 
-                                              client_id, TRUE, NULL);
+       client2 = silc_idlist_find_client_by_id(server->local_list, 
+                                               client_id, TRUE, NULL);
        if (!client2) {
          silc_free(client_id);
          goto out;
@@ -1140,8 +1166,11 @@ void silc_server_notify(SilcServer server,
       /* Kicker must be operator on channel */
       if (!silc_server_client_on_channel(client2, channel, &chl))
        goto out;
-      if (chl->mode == SILC_CHANNEL_UMODE_NONE)
+      if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+         !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+       SILC_LOG_DEBUG(("Kicking is not allowed"));
        goto out;
+      }
     }
 
     /* Send to channel */
@@ -1159,8 +1188,8 @@ void silc_server_notify(SilcServer server,
       /* 
        * Distribute the notify to local clients on channels
        */
-      unsigned char *id;
-      SilcUInt32 id_len;
+      unsigned char *id, *comment;
+      SilcUInt32 id_len, comment_len;
     
       SILC_LOG_DEBUG(("KILLED notify"));
       
@@ -1195,22 +1224,55 @@ void silc_server_notify(SilcServer server,
       }
 
       /* Get comment */
-      tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-      if (tmp_len > 128)
-       tmp = NULL;
+      comment = silc_argument_get_arg_type(args, 2, &comment_len);
+      if (comment_len > 128)
+       comment_len = 127;
+
+      /* From protocol version 1.1 we get the killer's ID as well. */
+      tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+      if (tmp) {
+       client_id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
+       if (!client_id)
+         goto out;
+
+       if (id_type == SILC_ID_CLIENT) {
+         /* If the the client is not in local list we check global list */
+         client2 = silc_idlist_find_client_by_id(server->global_list, 
+                                                 client_id, TRUE, NULL);
+         if (!client2) {
+           client2 = silc_idlist_find_client_by_id(server->local_list, 
+                                                   client_id, TRUE, NULL);
+           if (!client2) {
+             silc_free(client_id);
+             goto out;
+           }
+         }
+         silc_free(client_id);
+
+         /* Killer must be router operator */
+         if (!(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+           SILC_LOG_DEBUG(("Killing is not allowed"));
+           goto out;
+         }
+       }
+      }
 
       /* Send the notify to local clients on the channels except to the
         client who is killed. */
       silc_server_send_notify_on_channels(server, client, client,
-                                         SILC_NOTIFY_TYPE_KILLED, 
-                                         tmp ? 2 : 1,
-                                         id, id_len, 
+                                         SILC_NOTIFY_TYPE_KILLED, 3,
+                                         id, id_len, comment, comment_len,
                                          tmp, tmp_len);
 
       /* Remove the client from all channels */
       silc_server_remove_from_channels(server, NULL, client, FALSE, NULL, 
                                       FALSE);
 
+      /* Check if anyone is watching this nickname */
+      if (server->server_type == SILC_ROUTER)
+       silc_server_check_watcher_list(server, client, NULL,
+                                      SILC_NOTIFY_TYPE_KILLED);
+
       break;
     }
 
@@ -1249,12 +1311,23 @@ void silc_server_notify(SilcServer server,
     SILC_GET32_MSB(mode, tmp);
 
     /* Check that mode changing is allowed. */
-    if (!silc_server_check_umode_rights(server, client, mode))
+    if (!silc_server_check_umode_rights(server, client, mode)) {
+      SILC_LOG_DEBUG(("UMODE change is not allowed"));
       goto out;
+    }
+
+    /* Remove internal resumed flag if client is marked detached now */
+    if (mode & SILC_UMODE_DETACHED)
+      client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
 
     /* Change the mode */
     client->mode = mode;
 
+    /* Check if anyone is watching this nickname */
+    if (server->server_type == SILC_ROUTER)
+      silc_server_check_watcher_list(server, client, NULL,
+                                    SILC_NOTIFY_TYPE_UMODE_CHANGE);
+
     break;
 
   case SILC_NOTIFY_TYPE_BAN:
@@ -1323,6 +1396,42 @@ void silc_server_notify(SilcServer server,
     }
     break;
 
+  case SILC_NOTIFY_TYPE_ERROR:
+    {
+      /*
+       * Error notify
+       */
+      SilcStatus error;
+
+      tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+      if (!tmp && tmp_len != 1)
+       goto out;
+      error = (SilcStatus)tmp[0];
+
+      SILC_LOG_DEBUG(("ERROR notify (%d)", error));
+
+      if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
+         sock->type == SILC_SOCKET_TYPE_ROUTER) {
+       tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+       if (tmp) {
+         SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
+                         "the entry from cache"));
+         client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+         if (!client_id)
+           goto out;
+         client = silc_idlist_find_client_by_id(server->global_list, 
+                                                client_id, FALSE, NULL);
+         if (client) {
+           silc_server_remove_from_channels(server, NULL, client, TRUE, 
+                                            NULL, TRUE);
+           silc_idlist_del_client(server->global_list, client);
+         }
+         silc_free(client_id);
+       }
+      }
+    }
+    break;
+
     /* Ignore rest of the notify types for now */
   case SILC_NOTIFY_TYPE_NONE:
   case SILC_NOTIFY_TYPE_MOTD:
@@ -1400,6 +1509,7 @@ void silc_server_private_message(SilcServer server,
 {
   SilcSocketConnection dst_sock;
   SilcIDListData idata;
+  SilcClientEntry client;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1409,36 +1519,54 @@ void silc_server_private_message(SilcServer server,
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
-                                         packet->dst_id_len, NULL, &idata);
+                                         packet->dst_id_len, NULL, 
+                                         &idata, &client);
   if (!dst_sock) {
-    /* Send IDENTIFY command reply with error status to indicate that
-       such destination ID does not exist or is invalid */
-    SilcBuffer idp = silc_id_payload_encode_data(packet->dst_id,
-                                                packet->dst_id_len,
-                                                packet->dst_id_type);
+    SilcBuffer idp;
+    unsigned char error;
+
+    if (client && client->mode & SILC_UMODE_DETACHED) {
+      SILC_LOG_DEBUG(("Client is detached, discarding packet"));
+      return;
+    }
+
+    /* Send SILC_NOTIFY_TYPE_ERROR to indicate that such destination ID
+       does not exist or is invalid. */
+    idp = silc_id_payload_encode_data(packet->dst_id,
+                                     packet->dst_id_len,
+                                     packet->dst_id_type);
     if (!idp)
       return;
 
+    error = SILC_STATUS_ERR_NO_SUCH_CLIENT_ID;
     if (packet->src_id_type == SILC_ID_CLIENT) {
       SilcClientID *client_id = silc_id_str2id(packet->src_id,
                                               packet->src_id_len,
                                               packet->src_id_type);
-      silc_server_send_dest_command_reply(server, sock, 
-                                         client_id, SILC_ID_CLIENT,
-                                         SILC_COMMAND_IDENTIFY,
-                                         SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 
-                                         0, 1, 2, idp->data, idp->len);
+      silc_server_send_notify_dest(server, sock, FALSE,
+                                  client_id, SILC_ID_CLIENT,
+                                  SILC_NOTIFY_TYPE_ERROR, 2,
+                                  &error, 1,
+                                  idp->data, idp->len);
       silc_free(client_id);
     } else {
-      silc_server_send_command_reply(server, sock, SILC_COMMAND_IDENTIFY,
-                                    SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 
-                                    0, 1, 2, idp->data, idp->len);
+      silc_server_send_notify(server, sock, FALSE,
+                             SILC_NOTIFY_TYPE_ERROR, 2,
+                             &error, 1,
+                             idp->data, idp->len);
     }
 
     silc_buffer_free(idp);
     return;
   }
 
+  /* Check whether destination client wishes to receive private messages */
+  if (client && !(packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) &&
+      client->mode & SILC_UMODE_BLOCK_PRIVMSG) {
+    SILC_LOG_DEBUG(("Client blocks private messages, discarding packet"));
+    return;
+  }
+
   /* Send the private message */
   silc_server_send_private_message(server, dst_sock, idata->send_key,
                                   idata->hmac_send, idata->psn_send++,
@@ -1468,7 +1596,8 @@ void silc_server_private_message_key(SilcServer server,
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
-                                         packet->dst_id_len, NULL, &idata);
+                                         packet->dst_id_len, NULL, 
+                                         &idata, NULL);
   if (!dst_sock)
     return;
 
@@ -1563,6 +1692,7 @@ void silc_server_channel_message(SilcServer server,
   SilcChannelID *id = NULL;
   void *sender_id = NULL;
   SilcClientEntry sender_entry = NULL;
+  SilcChannelClientEntry chl;
   bool local = TRUE;
 
   SILC_LOG_DEBUG(("Processing channel message"));
@@ -1581,7 +1711,34 @@ void silc_server_channel_message(SilcServer server,
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
     if (!channel) {
-      SILC_LOG_DEBUG(("Could not find channel"));
+      SilcBuffer idp;
+      unsigned char error;
+
+      /* Send SILC_NOTIFY_TYPE_ERROR to indicate that such destination ID
+        does not exist or is invalid. */
+      idp = silc_id_payload_encode_data(packet->dst_id,
+                                       packet->dst_id_len,
+                                       packet->dst_id_type);
+      if (!idp)
+       goto out;
+
+      error = SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID;
+      if (packet->src_id_type == SILC_ID_CLIENT) {
+       SilcClientID *client_id = silc_id_str2id(packet->src_id,
+                                                packet->src_id_len,
+                                                packet->src_id_type);
+       silc_server_send_notify_dest(server, sock, FALSE,
+                                    client_id, SILC_ID_CLIENT,
+                                    SILC_NOTIFY_TYPE_ERROR, 2,
+                                    &error, 1, idp->data, idp->len);
+       silc_free(client_id);
+      } else {
+       silc_server_send_notify(server, sock, FALSE,
+                               SILC_NOTIFY_TYPE_ERROR, 2,
+                               &error, 1, idp->data, idp->len);
+      }
+      
+      silc_buffer_free(idp);
       goto out;
     }
   }
@@ -1601,11 +1758,26 @@ void silc_server_channel_message(SilcServer server,
                                                   sender_id, TRUE, NULL);
     }
     if (!sender_entry || !silc_server_client_on_channel(sender_entry, 
-                                                       channel, NULL)) {
+                                                       channel, &chl)) {
       SILC_LOG_DEBUG(("Client not on channel"));
       goto out;
     }
 
+    /* If channel is moderated check that client is allowed to send
+       messages. */
+    if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && 
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+      SILC_LOG_DEBUG(("Channel is silenced from normal users"));
+      goto out;
+    }
+    if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS && 
+       chl->mode & SILC_CHANNEL_UMODE_CHANOP &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+      SILC_LOG_DEBUG(("Channel is silenced from operators"));
+      goto out;
+    }
+
     /* If the packet is coming from router, but the client entry is local 
        entry to us then some router is rerouting this to us and it is not 
        allowed. When the client is local to us it means that we've routed
@@ -1671,9 +1843,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   SilcBuffer buffer = packet->buffer;
   SilcClientEntry client;
   SilcClientID *client_id;
-  SilcBuffer reply;
   SilcIDListData idata;
-  char *username = NULL, *realname = NULL, *id_string;
+  char *username = NULL, *realname = NULL;
   SilcUInt16 username_len;
   SilcUInt32 id_len;
   int ret;
@@ -1821,6 +1992,11 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   while (!silc_id_create_client_id(server, server->id, server->rng, 
                                   server->md5hash, nickname, &client_id)) {
     nickfail++;
+    if (nickfail > 9) {
+      silc_server_disconnect_remote(server, sock, 
+                                   "Server closed connection: Bad nickname");
+      return NULL;
+    }
     snprintf(&nickname[strlen(nickname) - 1], 1, "%d", nickfail);
   }
 
@@ -1844,72 +2020,15 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                            client->id, SILC_ID_CLIENT, id_len);
   
   /* Send the new client ID to the client. */
-  id_string = silc_id_id2str(client->id, SILC_ID_CLIENT);
-  reply = silc_buffer_alloc(2 + 2 + id_len);
-  silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply));
-  silc_buffer_format(reply,
-                    SILC_STR_UI_SHORT(SILC_ID_CLIENT),
-                    SILC_STR_UI_SHORT(id_len),
-                    SILC_STR_UI_XNSTRING(id_string, id_len),
-                    SILC_STR_END);
-  silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 0, 
-                         reply->data, reply->len, FALSE);
-  silc_free(id_string);
-  silc_buffer_free(reply);
+  silc_server_send_new_id(server, sock, FALSE, client->id, SILC_ID_CLIENT,
+                         silc_id_get_len(client->id, SILC_ID_CLIENT));
 
   /* Send some nice info to the client */
-  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                         ("Welcome to the SILC Network %s",
-                          username));
-  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                         ("Your host is %s, running version %s",
-                          server->config->server_info->server_name,
-                          server_version));
-  if (server->server_type == SILC_ROUTER) {
-    SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("There are %d clients on %d servers in SILC "
-                            "Network", server->stat.clients,
-                            server->stat.servers + 1));
-    SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("There are %d clients on %d server in our cell",
-                            server->stat.cell_clients,
-                            server->stat.cell_servers + 1));
-    SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("I have %d clients, %d channels, %d servers and "
-                            "%d routers",
-                            server->stat.my_clients, 
-                            server->stat.my_channels,
-                            server->stat.my_servers,
-                            server->stat.my_routers));
-    SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("There are %d server operators and %d router "
-                            "operators online",
-                            server->stat.server_ops,
-                            server->stat.router_ops));
-    SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("I have %d operators online",
-                            server->stat.my_router_ops +
-                            server->stat.my_server_ops));
-  } else {
-    SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("I have %d clients and %d channels formed",
-                            server->stat.my_clients,
-                            server->stat.my_channels));
-    SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("%d operators online",
-                            server->stat.my_server_ops));
-  }
-  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                         ("Your connection is secured with %s cipher, "
-                          "key length %d bits",
-                          idata->send_key->cipher->name,
-                          idata->send_key->cipher->key_len));
-  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                         ("Your current nickname is %s",
-                          client->nickname));
-
-  /* Send motd */
-  silc_server_send_motd(server, sock);
+  silc_server_send_connect_notifys(server, sock, client);
+
+  /* Check if anyone is watching this nickname */
+  if (server->server_type == SILC_ROUTER)
+    silc_server_check_watcher_list(server, client, NULL, 0);
 
   return client;
 }
@@ -2185,6 +2304,10 @@ static void silc_server_new_id_real(SilcServer server,
       if (sock->type == SILC_SOCKET_TYPE_SERVER)
        server->stat.cell_clients++;
       server->stat.clients++;
+
+      /* Check if anyone is watching this nickname */
+      if (server->server_type == SILC_ROUTER && id_list == server->local_list)
+       silc_server_check_watcher_list(server, entry, NULL, 0);
     }
     break;
 
@@ -2409,9 +2532,15 @@ void silc_server_new_channel(SilcServer server,
                      silc_id_render(channel_id, SILC_ID_CHANNEL), 
                      sock->hostname));
     
-      silc_idlist_add_channel(server->global_list, strdup(channel_name), 
-                             0, channel_id, sock->user_data, NULL, NULL, 0);
+      channel = 
+       silc_idlist_add_channel(server->global_list, strdup(channel_name), 
+                               0, channel_id, sock->user_data, NULL, NULL, 0);
+      if (!channel)
+       return;
+
       server->stat.channels++;
+      if (server->server_type == SILC_ROUTER)
+       channel->users_resolved = TRUE;
     }
   } else {
     /* The channel is coming from our server, thus it is in our cell
@@ -2654,7 +2783,8 @@ void silc_server_key_agreement(SilcServer server,
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
-                                         packet->dst_id_len, NULL, &idata);
+                                         packet->dst_id_len, NULL, 
+                                         &idata, NULL);
   if (!dst_sock)
     return;
 
@@ -2771,7 +2901,8 @@ void silc_server_ftp(SilcServer server,
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
-                                         packet->dst_id_len, NULL, &idata);
+                                         packet->dst_id_len, NULL, 
+                                         &idata, NULL);
   if (!dst_sock)
     return;
 
@@ -2780,3 +2911,516 @@ void silc_server_ftp(SilcServer server,
                           idata->hmac_send, idata->psn_send++,
                           packet, FALSE);
 }
+
+typedef struct {
+  SilcServer server;
+  SilcSocketConnection sock;
+  SilcPacketContext *packet;
+  void *data;
+} *SilcServerResumeResolve;
+
+SILC_SERVER_CMD_FUNC(resume_resolve)
+{
+  SilcServerResumeResolve r = (SilcServerResumeResolve)context;
+  SilcServer server = r->server;
+  SilcSocketConnection sock = r->sock;
+  SilcServerCommandReplyContext reply = context2;
+  SilcClientEntry client;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (!reply || !silc_command_get_status(reply->payload, NULL, NULL)) {
+    SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
+                   "closing connection", sock->hostname, sock->ip));
+    silc_server_disconnect_remote(server, sock, 
+                                 "Server closed connection: "
+                                 "Incomplete resume information");
+    goto out;
+  }
+
+  if (reply && silc_command_get(reply->payload) == SILC_COMMAND_WHOIS) {
+    /* Get entry to the client, and resolve it if we don't have it. */
+    client = silc_idlist_find_client_by_id(server->local_list, 
+                                          r->data, TRUE, NULL);
+    if (!client) {
+      client = silc_idlist_find_client_by_id(server->global_list,
+                                            r->data, TRUE, NULL);
+      if (!client) {
+       SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
+                       "closing connection", sock->hostname, sock->ip));
+       silc_server_disconnect_remote(server, sock, 
+                                     "Server closed connection: "
+                                     "Incomplete resume information");
+       goto out;
+      }
+    }
+
+    if (!(client->mode & SILC_UMODE_DETACHED)) {
+      SILC_LOG_ERROR(("Client %s (%s) tried to resume un-detached client, "
+                     "closing connection", sock->hostname, sock->ip));
+      silc_server_disconnect_remote(server, sock, 
+                                   "Server closed connection: "
+                                   "Incomplete resume information");
+      goto out;
+    }
+  }
+
+  /* Reprocess the packet */
+  silc_server_resume_client(server, sock, r->packet);
+
+ out:
+  silc_socket_free(r->sock);
+  silc_packet_context_free(r->packet);
+  silc_free(r->data);
+  silc_free(r);
+}
+
+/* Received client resuming packet.  This is used to resume detached
+   client session.  It can be sent by the client who wishes to resume
+   but this is also sent by servers and routers to notify other routers
+   that the client is not detached anymore. */
+
+void silc_server_resume_client(SilcServer server,
+                              SilcSocketConnection sock,
+                              SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer, buf;
+  SilcIDListData idata;
+  SilcClientEntry detached_client;
+  SilcClientID *client_id = NULL;
+  unsigned char *id_string, *auth = NULL;
+  SilcUInt16 id_len, auth_len = 0;
+  int ret, nickfail = 0;
+  bool resolved, local, nick_change = FALSE;
+  SilcChannelEntry channel;
+  SilcHashTableList htl;
+  SilcChannelClientEntry chl;
+  SilcServerResumeResolve r;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  ret = silc_buffer_unformat(buffer,
+                            SILC_STR_UI16_NSTRING(&id_string, &id_len),
+                            SILC_STR_END);
+  if (ret != -1)
+    client_id = silc_id_str2id(id_string, id_len, SILC_ID_CLIENT);
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
+    /* Client send this and is attempting to resume to old client session */
+    SilcClientEntry client;
+    SilcBuffer keyp;
+
+    if (ret != -1) {
+      silc_buffer_pull(buffer, 2 + id_len);
+      auth = buffer->data;
+      auth_len = buffer->len;
+      silc_buffer_push(buffer, 2 + id_len);
+    }
+
+    if (!client_id || auth_len < 128) {
+      SILC_LOG_ERROR(("Client %s (%s) sent incomplete resume information, "
+                     "closing connection", sock->hostname, sock->ip));
+      silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                   "Incomplete resume information");
+      return;
+    }
+
+    /* Take client entry of this connection */
+    client = (SilcClientEntry)sock->user_data;
+    idata = (SilcIDListData)client;
+
+    /* Get entry to the client, and resolve it if we don't have it. */
+    detached_client = silc_server_get_client_resolve(server, client_id, FALSE,
+                                                    &resolved);
+    if (!detached_client) {
+      if (resolved) {
+       /* The client info is being resolved. Reprocess this packet after
+          receiving the reply to the query. */
+       SILC_LOG_DEBUG(("Resolving client"));
+       r = silc_calloc(1, sizeof(*r));
+       if (!r)
+         return;
+       r->server = server;
+       r->sock = silc_socket_dup(sock);
+       r->packet = silc_packet_context_dup(packet);
+       r->data = silc_id_dup(client_id, SILC_ID_CLIENT);
+       silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+                                   server->cmd_ident,
+                                   silc_server_command_resume_resolve, r);
+      } else {
+       SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
+                       "closing connection", sock->hostname, sock->ip));
+       silc_server_disconnect_remote(server, sock, 
+                                     "Server closed connection: "
+                                     "Incomplete resume information");
+      }
+      return;
+    }
+
+    /* Check that the client is detached, and that we have other info too */
+    if (!(detached_client->mode & SILC_UMODE_DETACHED) ||
+       !silc_hash_table_count(detached_client->channels) ||
+       !detached_client->nickname) {
+      if (server->server_type == SILC_SERVER && !server->standalone) {
+       /* The client info is being resolved. Reprocess this packet after
+          receiving the reply to the query. */
+       SILC_LOG_DEBUG(("Resolving client info"));
+       silc_server_get_client_resolve(server, client_id, TRUE, NULL);
+       r = silc_calloc(1, sizeof(*r));
+       if (!r)
+         return;
+       r->server = server;
+       r->sock = silc_socket_dup(sock);
+       r->packet = silc_packet_context_dup(packet);
+       r->data = silc_id_dup(client_id, SILC_ID_CLIENT);
+       silc_server_command_pending(server, SILC_COMMAND_WHOIS,
+                                   server->cmd_ident,
+                                   silc_server_command_resume_resolve, r);
+       return;
+      }
+      if (server->server_type == SILC_SERVER) {
+       SILC_LOG_ERROR(("Client %s (%s) tried to resume un-detached client, "
+                       "closing connection", sock->hostname, sock->ip));
+       silc_server_disconnect_remote(server, sock, 
+                                     "Server closed connection: "
+                                     "Incomplete resume information");
+       return;
+      }
+    }
+
+    /* Check that we have the public key of the client, if not then we must
+       resolve it first. */
+    if (!detached_client->data.public_key) {
+      if (server->standalone) {
+       silc_server_disconnect_remote(server, sock, 
+                                     "Server closed connection: "
+                                     "Incomplete resume information");
+      } else {
+       /* We must retrieve the detached client's public key by sending
+          GETKEY command. Reprocess this packet after receiving the key */
+       SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+       SilcSocketConnection dest_sock = 
+         silc_server_get_client_route(server, NULL, 0, client_id, NULL, NULL);
+
+       SILC_LOG_DEBUG(("Resolving client public key"));
+
+       silc_server_send_command(server, dest_sock ? dest_sock : 
+                                server->router->connection,
+                                SILC_COMMAND_GETKEY, ++server->cmd_ident,
+                                1, 1, idp->data, idp->len);
+
+       r = silc_calloc(1, sizeof(*r));
+       if (!r)
+         return;
+
+       r->server = server;
+       r->sock = silc_socket_dup(sock);
+       r->packet = silc_packet_context_dup(packet);
+       silc_server_command_pending(server, SILC_COMMAND_GETKEY,
+                                   server->cmd_ident,
+                                   silc_server_command_resume_resolve, r);
+
+       silc_buffer_free(idp);
+      }
+      return;
+    } else if (!silc_pkcs_public_key_compare(detached_client->data.public_key,
+                                            idata->public_key)) {
+      /* We require that the connection and resuming authentication data
+        must be using same key pair. */
+      silc_server_disconnect_remote(server, sock, 
+                                   "Server closed connection: "
+                                   "Incomplete resume information");
+      return;
+    }
+
+    /* Verify the authentication payload.  This has to be successful in
+       order to allow the resuming */
+    if (!silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
+                              detached_client->data.public_key, 0,
+                              idata->hash, detached_client->id, 
+                              SILC_ID_CLIENT)) {
+      SILC_LOG_ERROR(("Client %s (%s) resume authentication failed, "
+                     "closing connection", sock->hostname, sock->ip));
+      silc_server_disconnect_remote(server, sock, "Server closed connection: "
+                                   "Incomplete resume information");
+      return;
+    }
+
+    /* Now resume the client to the network */
+
+    silc_schedule_task_del_by_context(server->schedule, detached_client);
+    sock->user_data = detached_client;
+    detached_client->connection = sock;
+
+    /* Take new keys and stuff into use in the old entry */
+    silc_idlist_del_data(detached_client);
+    silc_idlist_add_data(detached_client, idata);
+    detached_client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+    detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
+    detached_client->mode &= ~SILC_UMODE_DETACHED;
+
+    /* Send the RESUME_CLIENT packet to our primary router so that others
+       know this client isn't detached anymore. */
+    buf = silc_buffer_alloc_size(2 + id_len);
+    silc_buffer_format(buf,
+                      SILC_STR_UI_SHORT(id_len),
+                      SILC_STR_UI_XNSTRING(id_string, id_len),
+                      SILC_STR_END);
+
+    /* Send to primary router */
+    if (!server->standalone)
+      silc_server_packet_send(server, server->router->connection,
+                             SILC_PACKET_RESUME_CLIENT, 0, 
+                             buf->data, buf->len, TRUE);
+
+    /* As router we must deliver this packet directly to the original
+       server whom this client was earlier. */
+    if (server->server_type == SILC_ROUTER && detached_client->router &&
+       detached_client->router->server_type != SILC_ROUTER)
+      silc_server_packet_send(server, detached_client->router->connection,
+                             SILC_PACKET_RESUME_CLIENT, 0, 
+                             buf->data, buf->len, TRUE);
+    silc_buffer_free(buf);
+
+    detached_client->router = NULL;
+
+    /* Delete this client entry since we're resuming to old one. */
+    server->stat.my_clients--;
+    server->stat.clients--;
+    if (server->stat.cell_clients)
+      server->stat.cell_clients--;
+    silc_idlist_del_client(server->local_list, client);
+    client = detached_client;
+
+    /* If the ID is not based in our ID then change it */
+    if (!SILC_ID_COMPARE(client->id, server->id, server->id->ip.data_len)) {
+      while (!silc_id_create_client_id(server, server->id, server->rng, 
+                                      server->md5hash, client->nickname, 
+                                      &client_id)) {
+       nickfail++;
+       if (nickfail > 9) {
+         silc_server_disconnect_remote(server, sock, 
+                                       "Server closed connection: "
+                                       "Bad nickname");
+         return;
+       }
+       snprintf(&client->nickname[strlen(client->nickname) - 1], 1, 
+                "%d", nickfail);
+      }
+      nick_change = TRUE;
+    }
+
+    if (nick_change) {
+      /* Notify about Client ID change, nickname doesn't actually change. */
+      if (!server->standalone)
+       silc_server_send_notify_nick_change(server, server->router->connection,
+                                           FALSE, client->id, client_id,
+                                           client->nickname);
+    }
+
+    /* Resolve users on those channels that client has joined but we
+       haven't resolved user list yet. */
+    if (server->server_type == SILC_SERVER && !server->standalone) {
+      silc_hash_table_list(client->channels, &htl);
+      while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+       channel = chl->channel;
+       SILC_LOG_DEBUG(("Resolving users for %s channel", 
+                       channel->channel_name));
+       if (channel->disabled || !channel->users_resolved) {
+         silc_server_send_command(server, server->router->connection,
+                                  SILC_COMMAND_USERS, ++server->cmd_ident,
+                                  1, 2, channel->channel_name,
+                                  strlen(channel->channel_name));
+       }
+      }
+      silc_hash_table_list_reset(&htl);
+    }
+
+    /* Send the new client ID to the client. After this client may start
+       receiving other packets, and may start sending packets too. */
+    silc_server_send_new_id(server, sock, FALSE, client_id, SILC_ID_CLIENT,
+                           silc_id_get_len(client_id, SILC_ID_CLIENT));
+
+    if (nick_change) {
+      /* Send NICK change notify to channels as well. */
+      SilcBuffer oidp, nidp;
+      oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+      nidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+      silc_server_send_notify_on_channels(server, NULL, client, 
+                                         SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
+                                         oidp->data, oidp->len, 
+                                         nidp->data, nidp->len,
+                                         client->nickname, 
+                                         strlen(client->nickname));
+      silc_buffer_free(oidp);
+      silc_buffer_free(nidp);
+    }
+
+    /* Add the client again to the ID cache to get it to correct list */
+    if (!silc_idcache_del_by_context(server->local_list->clients, client))
+      silc_idcache_del_by_context(server->global_list->clients, client);
+    silc_free(client->id);
+    client->id = client_id;
+    client_id = NULL;
+    silc_idcache_add(server->local_list->clients, client->nickname,
+                    client->id, client, 0, NULL);
+
+    /* Send some nice info to the client */
+    silc_server_send_connect_notifys(server, sock, client);
+
+    /* Send all channel keys of channels the client has joined */
+    silc_hash_table_list(client->channels, &htl);
+    while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+      bool created = FALSE;
+      channel = chl->channel;
+
+      if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
+       continue;
+
+      /* If we don't have channel key, then create one */
+      if (!channel->channel_key) {
+       if (!silc_server_create_channel_key(server, channel, 0))
+         continue;
+       created = TRUE;
+      }
+
+      id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+      keyp = 
+       silc_channel_key_payload_encode(silc_id_get_len(channel->id,
+                                                       SILC_ID_CHANNEL), 
+                                       id_string,
+                                       strlen(channel->channel_key->
+                                              cipher->name),
+                                       channel->channel_key->cipher->name,
+                                       channel->key_len / 8, channel->key);
+      silc_free(id_string);
+
+      /* Send the key packet to client */
+      silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
+                             keyp->data, keyp->len, FALSE);
+
+      if (created && server->server_type == SILC_SERVER && 
+         !server->standalone)
+       silc_server_packet_send(server, server->router->connection, 
+                               SILC_PACKET_CHANNEL_KEY, 0, 
+                               keyp->data, keyp->len, FALSE);
+
+      silc_buffer_free(keyp);
+    }
+    silc_hash_table_list_reset(&htl);
+
+  } else if (sock->type != SILC_SOCKET_TYPE_CLIENT) {
+    /* Server or router sent this to us to notify that that a client has
+       been resumed. */
+    SilcServerEntry server_entry;
+    SilcServerID *server_id;
+
+    if (!client_id)
+      return;
+
+    /* Get entry to the client, and resolve it if we don't have it. */
+    detached_client = silc_idlist_find_client_by_id(server->local_list, 
+                                                   client_id, TRUE, NULL);
+    if (!detached_client) {
+      detached_client = silc_idlist_find_client_by_id(server->global_list,
+                                                     client_id, TRUE, NULL);
+      if (!detached_client)
+       return;
+    }
+
+    /* Check that the client has not been resumed already because it is
+       protocol error to attempt to resume more than once.  The client
+       will be killed if this protocol error occurs. */
+    if (detached_client->data.status & SILC_IDLIST_STATUS_RESUMED &&
+       !(detached_client->mode & SILC_UMODE_DETACHED)) {
+      /* The client is clearly attempting to resume more than once and
+        perhaps playing around by resuming from several different places
+        at the same time. */
+      silc_server_kill_client(server, detached_client, NULL,
+                             server->id, SILC_ID_SERVER);
+      return;
+    }
+
+    /* Check whether client is detached at all */
+    if (!(detached_client->mode & SILC_UMODE_DETACHED))
+      return;
+
+    /* Client is detached, and now it is resumed.  Remove the detached
+       mode and mark that it is resumed. */
+    detached_client->mode &= ~SILC_UMODE_DETACHED;
+    detached_client->data.status |= SILC_IDLIST_STATUS_RESUMED;
+
+    /* Get the new owner of the resumed client */
+    server_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+                              packet->src_id_type);
+    if (!server_id)
+      return;
+
+    /* Get server entry */
+    server_entry = silc_idlist_find_server_by_id(server->global_list, 
+                                                server_id, TRUE, NULL);
+    local = TRUE;
+    if (!server_entry) {
+      server_entry = silc_idlist_find_server_by_id(server->local_list, 
+                                                  server_id, TRUE, NULL);
+      local = FALSE;
+      if (!server_entry) {
+       silc_free(server_id);
+       return;
+      }
+    }
+
+    if (server->server_type == SILC_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_ROUTER && 
+       server_entry->server_type == SILC_ROUTER)
+      local = FALSE;
+
+    SILC_LOG_DEBUG(("Resuming detached client"));
+
+    /* Change the client to correct list. */
+    if (!silc_idcache_del_by_context(server->local_list->clients,
+                                    detached_client))
+      silc_idcache_del_by_context(server->global_list->clients,
+                                 detached_client);
+    silc_idcache_add(local && server->server_type == SILC_ROUTER ? 
+                    server->local_list->clients : 
+                    server->global_list->clients, 
+                    detached_client->nickname,
+                    detached_client->id, detached_client, FALSE, NULL);
+
+    /* Change the owner of the client if needed */
+    if (detached_client->router != server_entry)
+      detached_client->router = server_entry;
+
+    /* Update channel information regarding global clients on channel. */
+    if (server->server_type == SILC_SERVER) {
+      silc_hash_table_list(detached_client->channels, &htl);
+      while (silc_hash_table_get(&htl, NULL, (void **)&chl))
+       chl->channel->global_users = 
+         silc_server_channel_has_global(chl->channel);
+      silc_hash_table_list_reset(&htl);
+    }
+
+    silc_schedule_task_del_by_context(server->schedule, detached_client);
+
+    /* If the sender of this packet is server and we are router we need to
+       broadcast this packet to other routers in the network. */
+    if (!server->standalone && server->server_type == SILC_ROUTER &&
+       sock->type == SILC_SOCKET_TYPE_SERVER &&
+       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
+      SILC_LOG_DEBUG(("Broadcasting received Resume Client packet"));
+      silc_server_packet_send(server, server->router->connection,
+                             packet->type, 
+                             packet->flags | SILC_PACKET_FLAG_BROADCAST,
+                             buffer->data, buffer->len, FALSE);
+      silc_server_backup_send(server, (SilcServerEntry)sock->user_data, 
+                             packet->type, packet->flags,
+                             packet->buffer->data, packet->buffer->len, 
+                             FALSE, TRUE);
+    }
+
+    silc_free(server_id);
+  }
+
+  silc_free(client_id);
+}