updates.
[silc.git] / apps / silcd / packet_receive.c
index 88f08709a5619cd6b5ffda3cf0f59de2921eb473..a5c2493012bb6476f403860d20a85fdf4a4d40c2 100644 (file)
@@ -336,14 +336,36 @@ void silc_server_replace_id(SilcServer server,
   /* Replace the old ID */
   switch(old_id_type) {
   case SILC_ID_CLIENT:
-    SILC_LOG_DEBUG(("Old Client ID id(%s)", 
-                   silc_id_render(id, SILC_ID_CLIENT)));
-    SILC_LOG_DEBUG(("New Client ID id(%s)", 
-                   silc_id_render(id2, SILC_ID_CLIENT)));
-    if (silc_idlist_replace_client_id(server->local_list, id, id2) == NULL)
-      if (server->server_type == SILC_ROUTER)
-       silc_idlist_replace_client_id(server->global_list, id, id2);
-    break;
+    {
+      SilcBuffer nidp, oidp;
+      SilcClientEntry client = NULL;
+
+      SILC_LOG_DEBUG(("Old Client ID id(%s)", 
+                     silc_id_render(id, SILC_ID_CLIENT)));
+      SILC_LOG_DEBUG(("New Client ID id(%s)", 
+                     silc_id_render(id2, SILC_ID_CLIENT)));
+
+      if ((client = silc_idlist_replace_client_id(server->local_list, 
+                                                 id, id2)) == NULL)
+       if (server->server_type == SILC_ROUTER)
+         client = silc_idlist_replace_client_id(server->global_list, id, id2);
+      
+      if (client) {
+       oidp = silc_id_payload_encode(id, SILC_ID_CLIENT);
+       nidp = silc_id_payload_encode(id2, SILC_ID_CLIENT);
+
+       /* Send the NICK_CHANGE notify type to local clients on the channels
+          this client is joined to. */
+       silc_server_send_notify_on_channels(server, client, 
+                                           SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
+                                           oidp->data, oidp->len, 
+                                           nidp->data, nidp->len);
+       
+       silc_buffer_free(nidp);
+       silc_buffer_free(oidp);
+      }
+      break;
+    }
 
   case SILC_ID_SERVER:
     SILC_LOG_DEBUG(("Old Server ID id(%s)", 
@@ -455,11 +477,15 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                          ("Welcome to the SILC Network %s@%s",
                           username, sock->hostname));
+  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));
+                            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,
@@ -485,10 +511,6 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                            ("%d operators online",
                             server->stat.my_server_ops));
   }
-  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));
   SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                          ("Your connection is secured with %s cipher, "
                           "key length %d bits",
@@ -859,7 +881,7 @@ void silc_server_notify(SilcServer server,
   SilcNotifyType type;
   SilcArgumentPayload args;
   SilcChannelID *channel_id;
-  SilcClientID *client_id;
+  SilcClientID *client_id, *client_id2;
   SilcChannelEntry channel;
   SilcClientEntry client;
   unsigned char *tmp;
@@ -1013,8 +1035,10 @@ void silc_server_notify(SilcServer server,
     if (!client) {
       client = silc_idlist_find_client_by_id(server->local_list, 
                                             client_id, NULL);
-      if (!client)
+      if (!client) {
+       silc_free(client_id);
        goto out;
+      }
     }
     silc_free(client_id);
 
@@ -1025,12 +1049,76 @@ void silc_server_notify(SilcServer server,
     silc_idlist_del_client(server->global_list, client);
     break;
 
-    /* Ignore rest notify types for now */
-  case SILC_NOTIFY_TYPE_NONE:
-  case SILC_NOTIFY_TYPE_INVITE:
+  case SILC_NOTIFY_TYPE_NICK_CHANGE:
+    {
+      /* 
+       * Distribute the notify to local clients on the channel
+       */
+      unsigned char *id, *id2;
+
+      SILC_LOG_DEBUG(("NICK CHANGE notify"));
+      
+      /* Get old client ID */
+      id = silc_argument_get_arg_type(args, 1, &tmp_len);
+      if (!id)
+       goto out;
+      client_id = silc_id_payload_parse_id(id, tmp_len);
+      
+      /* Get new client ID */
+      id2 = silc_argument_get_arg_type(args, 2, &tmp_len);
+      if (!id2)
+       goto out;
+      client_id2 = silc_id_payload_parse_id(id2, tmp_len);
+      
+      SILC_LOG_DEBUG(("Old Client ID id(%s)", 
+                     silc_id_render(client_id, SILC_ID_CLIENT)));
+      SILC_LOG_DEBUG(("New Client ID id(%s)", 
+                     silc_id_render(client_id2, SILC_ID_CLIENT)));
+
+      /* Replace the Client ID */
+      client = silc_idlist_replace_client_id(server->global_list, client_id,
+                                            client_id2);
+      if (!client)
+       client = silc_idlist_replace_client_id(server->local_list, client_id, 
+                                              client_id2);
+
+      if (client)
+       /* Send the NICK_CHANGE notify type to local clients on the channels
+          this client is joined to. */
+       silc_server_send_notify_on_channels(server, client, 
+                                           SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
+                                           id, tmp_len, 
+                                           id2, tmp_len);
+
+      silc_free(client_id);
+      if (!client)
+       silc_free(client_id2);
+      break;
+    }
   case SILC_NOTIFY_TYPE_TOPIC_SET:
+    /* 
+     * Distribute the notify to local clients on the channel
+     */
+    SILC_LOG_DEBUG(("TOPIC SET notify (not-impl XXX)"));
+    break;
+
   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+    /* 
+     * Distribute the notify to local clients on the channel
+     */
+    SILC_LOG_DEBUG(("CMODE CHANGE notify (not-impl XXX)"));
+    break;
+
   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+    /* 
+     * Distribute the notify to local clients on the channel
+     */
+    SILC_LOG_DEBUG(("CUMODE CHANGE notify (not-impl XXX)"));
+    break;
+
+    /* Ignore rest notify types for now */
+  case SILC_NOTIFY_TYPE_NONE:
+  case SILC_NOTIFY_TYPE_INVITE:
   case SILC_NOTIFY_TYPE_MOTD:
   default:
     break;
@@ -1250,3 +1338,166 @@ void silc_server_remove_id(SilcServer server,
  out:
   silc_id_payload_free(idp);
 }
+
+/* Processes received SET_MODE packet. The packet is used to distribute
+   the information about changed channel's or client's channel modes. */
+
+void silc_server_set_mode(SilcServer server,
+                         SilcSocketConnection sock,
+                         SilcPacketContext *packet)
+{
+  SilcSetModePayload payload = NULL;
+  SilcArgumentPayload args = NULL;
+  unsigned short mode_type;
+  unsigned int mode_mask;
+  unsigned char *tmp, *tmp2;
+  unsigned int tmp_len, tmp_len2;
+  unsigned char mode[4];
+  SilcClientID *client_id;
+  SilcChannelID *channel_id = NULL;
+  SilcClientEntry client;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      packet->src_id_type == SILC_ID_CLIENT)
+    return;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* If we are router and this packet is not already broadcast packet
+     we will broadcast it. The sending socket really cannot be router or
+     the router is buggy. If this packet is coming from router then it must
+     have the broadcast flag set already and we won't do anything. */
+  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 Set Mode packet"));
+    silc_server_packet_send(server, server->router->connection, packet->type,
+                           packet->flags | SILC_PACKET_FLAG_BROADCAST, 
+                           packet->buffer->data, packet->buffer->len, FALSE);
+  }
+
+  /* Parse Set Mode payload */
+  payload = silc_set_mode_payload_parse(packet->buffer);
+  if (!payload)
+    return;
+
+  mode_type = silc_set_mode_get_type(payload);
+  args = silc_set_mode_get_args(payload);
+  if (!args)
+    goto out;
+
+  mode_mask = silc_set_mode_get_mode(payload);
+  SILC_PUT32_MSB(mode_mask, mode);
+
+  switch (mode_type) {
+  case SILC_MODE_TYPE_CHANNEL:
+    /* Get Channel ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!channel_id)
+      goto out;
+
+    /* Get channel entry */
+    channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                            channel_id, NULL);
+    if (!channel) {
+      channel = silc_idlist_find_channel_by_id(server->global_list, 
+                                              channel_id, NULL);
+      if (!channel)
+       goto out;
+    }
+
+    /* Get Client ID payload */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    /* Send CMODE_CHANGE notify to local channel */
+    silc_server_send_notify_to_channel(server, sock, channel, FALSE,
+                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 
+                                      2, tmp, tmp_len,
+                                      mode, sizeof(mode));
+
+    /* Change the mode */
+    channel->mode = mode_mask;
+    break;
+
+  case SILC_MODE_TYPE_UCHANNEL:
+    /* Get Channel ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+    if (!channel_id)
+      goto out;
+
+    /* Get channel entry */
+    channel = silc_idlist_find_channel_by_id(server->local_list, 
+                                            channel_id, NULL);
+    if (!channel) {
+      channel = silc_idlist_find_channel_by_id(server->global_list, 
+                                              channel_id, NULL);
+      if (!channel)
+       goto out;
+    }
+
+    /* Get Client ID payload */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    /* Get target Client ID */
+    tmp2 = silc_argument_get_arg_type(args, 3, &tmp_len2);
+    if (!tmp2)
+      goto out;
+    client_id = silc_id_payload_parse_id(tmp2, tmp_len2);
+    if (!client_id)
+      goto out;
+
+    /* Get target client entry */
+    client = silc_idlist_find_client_by_id(server->global_list, 
+                                          client_id, NULL);
+    if (!client) {
+      client = silc_idlist_find_client_by_id(server->local_list, 
+                                            client_id, NULL);
+      if (!client) {
+       silc_free(client_id);
+       goto out;
+      }
+    }
+    silc_free(client_id);
+
+    /* Send CUMODE_CHANGE notify to local channel */
+    silc_server_send_notify_to_channel(server, sock, channel, FALSE,
+                                      SILC_NOTIFY_TYPE_CUMODE_CHANGE, 2, 
+                                      tmp, tmp_len,
+                                      mode, sizeof(mode),
+                                      tmp2, tmp_len2);
+
+    /* Get entry to the channel user list */
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+      if (chl->client == client) {
+       /* Change the mode */
+       chl->mode = mode_mask;
+       break;
+      }
+
+    break;
+
+  default:
+    break;
+  }
+
+ out:
+  if (channel_id)
+    silc_free(channel_id);
+  if (args)
+    silc_argument_payload_free(args);
+  if (payload)
+    silc_set_mode_payload_free(payload);
+}