updates.
[silc.git] / apps / silcd / packet_receive.c
index f09bccb6dc4d7910c847e52d2d79001dc20ec545..85b1a1b20444afc59ec5584ba53d8aa24a87b245 100644 (file)
@@ -180,7 +180,7 @@ void silc_server_notify(SilcServer server,
        client = 
          silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
                                 silc_id_dup(client_id, SILC_ID_CLIENT), 
-                                sock->user_data, NULL);
+                                sock->user_data, NULL, 0);
        if (!client) {
          SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
          silc_free(client_id);
@@ -324,14 +324,18 @@ void silc_server_notify(SilcServer server,
     if (tmp_len > 128)
       tmp = NULL;
 
+    /* Update statistics */
+    server->stat.clients--;
+    if (server->server_type == SILC_ROUTER)
+      server->stat.cell_clients--;
+    SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+    SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
     /* Remove the client from all channels. */
     silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE);
 
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
     cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
-    server->stat.clients--;
-    if (server->server_type == SILC_ROUTER)
-      server->stat.cell_clients--;
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
@@ -367,10 +371,8 @@ void silc_server_notify(SilcServer server,
       goto out;
     }
 
-    if (channel->topic)
-      silc_free(channel->topic);
-    channel->topic = silc_calloc(tmp_len + 1, sizeof(*channel->topic));
-    memcpy(channel->topic, tmp, tmp_len);
+    silc_free(channel->topic);
+    channel->topic = strdup(tmp);
 
     /* Send the same notify to the channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
@@ -520,6 +522,13 @@ void silc_server_notify(SilcServer server,
       memset(hash, 0, sizeof(hash));
     }
 
+    /* Get the passphrase */
+    tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
+    if (tmp) {
+      silc_free(channel->passphrase);
+      channel->passphrase = strdup(tmp);
+    }
+
     break;
 
   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
@@ -800,6 +809,15 @@ void silc_server_notify(SilcServer server,
                                     users_modes->len, FALSE);
        silc_buffer_free(users_modes);
       }
+
+      /* Re-announce channel's topic */
+      if (channel->topic) {
+       silc_server_send_notify_topic_set(server, sock,
+                                         server->server_type == SILC_ROUTER ?
+                                         TRUE : FALSE, channel, 
+                                         channel->id, SILC_ID_CHANNEL,
+                                         channel->topic);
+      }
     }
 
     silc_free(channel_id);
@@ -835,6 +853,7 @@ void silc_server_notify(SilcServer server,
        if (server->server_type != SILC_ROUTER &&
            silc_argument_get_arg_num(args) > 1) {
          int i;
+         bool local;
 
          for (i = 1; i < silc_argument_get_arg_num(args); i++) {
            /* Get Client ID */
@@ -848,9 +867,11 @@ void silc_server_notify(SilcServer server,
            /* Get client entry */
            client = silc_idlist_find_client_by_id(server->global_list, 
                                                   client_id, TRUE, &cache);
+           local = TRUE;
            if (!client) {
              client = silc_idlist_find_client_by_id(server->local_list, 
                                                     client_id, TRUE, &cache);
+             local = FALSE;
              if (!client) {
                silc_free(client_id);
                continue;
@@ -858,15 +879,20 @@ void silc_server_notify(SilcServer server,
            }
            silc_free(client_id);
 
-           /* Remove the client from all channels. */
-           silc_server_remove_from_channels(server, NULL, client, 
-                                            TRUE, NULL, FALSE);
-           
-           client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
-           cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+           /* Update statistics */
            server->stat.clients--;
            if (server->server_type == SILC_ROUTER)
              server->stat.cell_clients--;
+           SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+           SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
+           /* Remove the client from all channels. */
+           silc_server_remove_from_channels(server, NULL, client, 
+                                            TRUE, NULL, FALSE);
+
+           /* Remove the client */
+           silc_idlist_del_client(local ? server->local_list :
+                                  server->global_list, client);
          }
        }
 
@@ -1011,7 +1037,7 @@ void silc_server_notify(SilcServer server,
      */
 
     SILC_LOG_DEBUG(("UMODE_CHANGE notify"));
-      
+
     /* Get client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -1037,9 +1063,33 @@ void silc_server_notify(SilcServer server,
     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
     if (!tmp)
       goto out;
+    SILC_GET32_MSB(mode, tmp);
+
+#define SILC_UMODE_STATS_UPDATE(oper, mod)     \
+do {                                           \
+    if (client->mode & (mod)) {                        \
+      if (!(mode & (mod))) {                   \
+       if (client->connection)                 \
+         server->stat.my_ ## oper ## _ops--;   \
+        if (server->server_type == SILC_ROUTER)        \
+         server->stat. oper ## _ops--;         \
+      }                                                \
+    } else {                                   \
+      if (mode & (mod)) {                      \
+       if (client->connection)                 \
+         server->stat.my_ ## oper ## _ops++;   \
+        if (server->server_type == SILC_ROUTER)        \
+         server->stat. oper ## _ops++;         \
+      }                                                \
+    }                                          \
+} while(0)
+
+    /* Update statistics */
+    SILC_UMODE_STATS_UPDATE(server, SILC_UMODE_SERVER_OPERATOR);
+    SILC_UMODE_STATS_UPDATE(router, SILC_UMODE_ROUTER_OPERATOR);
 
     /* Save the mode */
-    SILC_GET32_MSB(client->mode, tmp);
+    client->mode = mode;
 
     break;
 
@@ -1107,7 +1157,6 @@ void silc_server_notify(SilcServer server,
        }
       }
     }
-
     break;
 
     /* Ignore rest of the notify types for now */
@@ -1206,9 +1255,22 @@ void silc_server_private_message(SilcServer server,
     if (!idp)
       return;
 
-    silc_server_send_command_reply(server, sock, SILC_COMMAND_IDENTIFY,
-                                  SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0, 1,
-                                  2, idp, idp->len);
+    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_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_buffer_free(idp);
     return;
   }
@@ -1290,7 +1352,7 @@ void silc_server_command_reply(SilcServer server,
 
   if (packet->dst_id_type == SILC_ID_SERVER) {
     /* For now this must be for us */
-    if (memcmp(packet->dst_id, server->id_string, packet->dst_id_len)) {
+    if (memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
       SILC_LOG_ERROR(("Cannot process command reply to unknown server"));
       return;
     }
@@ -1444,8 +1506,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   SilcClientID *client_id;
   SilcBuffer reply;
   SilcIDListData idata;
-  SilcIDCacheEntry id_cache = NULL;
   char *username = NULL, *realname = NULL, *id_string;
+  uint16 username_len;
   uint32 id_len;
   int ret;
   char *hostname, *nickname;
@@ -1470,14 +1532,13 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   /* Parse incoming packet */
   ret = silc_buffer_unformat(buffer,
-                            SILC_STR_UI16_STRING_ALLOC(&username),
+                            SILC_STR_UI16_NSTRING_ALLOC(&username, 
+                                                        &username_len),
                             SILC_STR_UI16_STRING_ALLOC(&realname),
                             SILC_STR_END);
   if (ret == -1) {
-    if (username)
-      silc_free(username);
-    if (realname)
-      silc_free(realname);
+    silc_free(username);
+    silc_free(realname);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                   "Incomplete client information");
     return NULL;
@@ -1485,17 +1546,22 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   if (!username) {
     silc_free(username);
-    if (realname)
-      silc_free(realname);
+    silc_free(realname);
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                   "Incomplete client information");
     return NULL;
   }
 
-  if (strlen(username) > 128)
-    username[127] = '\0';
+  if (username_len > 128)
+    username[128] = '\0';
 
-  nickname = strdup(username);
+  /* Check for bad characters for nickname, and modify the nickname if
+     it includes those. */
+  if (silc_server_name_bad_chars(username, username_len)) {
+    nickname = silc_server_name_modify_bad(username, username_len);
+  } else {
+    nickname = strdup(username);
+  }
 
   /* Make sanity checks for the hostname of the client. If the hostname
      is provided in the `username' check that it is the same than the
@@ -1514,8 +1580,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
        strcmp(sock->hostname, hostname)) {
       silc_free(username);
       silc_free(hostname);
-      if (realname)
-       silc_free(realname);
+      silc_free(realname);
       silc_server_disconnect_remote(server, sock, 
                                    "Server closed connection: "
                                    "Incomplete client information");
@@ -1532,18 +1597,15 @@ SilcClientEntry silc_server_new_client(SilcServer server,
        phostname && strcmp(phostname, hostname)) {
       silc_free(username);
       silc_free(hostname);
-      if (phostname)
-       silc_free(phostname);
-      if (realname)
-       silc_free(realname);
+      silc_free(phostname);
+      silc_free(realname);
       silc_server_disconnect_remote(server, sock, 
                                    "Server closed connection: "
                                    "Incomplete client information");
       return NULL;
     }
     
-    if (phostname)
-      silc_free(phostname);
+    silc_free(phostname);
   } else {
     /* The hostname is not present, add it. */
     char *newusername;
@@ -1598,7 +1660,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   /* Add the client again to the ID cache */
   silc_idcache_add(server->local_list->clients, client->nickname,
-                  client_id, client, FALSE);
+                  client_id, client, 0, NULL);
 
   /* Notify our router about new client on the SILC network */
   if (!server->standalone)
@@ -1646,10 +1708,14 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                             server->stat.my_servers,
                             server->stat.my_routers));
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
-                           ("%d server operators and %d router operators "
-                            "online",
-                            server->stat.my_server_ops,
-                            server->stat.my_router_ops));
+                           ("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",
@@ -1766,7 +1832,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   /* Add again the entry to the ID cache. */
   silc_idcache_add(local ? server->local_list->servers : 
                   server->global_list->servers, server_name, server_id, 
-                  new_server, FALSE);
+                  new_server, 0, NULL);
 
   /* Distribute the information about new server in the SILC network
      to our router. If we are normal server we won't send anything
@@ -1912,7 +1978,7 @@ static void silc_server_new_id_real(SilcServer server,
         global list. Cell wide information however is kept in the local
         list. */
       entry = silc_idlist_add_client(id_list, NULL, NULL, NULL, 
-                                    id, router, NULL);
+                                    id, router, NULL, 0);
       if (!entry) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
 
@@ -2151,7 +2217,7 @@ void silc_server_new_channel(SilcServer server,
                      sock->hostname));
     
       silc_idlist_add_channel(server->global_list, strdup(channel_name), 
-                             0, channel_id, sock->user_data, NULL, NULL);
+                             0, channel_id, sock->user_data, NULL, NULL, 0);
       server->stat.channels++;
     }
   } else {
@@ -2204,6 +2270,8 @@ void silc_server_new_channel(SilcServer server,
       channel->mode = silc_channel_get_mode(payload);
 
       /* Send the new channel key to the server */
+      id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+      id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
       chk = silc_channel_key_payload_encode(id_len, id,
                                            strlen(channel->channel_key->
                                                   cipher->name),
@@ -2236,7 +2304,8 @@ void silc_server_new_channel(SilcServer server,
        silc_server_send_notify_cmode(server, sock, FALSE, channel,
                                      channel->mode, server->id,
                                      SILC_ID_SERVER,
-                                     channel->cipher, channel->hmac_name);
+                                     channel->cipher, channel->hmac_name,
+                                     channel->passphrase);
       }
 
       /* Create new key for the channel and send it to the server and
@@ -2249,8 +2318,8 @@ void silc_server_new_channel(SilcServer server,
        /* Send to the channel */
        silc_server_send_channel_key(server, sock, channel, FALSE);
        id = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-       id_len = SILC_ID_CHANNEL_LEN;
-       
+       id_len = silc_id_get_len(channel->id, SILC_ID_CHANNEL);
+
        /* Send to the server */
        chk = silc_channel_key_payload_encode(id_len, id,
                                              strlen(channel->channel_key->