updates.
[silc.git] / apps / silcd / packet_receive.c
index 38b2a86a5b5d2923f10c6854f0b5204f00aa33db..65ceb85dfb77001d369aa8439338658b2406b077 100644 (file)
@@ -39,8 +39,10 @@ void silc_server_notify(SilcServer server,
   SilcArgumentPayload args;
   SilcChannelID *channel_id, *channel_id2;
   SilcClientID *client_id, *client_id2;
+  SilcServerID *server_id;
   SilcChannelEntry channel;
   SilcClientEntry client;
+  SilcServerEntry server_entry;
   SilcChannelClientEntry chl;
   SilcIDCacheEntry cache;
   unsigned int mode;
@@ -611,6 +613,9 @@ void silc_server_notify(SilcServer server,
 
     SILC_LOG_DEBUG(("CHANNEL CHANGE"));
 
+    if (sock->type != SILC_SOCKET_TYPE_ROUTER)
+      break;
+
     /* Get the old Channel ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -644,19 +649,76 @@ void silc_server_notify(SilcServer server,
     if (!channel_id2)
       goto out;
 
+    SILC_LOG_DEBUG(("Old Channel ID id(%s)", 
+                   silc_id_render(channel_id, SILC_ID_CHANNEL)));
+    SILC_LOG_DEBUG(("New Channel ID id(%s)", 
+                   silc_id_render(channel_id2, SILC_ID_CHANNEL)));
+
     /* Replace the Channel ID */
     if (!silc_idlist_replace_channel_id(server->global_list, channel_id,
                                        channel_id2))
-      silc_idlist_replace_channel_id(server->local_list, channel_id,
-                                    channel_id2);
+      if (!silc_idlist_replace_channel_id(server->local_list, channel_id,
+                                         channel_id2)) {
+       silc_free(channel_id2);
+       channel_id2 = NULL;
+      }
+
+    if (channel_id2) {
+      SilcBuffer users = NULL;
+      
+      /* Re-announce our clients on the channel as the ID has changed now */
+      silc_server_announce_get_channel_users(server, channel, &users);
+      if (users) {
+       silc_buffer_push(users, users->data - users->head);
+       silc_server_packet_send(server, sock,
+                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                               users->data, users->len, FALSE);
+       silc_buffer_free(users);
+      }
+    }
 
     silc_free(channel_id);
-    silc_free(channel_id2);
 
     break;
 
   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
-    SILC_LOG_DEBUG(("SERVER SIGNOFF notify (not-impl XXX)"));
+    /* 
+     * Remove the server entry and all clients that this server owns.
+     */
+
+    SILC_LOG_DEBUG(("SERVER SIGNOFF notify"));
+
+    /* Get Server ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+    server_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!server_id)
+      goto out;
+
+    /* Get server entry */
+    server_entry = silc_idlist_find_server_by_id(server->global_list, 
+                                                server_id, NULL);
+    if (!server_entry) {
+      server_entry = silc_idlist_find_server_by_id(server->local_list, 
+                                                  server_id, NULL);
+      if (!server_entry) {
+       silc_free(server_id);
+       goto out;
+      }
+    }
+    silc_free(server_id);
+
+    /* Free all client entries that this server owns as they will
+       become invalid now as well. */
+    silc_server_remove_clients_by_server(server, server_entry, TRUE);
+
+    /* Remove the server entry */
+    if (!silc_idlist_del_server(server->global_list, server_entry))
+      silc_idlist_del_server(server->local_list, server_entry);
+
+    /* XXX update statistics */
+
     break;
 
   case SILC_NOTIFY_TYPE_KICKED:
@@ -1277,6 +1339,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   cache->id = (void *)client_id;
   cache->type = SILC_ID_CLIENT;
   cache->data = username;
+  cache->data_len = strlen(username);
   silc_idcache_sort_by_data(server->local_list->clients);
 
   /* Notify our router about new client on the SILC network */
@@ -1432,6 +1495,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   cache->id = (void *)server_id;
   cache->type = SILC_ID_SERVER;
   cache->data = server_name;
+  cache->data_len = strlen(server_name);
   silc_idcache_sort_by_data(server->local_list->servers);
 
   /* Distribute the information about new server in the SILC network
@@ -1654,6 +1718,7 @@ void silc_server_new_channel(SilcServer server,
   unsigned int name_len;
   unsigned char *id;
   unsigned int id_len;
+  unsigned int mode;
 
   SILC_LOG_DEBUG(("Processing New Channel"));
 
@@ -1738,6 +1803,10 @@ void silc_server_new_channel(SilcServer server,
       /* The channel exist by that name, check whether the ID's match.
         If they don't then we'll force the server to use the ID we have.
         We also create a new key for the channel. */
+      SilcBuffer users = NULL;
+
+      if (!channel->id)
+       channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
 
       if (SILC_ID_CHANNEL_COMPARE(channel_id, channel->id)) {
        /* They don't match, send CHANNEL_CHANGE notify to the server to
@@ -1749,6 +1818,17 @@ void silc_server_new_channel(SilcServer server,
                                               SILC_ID_CHANNEL_LEN);
       }
 
+      /* If the mode is different from what we have then enforce the
+        mode change. */
+      mode = silc_channel_get_mode(payload);
+      if (channel->mode != mode) {
+       SILC_LOG_DEBUG(("Forcing the server to change channel mode"));
+       silc_server_send_notify_cmode(server, sock, FALSE, channel,
+                                     channel->mode, server->id,
+                                     SILC_ID_SERVER, SILC_ID_SERVER_LEN,
+                                     channel->cipher, channel->hmac_name);
+      }
+
       /* Create new key for the channel and send it to the server and
         everybody else possibly on the channel. */
 
@@ -1757,6 +1837,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;
        
        /* Send to the server */
        chk = silc_channel_key_payload_encode(id_len, id,
@@ -1769,6 +1851,7 @@ void silc_server_new_channel(SilcServer server,
        silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
                                chk->data, chk->len, FALSE);
        silc_buffer_free(chk);
+       silc_free(id);
       }
 
       silc_free(channel_id);
@@ -1776,9 +1859,18 @@ void silc_server_new_channel(SilcServer server,
       /* Since the channel is coming from server and we also know about it
         then send the JOIN notify to the server so that it see's our
         users on the channel "joining" the channel. */
-      /* XXX TODO **/
+      silc_server_announce_get_channel_users(server, channel, &users);
+      if (users) {
+       silc_buffer_push(users, users->data - users->head);
+       silc_server_packet_send(server, sock,
+                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                               users->data, users->len, FALSE);
+       silc_buffer_free(users);
+      }
     }
   }
+
+  silc_channel_payload_free(payload);
 }
 
 /* Received New Channel List packet, list of New Channel List payloads inside