updates.
[silc.git] / apps / silcd / packet_receive.c
index 972e60be2e268adcd5812d043e3030ad7ff944ed..1a1be10d11fd3ceadf491f74c762d5ea2ac04cc3 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
@@ -69,11 +69,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 +332,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);
@@ -378,9 +379,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,6 +398,9 @@ 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;
@@ -426,6 +427,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"));
       
@@ -450,26 +453,24 @@ 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_id2, nickname);
       if (!client)
        client = silc_idlist_replace_client_id(server->local_list, client_id, 
-                                              client_id2);
+                                              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, NULL, client,
+                                           SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
+                                           id, tmp_len, id2, tmp_len,
+                                           nickname, nickname ?
+                                           nickname_len : 0);
       }
 
       silc_free(client_id);
@@ -595,7 +596,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;
@@ -1039,7 +1040,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);
@@ -1126,8 +1127,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);
@@ -1171,8 +1171,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"));
       
@@ -1207,16 +1207,42 @@ 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, NULL);
+       if (!client_id)
+         goto out;
+
+       /* 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 */
@@ -1414,6 +1440,7 @@ void silc_server_private_message(SilcServer server,
 {
   SilcSocketConnection dst_sock;
   SilcIDListData idata;
+  SilcClientEntry client;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1423,7 +1450,8 @@ 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 */
@@ -1441,11 +1469,11 @@ void silc_server_private_message(SilcServer server,
                                          client_id, SILC_ID_CLIENT,
                                          SILC_COMMAND_IDENTIFY,
                                          SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 
-                                         0, 1, 2, idp->data, idp->len);
+                                         0, 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, 
+                                    SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
                                     0, 1, 2, idp->data, idp->len);
     }
 
@@ -1453,6 +1481,13 @@ void silc_server_private_message(SilcServer server,
     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++,
@@ -1482,7 +1517,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;
 
@@ -1577,6 +1613,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"));
@@ -1615,11 +1652,24 @@ 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_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
@@ -1878,15 +1928,18 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                          ("Your host is %s, running version %s",
                           server->server_name, server_version));
-  if (server->server_type == SILC_ROUTER) {
+
+  if (server->stat.clients && server->stat.servers + 1)
     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));
+  if (server->stat.cell_clients && server->stat.cell_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));
+  if (server->server_type == SILC_ROUTER) {
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("I have %d clients, %d channels, %d servers and "
                             "%d routers",
@@ -1894,24 +1947,25 @@ SilcClientEntry silc_server_new_client(SilcServer server,
                             server->stat.my_channels,
                             server->stat.my_servers,
                             server->stat.my_routers));
+  } 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));
+  }
+
+  if (server->stat.server_ops || server->stat.router_ops)
     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));
+  if (server->stat.my_router_ops + server->stat.my_server_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",
@@ -2667,7 +2721,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;
 
@@ -2784,7 +2839,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;