updates.
[silc.git] / apps / silcd / packet_receive.c
index 428c1f7f9f47d94744424e609a116e0537e6e5ff..080e9eb5c0afde9fa5985f46dfac2ec6b09232c5 100644 (file)
@@ -338,6 +338,11 @@ void silc_server_notify(SilcServer server,
     /* Remove the client from all channels. */
     silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, FALSE);
 
+    /* Check if anyone is watching this nickname */
+    if (server->server_type == SILC_ROUTER)
+      silc_server_check_watcher_list(server, client, NULL,
+                                    SILC_NOTIFY_TYPE_SIGNOFF);
+
     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
     cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
     break;
@@ -402,8 +407,9 @@ void silc_server_notify(SilcServer server,
     /* Get user's channel entry and check that topic set is allowed. */
     if (!silc_server_client_on_channel(client, channel, &chl))
       goto out;
-    if (chl->mode == SILC_CHANNEL_UMODE_NONE && 
-       channel->mode & SILC_CHANNEL_MODE_TOPIC) {
+    if (channel->mode & SILC_CHANNEL_MODE_TOPIC &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       SILC_LOG_DEBUG(("Topic change is not allowed"));
       goto out;
     }
@@ -455,10 +461,12 @@ void silc_server_notify(SilcServer server,
       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 = silc_idlist_replace_client_id(server,
+                                            server->global_list, client_id,
                                             client_id2, nickname);
       if (!client)
-       client = silc_idlist_replace_client_id(server->local_list, client_id, 
+       client = silc_idlist_replace_client_id(server,
+                                              server->local_list, client_id, 
                                               client_id2, nickname);
 
       if (client) {
@@ -583,8 +591,7 @@ void silc_server_notify(SilcServer server,
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
       silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
-                    channel->key_len / 8, 
-                    hash);
+                    channel->key_len / 8, hash);
       silc_hmac_set_key(channel->hmac, hash, 
                        silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
@@ -688,7 +695,8 @@ void silc_server_notify(SilcServer server,
        
        if (client != client2) {
          /* Sender must be operator */
-         if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+         if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+             !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
            SILC_LOG_DEBUG(("CUMODE change is not allowed"));
            goto out;
          }
@@ -828,8 +836,9 @@ void silc_server_notify(SilcServer server,
     /* Get user's channel entry and check that inviting is allowed. */
     if (!silc_server_client_on_channel(client, channel, &chl))
       goto out;
-    if (chl->mode == SILC_CHANNEL_UMODE_NONE && 
-       channel->mode & SILC_CHANNEL_MODE_INVITE) {
+    if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       SILC_LOG_DEBUG(("Inviting is not allowed"));
       goto out;
     }
@@ -1047,6 +1056,15 @@ void silc_server_notify(SilcServer server,
            silc_server_remove_from_channels(server, NULL, client, 
                                             TRUE, NULL, FALSE);
 
+           /* Check if anyone is watching this nickname */
+           if (server->server_type == SILC_ROUTER)
+             silc_server_check_watcher_list(server, client, NULL,
+                                            SILC_NOTIFY_TYPE_SERVER_SIGNOFF);
+
+           /* Remove this client from watcher list if it is */
+           if (local)
+             silc_server_del_from_watcher_list(server, client);
+
            /* Remove the client */
            silc_idlist_del_client(local ? server->local_list :
                                   server->global_list, client);
@@ -1148,7 +1166,8 @@ void silc_server_notify(SilcServer server,
       /* Kicker must be operator on channel */
       if (!silc_server_client_on_channel(client2, channel, &chl))
        goto out;
-      if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+      if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+         !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
        SILC_LOG_DEBUG(("Kicking is not allowed"));
        goto out;
       }
@@ -1249,6 +1268,11 @@ void silc_server_notify(SilcServer server,
       silc_server_remove_from_channels(server, NULL, client, FALSE, NULL, 
                                       FALSE);
 
+      /* Check if anyone is watching this nickname */
+      if (server->server_type == SILC_ROUTER)
+       silc_server_check_watcher_list(server, client, NULL,
+                                      SILC_NOTIFY_TYPE_KILLED);
+
       break;
     }
 
@@ -1299,6 +1323,11 @@ void silc_server_notify(SilcServer server,
     /* Change the mode */
     client->mode = mode;
 
+    /* Check if anyone is watching this nickname */
+    if (server->server_type == SILC_ROUTER)
+      silc_server_check_watcher_list(server, client, NULL,
+                                    SILC_NOTIFY_TYPE_UMODE_CHANGE);
+
     break;
 
   case SILC_NOTIFY_TYPE_BAN:
@@ -1736,7 +1765,9 @@ void silc_server_channel_message(SilcServer server,
 
     /* If channel is moderated check that client is allowed to send
        messages. */
-    if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chl->mode) {
+    if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && 
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       SILC_LOG_DEBUG(("Channel is silenced from normal users"));
       goto out;
     }
@@ -1832,8 +1863,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   /* Remove the old cache entry. */
   if (!silc_idcache_del_by_context(server->local_list->clients, client)) {
     SILC_LOG_INFO(("Unauthenticated client attempted to register to network"));
-    silc_server_disconnect_remote(server, sock, "Server closed connection: "
-                                  "You have not been authenticated");
+    silc_server_disconnect_remote(server, sock, 
+                                 SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
     return NULL;
   }
 
@@ -1848,8 +1879,9 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     silc_free(realname);
     SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
                    "connection", sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock, "Server closed connection: "
-                                  "Incomplete client information");
+    silc_server_disconnect_remote(server, sock, 
+                                 SILC_STATUS_ERR_INCOMPLETE_INFORMATION, 
+                                 NULL);
     return NULL;
   }
 
@@ -1858,8 +1890,9 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     silc_free(realname);
     SILC_LOG_ERROR(("Client %s (%s) did not send its username, closing "
                    "connection", sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock, "Server closed connection: "
-                                  "Incomplete client information");
+    silc_server_disconnect_remote(server, sock, 
+                                 SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                 NULL);
     return NULL;
   }
 
@@ -1894,8 +1927,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
       SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
                      "connection", sock->hostname, sock->ip));
       silc_server_disconnect_remote(server, sock, 
-                                   "Server closed connection: "
-                                   "Incomplete client information");
+                                   SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                   NULL);
       return NULL;
     }
     
@@ -1914,8 +1947,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
       SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
                      "connection", sock->hostname, sock->ip));
       silc_server_disconnect_remote(server, sock, 
-                                   "Server closed connection: "
-                                   "Incomplete client information");
+                                   SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                   NULL);
       return NULL;
     }
     
@@ -1963,7 +1996,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     nickfail++;
     if (nickfail > 9) {
       silc_server_disconnect_remote(server, sock, 
-                                   "Server closed connection: Bad nickname");
+                                   SILC_STATUS_ERR_BAD_NICKNAME, NULL);
       return NULL;
     }
     snprintf(&nickname[strlen(nickname) - 1], 1, "%d", nickfail);
@@ -1995,6 +2028,10 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   /* Send some nice info to the client */
   silc_server_send_connect_notifys(server, sock, client);
 
+  /* Check if anyone is watching this nickname */
+  if (server->server_type == SILC_ROUTER)
+    silc_server_check_watcher_list(server, client, NULL, 0);
+
   return client;
 }
 
@@ -2036,8 +2073,8 @@ SilcServerEntry silc_server_new_server(SilcServer server,
       SILC_LOG_INFO(("Unauthenticated %s attempted to register to "
                     "network", (sock->type == SILC_SOCKET_TYPE_SERVER ?
                                 "server" : "router")));
-      silc_server_disconnect_remote(server, sock, "Server closed connection: "
-                                   "You have not been authenticated");
+      silc_server_disconnect_remote(server, sock, 
+                                   SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
       return NULL;
     }
     local = FALSE;
@@ -2079,8 +2116,8 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   if (!silc_id_is_valid_server_id(server, server_id, sock)) {
     SILC_LOG_INFO(("Invalid server ID sent by %s (%s)",
                   sock->ip, sock->hostname));
-    silc_server_disconnect_remote(server, sock, "Server closed connection: "
-                                 "Your Server ID is not valid");
+    silc_server_disconnect_remote(server, sock, 
+                                 SILC_STATUS_ERR_BAD_SERVER_ID, NULL);
     silc_free(server_name);
     return NULL;
   }
@@ -2269,6 +2306,10 @@ static void silc_server_new_id_real(SilcServer server,
       if (sock->type == SILC_SOCKET_TYPE_SERVER)
        server->stat.cell_clients++;
       server->stat.clients++;
+
+      /* Check if anyone is watching this nickname */
+      if (server->server_type == SILC_ROUTER && id_list == server->local_list)
+       silc_server_check_watcher_list(server, entry, NULL, 0);
     }
     break;
 
@@ -2893,9 +2934,9 @@ SILC_SERVER_CMD_FUNC(resume_resolve)
   if (!reply || !silc_command_get_status(reply->payload, NULL, NULL)) {
     SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
                    "closing connection", sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock, 
-                                 "Server closed connection: "
-                                 "Incomplete resume information");
+    silc_server_disconnect_remote(server, sock,
+                                 SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                 "Resuming not possible");
     goto out;
   }
 
@@ -2909,9 +2950,9 @@ SILC_SERVER_CMD_FUNC(resume_resolve)
       if (!client) {
        SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
                        "closing connection", sock->hostname, sock->ip));
-       silc_server_disconnect_remote(server, sock, 
-                                     "Server closed connection: "
-                                     "Incomplete resume information");
+       silc_server_disconnect_remote(server, sock,
+                                     SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                     "Resuming not possible");
        goto out;
       }
     }
@@ -2919,9 +2960,9 @@ SILC_SERVER_CMD_FUNC(resume_resolve)
     if (!(client->mode & SILC_UMODE_DETACHED)) {
       SILC_LOG_ERROR(("Client %s (%s) tried to resume un-detached client, "
                      "closing connection", sock->hostname, sock->ip));
-      silc_server_disconnect_remote(server, sock, 
-                                   "Server closed connection: "
-                                   "Incomplete resume information");
+      silc_server_disconnect_remote(server, sock,
+                                   SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                   "Resuming not possible");
       goto out;
     }
   }
@@ -2981,8 +3022,9 @@ void silc_server_resume_client(SilcServer server,
     if (!client_id || auth_len < 128) {
       SILC_LOG_ERROR(("Client %s (%s) sent incomplete resume information, "
                      "closing connection", sock->hostname, sock->ip));
-      silc_server_disconnect_remote(server, sock, "Server closed connection: "
-                                   "Incomplete resume information");
+      silc_server_disconnect_remote(server, sock,
+                                   SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                   "Resuming not possible");
       return;
     }
 
@@ -3011,9 +3053,9 @@ void silc_server_resume_client(SilcServer server,
       } else {
        SILC_LOG_ERROR(("Client %s (%s) tried to resume unknown client, "
                        "closing connection", sock->hostname, sock->ip));
-       silc_server_disconnect_remote(server, sock, 
-                                     "Server closed connection: "
-                                     "Incomplete resume information");
+       silc_server_disconnect_remote(server, sock,
+                                     SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                     "Resuming not possible");
       }
       return;
     }
@@ -3042,9 +3084,9 @@ void silc_server_resume_client(SilcServer server,
       if (server->server_type == SILC_SERVER) {
        SILC_LOG_ERROR(("Client %s (%s) tried to resume un-detached client, "
                        "closing connection", sock->hostname, sock->ip));
-       silc_server_disconnect_remote(server, sock, 
-                                     "Server closed connection: "
-                                     "Incomplete resume information");
+       silc_server_disconnect_remote(server, sock,
+                                     SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                     "Resuming not possible");
        return;
       }
     }
@@ -3053,9 +3095,9 @@ void silc_server_resume_client(SilcServer server,
        resolve it first. */
     if (!detached_client->data.public_key) {
       if (server->standalone) {
-       silc_server_disconnect_remote(server, sock, 
-                                     "Server closed connection: "
-                                     "Incomplete resume information");
+       silc_server_disconnect_remote(server, sock,
+                                     SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                     "Resuming not possible");
       } else {
        /* We must retrieve the detached client's public key by sending
           GETKEY command. Reprocess this packet after receiving the key */
@@ -3088,9 +3130,9 @@ void silc_server_resume_client(SilcServer server,
                                             idata->public_key)) {
       /* We require that the connection and resuming authentication data
         must be using same key pair. */
-      silc_server_disconnect_remote(server, sock, 
-                                   "Server closed connection: "
-                                   "Incomplete resume information");
+      silc_server_disconnect_remote(server, sock,
+                                   SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                   "Resuming not possible");
       return;
     }
 
@@ -3102,8 +3144,9 @@ void silc_server_resume_client(SilcServer server,
                               SILC_ID_CLIENT)) {
       SILC_LOG_ERROR(("Client %s (%s) resume authentication failed, "
                      "closing connection", sock->hostname, sock->ip));
-      silc_server_disconnect_remote(server, sock, "Server closed connection: "
-                                   "Incomplete resume information");
+      silc_server_disconnect_remote(server, sock,
+                                   SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
+                                   "Resuming not possible");
       return;
     }
 
@@ -3161,8 +3204,7 @@ void silc_server_resume_client(SilcServer server,
        nickfail++;
        if (nickfail > 9) {
          silc_server_disconnect_remote(server, sock, 
-                                       "Server closed connection: "
-                                       "Bad nickname");
+                                       SILC_STATUS_ERR_BAD_NICKNAME, NULL);
          return;
        }
        snprintf(&client->nickname[strlen(client->nickname) - 1], 1,