Added support for watching by public keys.
authorPekka Riikonen <priikone@silcnet.org>
Mon, 23 Feb 2004 08:31:39 +0000 (08:31 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Mon, 23 Feb 2004 08:31:39 +0000 (08:31 +0000)
CHANGES
apps/silcd/command.c
apps/silcd/server.c
apps/silcd/server_internal.h
apps/silcd/server_util.c

diff --git a/CHANGES b/CHANGES
index 61a90f08e03995c7d00fdf717a5df3f925ddd2d6..81c054dc3de863b9b83ec9c0fb4cf5b414014511 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,9 @@
+Mon Feb 23 09:30:30 CET 2004  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added support for public key watching in server.  Affected
+         files are silcd/server.c, server_internal.h, command.c,
+         server_util.c.
+
 Sun Feb 22 19:03:59 EET 2004  Pekka Riikonen <priikone@silcnet.org>
 
        * Added public key to the SIlcClientEntry.  Affected files
index bb56e807b151ba4b0e7daf2feb1f300241db50f6..8adf8bf0195bff7884e9d8475dc8260a4648ebfd 100644 (file)
@@ -4007,9 +4007,9 @@ SILC_SERVER_CMD_FUNC(watch)
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
   char *add_nick, *del_nick;
-  SilcUInt32 add_nick_len, del_nick_len, tmp_len;
+  SilcUInt32 add_nick_len, del_nick_len, tmp_len, pk_len;
   char nick[128 + 1];
-  unsigned char hash[16], *tmp;
+  unsigned char hash[16], *tmp,  *pk;
   SilcClientEntry client;
   SilcClientID *client_id = NULL;
 
@@ -4081,10 +4081,13 @@ SILC_SERVER_CMD_FUNC(watch)
     goto out;
   }
 
+  /* Take public key for watching by public key */
+  pk = silc_argument_get_arg_type(cmd->args, 3, &pk_len);
+
   /* Take nickname */
   add_nick = silc_argument_get_arg_type(cmd->args, 2, &add_nick_len);
   del_nick = silc_argument_get_arg_type(cmd->args, 3, &del_nick_len);
-  if (!add_nick && !del_nick) {
+  if (!add_nick && !del_nick && !pk) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
                                          0);
@@ -4162,6 +4165,92 @@ SILC_SERVER_CMD_FUNC(watch)
       silc_free(tmp);
   }
 
+  /* Add/del public key */
+  if (pk) {
+    SilcUInt16 pkargc;
+    SilcArgumentPayload pkargs;
+    SilcUInt32 type;
+    SilcPublicKey public_key, pkkey;
+
+    if (pk_len < 2) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                           0);
+      goto out;
+    }
+
+    /* Get the argument from the Argument List Payload */
+    SILC_GET16_MSB(pkargc, pk);
+    pkargs = silc_argument_payload_parse(pk + 2, pk_len - 2, pkargc);
+    if (!pkargs) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                           0);
+      goto out;
+    }
+   
+    pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
+    while (pk) {
+      if (!silc_pkcs_public_key_payload_decode(pk, pk_len, &public_key))
+       continue;
+      if (type == 0x03)
+        type = 0x00;
+
+      if (type == 0x00) {
+       /* Add public key to watch list */
+
+       /* Check whether this client is already watching this public key */
+       if (silc_hash_table_find_by_context(server->watcher_list_pk,
+                                           public_key, client, NULL)) {
+         silc_pkcs_public_key_free(public_key);
+         silc_server_command_send_status_reply(
+                               cmd, SILC_COMMAND_WATCH,
+                               SILC_STATUS_ERR_NICKNAME_IN_USE, 0);
+         goto out;
+       }
+
+       /* Get the public key from the watcher list and use the same key in
+          new entries as well.  If key doesn't exist then create it. */
+       pkkey = NULL;
+       if (!silc_hash_table_find(server->watcher_list_pk, public_key,
+                                 (void *)&pkkey, NULL))
+         pkkey = public_key;
+       else
+         silc_pkcs_public_key_free(public_key);
+
+       /* Add the client to the watcher list with the specified public
+          key. */
+       silc_hash_table_add(server->watcher_list, public_key, client);
+
+      } else if (type == 0x01) {
+       /* Delete public key from watch list */
+
+       /* Check that this client is watching this public key */
+       if (silc_hash_table_find_by_context(server->watcher_list_pk,
+                                           public_key, client,
+                                           (void *)&pkkey)) {
+         silc_pkcs_public_key_free(public_key);
+         silc_server_command_send_status_reply(
+                               cmd, SILC_COMMAND_WATCH,
+                               SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+         goto out;
+       }
+
+       /* Delete the public key from the watcher list. */
+       silc_hash_table_del_by_context(server->watcher_list_pk,
+                                      public_key, client);
+
+       /* Now check whether there still exists entries with this key, if 
+          not then free the key to not leak memory. */
+       if (!silc_hash_table_find(server->watcher_list, hash, NULL, NULL))
+         silc_pkcs_public_key_free(pkkey);
+        silc_pkcs_public_key_free(public_key);
+      }
+
+      pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
+    }
+  }
+
   /* Distribute the watch list to backup routers too */
   if (server->backup) {
     SilcBuffer tmpbuf;
index afb0cb1f493366509002ee1c21d71501ebc62fb2..083206bc5df1d8f1eee6222fbe63457f109841b3 100644 (file)
@@ -180,6 +180,7 @@ void silc_server_free(SilcServer server)
   silc_idcache_free(server->global_list->servers);
   silc_idcache_free(server->global_list->channels);
   silc_hash_table_free(server->watcher_list);
+  silc_hash_table_free(server->watcher_list_pk);
 
   silc_hash_free(server->md5hash);
   silc_hash_free(server->sha1hash);
@@ -353,13 +354,19 @@ bool silc_server_init(SilcServer server)
   server->global_list->servers = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
   server->global_list->channels = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
 
-  /* Init watcher list */
+  /* Init watcher lists */
   server->watcher_list =
     silc_hash_table_alloc(1, silc_hash_client_id_hash, NULL,
                          silc_hash_data_compare, (void *)CLIENTID_HASH_LEN,
                          NULL, NULL, TRUE);
   if (!server->watcher_list)
     goto err;
+  server->watcher_list_pk =
+    silc_hash_table_alloc(1, silc_hash_public_key, NULL,
+                         silc_hash_public_key_compare, NULL,
+                         NULL, NULL, TRUE);
+  if (!server->watcher_list_pk)
+    goto err;
 
   /* Init public key list */
   server->pk_hash =
index 6c99d1fdba4814d552a3edc232ef6f26d0f1ba1f..6ee26c49d349a60dc8b681b45e5d67869d6658d6 100644 (file)
@@ -111,6 +111,7 @@ struct SilcServerStruct {
   SilcIDList local_list;
   SilcIDList global_list;
   SilcHashTable watcher_list;
+  SilcHashTable watcher_list_pk;
 
   /* Table of connected sockets */
   SilcSocketConnection *sockets;
index 8e545578717d506a75e693bd27aa12dc17e5c564..56791fab71edc47556413ba88afdda94ac410797 100644 (file)
@@ -1704,9 +1704,9 @@ silc_server_check_watcher_list_foreach(void *key, void *context,
   }
 }
 
-/* This function checks whether the `client' nickname is being watched
-   by someone, and notifies the watcher of the notify change of notify
-   type indicated by `notify'. */
+/* This function checks whether the `client' nickname and/or 'client' 
+   public key is being watched by someone, and notifies the watcher of the 
+   notify change of notify type indicated by `notify'. */
 
 bool silc_server_check_watcher_list(SilcServer server,
                                    SilcClientEntry client,
@@ -1739,10 +1739,17 @@ bool silc_server_check_watcher_list(SilcServer server,
   n.new_nick = new_nick;
   n.notify = notify;
 
-  /* Send notify to all watchers */
+  /* Send notify to all watchers watching this nickname */
   silc_hash_table_find_foreach(server->watcher_list, hash,
                               silc_server_check_watcher_list_foreach, &n);
 
+  /* Send notify to all watchers watching this public key */
+  if (client->data.public_key)
+    silc_hash_table_find_foreach(server->watcher_list_pk,
+                                client->data.public_key,
+                                silc_server_check_watcher_list_foreach, 
+                                &n);
+
   return TRUE;
 }