updates.
[silc.git] / apps / silcd / packet_receive.c
index f4d7e14f9816c9359a88444d080a54a4fe0d4ce6..9f1e4ccc2654c27786c2cde062f3b28716e479e7 100644 (file)
@@ -513,12 +513,38 @@ void silc_server_notify(SilcServer server,
 
     /* Get entry to the channel user list */
     silc_list_start(channel->user_list);
-    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      SilcChannelClientEntry chl2 = NULL;
+
+      /* If the mode is channel founder and we already find a client 
+        to have that mode on the channel we will enforce the sender
+        to change the channel founder mode away. There can be only one
+        channel founder on the channel. */
+      if (server->server_type == SILC_ROUTER &&
+         mode & SILC_CHANNEL_UMODE_CHANFO &&
+         chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+       silc_server_send_notify_cumode(server, sock, FALSE, channel,
+                                      (mode & (~SILC_CHANNEL_UMODE_CHANFO)),
+                                      server->id, SILC_ID_SERVER, 
+                                      SILC_ID_SERVER_LEN,
+                                      client->id, SILC_ID_CLIENT_LEN);
+       silc_free(channel_id);
+
+       /* Change the mode back if we changed it */
+       if (chl2)
+         chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+       goto out;
+      }
+
       if (chl->client == client) {
        /* Change the mode */
        chl->mode = mode;
-       break;
+       if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
+         break;
+
+       chl2 = chl;
       }
+    }
 
     /* Send the same notify to the channel */
     silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
@@ -658,10 +684,11 @@ void silc_server_notify(SilcServer server,
       }
 
     if (channel_id2) {
-      SilcBuffer users = NULL;
+      SilcBuffer users = NULL, users_modes = NULL;
       
       /* Re-announce our clients on the channel as the ID has changed now */
-      silc_server_announce_get_channel_users(server, channel, &users);
+      silc_server_announce_get_channel_users(server, channel, &users,
+                                            &users_modes);
       if (users) {
        silc_buffer_push(users, users->data - users->head);
        silc_server_packet_send(server, sock,
@@ -669,6 +696,13 @@ void silc_server_notify(SilcServer server,
                                users->data, users->len, FALSE);
        silc_buffer_free(users);
       }
+      if (users_modes) {
+       silc_buffer_push(users_modes, users_modes->data - users_modes->head);
+       silc_server_packet_send(server, sock,
+                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                               users_modes->data, users_modes->len, FALSE);
+       silc_buffer_free(users_modes);
+      }
     }
 
     silc_free(channel_id);
@@ -956,7 +990,7 @@ void silc_server_notify_list(SilcServer server,
   SilcBuffer buffer;
   uint16 len;
 
-  SILC_LOG_DEBUG(("Processing New Notify List"));
+  SILC_LOG_DEBUG(("Processing Notify List"));
 
   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
       packet->src_id_type != SILC_ID_SERVER)
@@ -1148,6 +1182,7 @@ void silc_server_channel_message(SilcServer server,
   SilcChannelClientEntry chl;
   SilcChannelID *id = NULL;
   void *sender = NULL;
+  void *sender_entry = NULL;
 
   SILC_LOG_DEBUG(("Processing channel message"));
 
@@ -1178,12 +1213,13 @@ void silc_server_channel_message(SilcServer server,
                          packet->src_id_type);
   if (!sender)
     goto out;
-  if (sock->type != SILC_SOCKET_TYPE_ROUTER && 
-      packet->src_id_type == SILC_ID_CLIENT) {
+  if (packet->src_id_type == SILC_ID_CLIENT) {
     silc_list_start(channel->user_list);
     while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
-      if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender))
+      if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender)) {
+       sender_entry = chl->client;
        break;
+      }
     }
     if (chl == SILC_LIST_END) {
       SILC_LOG_DEBUG(("Client not on channel"));
@@ -1191,11 +1227,10 @@ void silc_server_channel_message(SilcServer server,
     }
   }
 
-
   /* Distribute the packet to our local clients. This will send the
      packet for further routing as well, if needed. */
   silc_server_packet_relay_to_channel(server, sock, channel, sender,
-                                     packet->src_id_type,
+                                     packet->src_id_type, sender_entry,
                                      packet->buffer->data,
                                      packet->buffer->len, FALSE);
 
@@ -1536,8 +1571,25 @@ static void silc_server_new_id_real(SilcServer server,
   else
     id_list = server->global_list;
 
-  router_sock = sock;
-  router = sock->user_data;
+  /* If the packet is coming from server then use the sender as the
+     origin of the the packet. If it came from router then check the real
+     sender of the packet and use that as the origin. */
+  if (sock->type == SILC_SOCKET_TYPE_SERVER) {
+    router_sock = sock;
+    router = sock->user_data;
+  } else {
+    void *sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+                                    packet->src_id_type);
+    router = silc_idlist_find_server_by_id(server->global_list,
+                                          sender_id, NULL);
+    if (!router)
+      router = silc_idlist_find_server_by_id(server->local_list,
+                                            sender_id, NULL);
+    silc_free(sender_id);
+    if (!router)
+      goto out;
+    router_sock = sock;
+  }
 
   switch(id_type) {
   case SILC_ID_CLIENT:
@@ -1777,7 +1829,7 @@ 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;
+      SilcBuffer users = NULL, users_modes = NULL;
 
       if (!channel->id)
        channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
@@ -1833,7 +1885,8 @@ 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. */
-      silc_server_announce_get_channel_users(server, channel, &users);
+      silc_server_announce_get_channel_users(server, channel, &users,
+                                            &users_modes);
       if (users) {
        silc_buffer_push(users, users->data - users->head);
        silc_server_packet_send(server, sock,
@@ -1841,6 +1894,13 @@ void silc_server_new_channel(SilcServer server,
                                users->data, users->len, FALSE);
        silc_buffer_free(users);
       }
+      if (users_modes) {
+       silc_buffer_push(users_modes, users_modes->data - users_modes->head);
+       silc_server_packet_send(server, sock,
+                               SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                               users_modes->data, users_modes->len, FALSE);
+       silc_buffer_free(users_modes);
+      }
     }
   }