Added Requested Attributes sending and receiving support to
authorPekka Riikonen <priikone@silcnet.org>
Wed, 9 Oct 2002 19:02:38 +0000 (19:02 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 9 Oct 2002 19:02:38 +0000 (19:02 +0000)
client library.  Added requested attributes support to WHOIS
command (-details options).  Added silc_client_attribute[s]_*
functions.  Added attributes support to get_clients_by_id_resolve
function.

20 files changed:
CHANGES
TODO
apps/irssi/docs/help/in/whois.in
apps/irssi/src/silc/core/silc-servers.c
lib/silcclient/Makefile.am
lib/silcclient/client.c
lib/silcclient/client.h
lib/silcclient/client_attrs.c [new file with mode: 0644]
lib/silcclient/client_channel.c
lib/silcclient/client_ftp.c
lib/silcclient/client_internal.h
lib/silcclient/client_keyagr.c
lib/silcclient/client_notify.c
lib/silcclient/client_prvmsg.c
lib/silcclient/command.c
lib/silcclient/command.h
lib/silcclient/command_reply.c
lib/silcclient/idlist.c
lib/silcclient/idlist.h
lib/silcclient/silcclient.h

diff --git a/CHANGES b/CHANGES
index 81f21158a74367c411f2532e82fc7f4d5946a745..2f92996c09abf8e10dcc34bce2fd07dfa520c71d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,37 @@
+Wed Oct  9 17:22:57 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added silc_attribute_payload_encode_data to directly encode
+         the data into the attributes buffer.  Renamed function
+         silc_attribute_payload_parse_list to silc_attribute_payload_parse.
+         Affected files are lib/silccore/silcattrs.[ch].
+
+       * silc_hash_table_find_foreach calls the foreach function now
+         once even if the nothing was found with context set to NULL.
+         Affected file lib/silcutil/silchashtable.[ch].
+
+       * Remove the RESOLVING flag from client entry after received
+         the Requested Attributes from the client.  Fixed memory leak
+         in client entry freeing.  Affected files silcd/server_query.c
+         and idlist.c.
+
+       * Added Requested Attributes support into SILC Client Library.
+         It is not able to send requested attributes in WHOIS command,
+         and also receive and process requested attributes.  Added
+         silc_client_attribute_[add|del] and silc_client_attributes_get
+         functions.  Added also `ignore_requested_attributes' to the
+         SilcClientParams to not use attributes in client.  Affected
+         files are lib/silcclient/command.c, client_attrs.[ch],
+         silcclient.h, client_internal and client.[ch].
+
+       * Changed the silc_client_get_client_by_id to support Requested
+         Attributes, it takes them as argument now.  Affected file
+         is lib/silcclient/silcclient.h, and idlist.c.
+
+       * Added -details option to WHOIS command in Irssi SILC Client
+         to support the requested attributes.  By default it requests
+         all attributes.  Affected file lib/silcclient/command.c and
+         irssi/doc/help/in/whois.in.
+
 Tue Oct  8 17:58:28 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Add also SERVICE attribute for server-constructed attribute
 Tue Oct  8 17:58:28 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Add also SERVICE attribute for server-constructed attribute
diff --git a/TODO b/TODO
index 2559986ceb142383cf03f1c135dda24ee25cb75e..3bf55507473ee768281b0238de56f7d75e9c5317 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,9 @@
 TODO/bugs in Irssi SILC client
 ==============================
 
 TODO/bugs in Irssi SILC client
 ==============================
 
+ o Add support for the Requested Attributes in WHOIS (setting information
+   and displaying information).  Do /SET MY_* settings to set them.
+
  o Server password is not used at all.  It is not possible to automize
    the password authentication currently.  The silc_get_auth_method
    in irssi/src/silc/core/client_ops.c should find the connection's
  o Server password is not used at all.  It is not possible to automize
    the password authentication currently.  The silc_get_auth_method
    in irssi/src/silc/core/client_ops.c should find the connection's
@@ -15,9 +18,6 @@ TODO/bugs in Irssi SILC client
 TODO/bugs In SILC Client Library
 ================================
 
 TODO/bugs In SILC Client Library
 ================================
 
- o Add support for the <Requested Attributes> in WHOIS.  Sending and
-   reception should be added.
-
  o The PRIVATE_MESSAGE_KEY packet is not handled (it is implemented 
    though).  This should be added and perhaps new client operation
    should be added to notify application that it was received and
  o The PRIVATE_MESSAGE_KEY packet is not handled (it is implemented 
    though).  This should be added and perhaps new client operation
    should be added to notify application that it was received and
@@ -30,6 +30,10 @@ TODO/bugs In SILC Client Library
 TODO/bugs In SILC Server
 ========================
 
 TODO/bugs In SILC Server
 ========================
 
+ o If client's public key is saved in the server (and doing public key
+   authentication) then the hostname and the username information could
+   be taken from the public key.  Should be a configuration option!
+
  o Backup router related issues:
 
        o Add special handling in router and server for "connection
  o Backup router related issues:
 
        o Add special handling in router and server for "connection
@@ -44,10 +48,6 @@ TODO/bugs In SILC Server
    each JOIN command will create and distribute the new channel key
    to everybody on the channel (Fix this to 0.9.x).
 
    each JOIN command will create and distribute the new channel key
    to everybody on the channel (Fix this to 0.9.x).
 
- o If client's public key is saved in the server (and doing public key
-   authentication) then the hostname and the username information could
-   be taken from the public key.  Should be a configuration option!
-
  o Testing
 
 
  o Testing
 
 
index f9ebe71de3837d4d0de75bcb0461b7547dcc9547..274251b60940d075cabdab2da9a74b12fdec850f 100644 (file)
@@ -1,9 +1,30 @@
 
 @SYNTAX:whois@
 
 
 @SYNTAX:whois@
 
-Shows whois information of the specified client.
-By default, this is aliased to /WI.
+Shows WHOIS information of the specified client. By default,
+this is aliased to /WI. If the -details option is used WHOIS
+will retrieve as detailed information about the user as possible.
+Using this option WHOIS MAY return following information about
+the user:
 
 
-See also: WHOWAS, CHANNEL
+  o User's public key
+  o Business card of the user (VCard)
+  o List of network services user is currently using
+  o Text and/or multimedia message (MIME, image, etc)
+  o User's personal mood
+  o User's preferred language
+  o User's preferred contact method (chat, email, etc)
+  o User's timezone
+  o User's geographical location
+  o Information about the device user is using (computer, PDA, etc)
+
+It is also possible to receive other information. Note that all
+users do not want to send these informations or may send only
+some of the information. It also possible that none of these
+informations is received.
 
 
+If you want to send your information in WHOIS you can set the
+information with SET command. See /SET MY.
+
+See also: WHOWAS, CHANNEL
 
 
index 29cdca77bb13f449f2a765c6899dabfd4dca116d..731298dda13ce798865e1b5f7102466184df1f0b 100644 (file)
@@ -391,7 +391,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server)
 /* SYNTAX: SILCOPER <username> [-pubkey] */
 /* SYNTAX: TOPIC <channel> [<topic>] */
 /* SYNTAX: UMODE +|-<modes> */
 /* SYNTAX: SILCOPER <username> [-pubkey] */
 /* SYNTAX: TOPIC <channel> [<topic>] */
 /* SYNTAX: UMODE +|-<modes> */
-/* SYNTAX: WHOIS <nickname>[@<hostname>] [<count>] */
+/* SYNTAX: WHOIS <nickname>[@<hostname>] [-details] [<count>] */
 /* SYNTAX: WHOWAS <nickname>[@<hostname>] [<count>] */
 /* SYNTAX: CLOSE <server> [<port>] */
 /* SYNTAX: SHUTDOWN */
 /* SYNTAX: WHOWAS <nickname>[@<hostname>] [<count>] */
 /* SYNTAX: CLOSE <server> [<port>] */
 /* SYNTAX: SHUTDOWN */
index 68d9f9d7d5356d58e4f87e97b45423fc704f5dc1..6eda8de345cb5f3ea268931a2a7e07ebbd0d0319 100644 (file)
@@ -28,6 +28,7 @@ libsilcclient_a_SOURCES = \
        client_channel.c \
        client_ftp.c    \
        client_resume.c \
        client_channel.c \
        client_ftp.c    \
        client_resume.c \
+       client_attrs.c  \
        command.c \
        command_reply.c \
        idlist.c \
        command.c \
        command_reply.c \
        idlist.c \
index 0d238bfa4fb2cdaf87d11eda7f8b9b26760ef88e..45d81d04daa12f486a8d3b278c1b312bbb152db3 100644 (file)
@@ -960,13 +960,15 @@ void silc_client_packet_parse_type(SilcClient client,
   SilcBuffer buffer = packet->buffer;
   SilcPacketType type = packet->type;
 
   SilcBuffer buffer = packet->buffer;
   SilcPacketType type = packet->type;
 
-  SILC_LOG_DEBUG(("Parsing packet type %d", type));
+  SILC_LOG_DEBUG(("Parsing %s packet", silc_get_packet_name(type)));
 
   /* Parse the packet type */
   switch(type) {
 
   /* Parse the packet type */
   switch(type) {
+
   case SILC_PACKET_DISCONNECT:
     silc_client_disconnected_by_server(client, sock, buffer);
     break;
   case SILC_PACKET_DISCONNECT:
     silc_client_disconnected_by_server(client, sock, buffer);
     break;
+
   case SILC_PACKET_SUCCESS:
     /*
      * Success received for something. For now we can have only
   case SILC_PACKET_SUCCESS:
     /*
      * Success received for something. For now we can have only
@@ -976,6 +978,7 @@ void silc_client_packet_parse_type(SilcClient client,
     if (sock->protocol)
       silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
     break;
     if (sock->protocol)
       silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
     break;
+
   case SILC_PACKET_FAILURE:
     /*
      * Failure received for some protocol. Set the protocol state to 
   case SILC_PACKET_FAILURE:
     /*
      * Failure received for some protocol. Set the protocol state to 
@@ -984,6 +987,7 @@ void silc_client_packet_parse_type(SilcClient client,
      */
     silc_client_process_failure(client, sock, packet);
     break;
      */
     silc_client_process_failure(client, sock, packet);
     break;
+
   case SILC_PACKET_REJECT:
     break;
 
   case SILC_PACKET_REJECT:
     break;
 
@@ -1007,6 +1011,7 @@ void silc_client_packet_parse_type(SilcClient client,
      */
     silc_client_channel_message(client, sock, packet);
     break;
      */
     silc_client_channel_message(client, sock, packet);
     break;
+
   case SILC_PACKET_CHANNEL_KEY:
     /*
      * Received key for a channel. By receiving this key the client will be
   case SILC_PACKET_CHANNEL_KEY:
     /*
      * Received key for a channel. By receiving this key the client will be
@@ -1022,12 +1027,21 @@ void silc_client_packet_parse_type(SilcClient client,
      */
     silc_client_private_message(client, sock, packet);
     break;
      */
     silc_client_private_message(client, sock, packet);
     break;
+
   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
     /*
      * Received private message key
      */
     break;
 
   case SILC_PACKET_PRIVATE_MESSAGE_KEY:
     /*
      * Received private message key
      */
     break;
 
+  case SILC_PACKET_COMMAND:
+    /*
+     * Received command packet, a special case since normally client
+     * does not receive commands.
+     */
+    silc_client_command_process(client, sock, packet);
+    break;
+
   case SILC_PACKET_COMMAND_REPLY:
     /*
      * Recived reply for a command
   case SILC_PACKET_COMMAND_REPLY:
     /*
      * Recived reply for a command
@@ -1094,6 +1108,7 @@ void silc_client_packet_parse_type(SilcClient client,
                      "protocol active, packet dropped."));
     }
     break;
                      "protocol active, packet dropped."));
     }
     break;
+
   case SILC_PACKET_KEY_EXCHANGE_2:
     if (sock->protocol && sock->protocol->protocol && 
        (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
   case SILC_PACKET_KEY_EXCHANGE_2:
     if (sock->protocol && sock->protocol->protocol && 
        (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
index 2073bc5a0db7e5d09eb8f75048b647bd63b50f95..6fbdbd4a54919cd6599c11f976a2fcba5b200684 100644 (file)
@@ -131,6 +131,9 @@ struct SilcClientConnectionStruct {
   SilcUInt32 next_session_id;
   SilcClientFtpSession active_session;
 
   SilcUInt32 next_session_id;
   SilcClientFtpSession active_session;
 
+  /* Requested Attributes */
+  SilcHashTable attrs;
+
   /* Pointer back to the SilcClient. This object is passed to the application
      and the actual client object is accesible through this pointer. */
   SilcClient client;
   /* Pointer back to the SilcClient. This object is passed to the application
      and the actual client object is accesible through this pointer. */
   SilcClient client;
diff --git a/lib/silcclient/client_attrs.c b/lib/silcclient/client_attrs.c
new file mode 100644 (file)
index 0000000..5369310
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+
+  client_attrs.c 
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 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
+  the Free Software Foundation; version 2 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+*/
+/* $Id$ */
+
+#include "silcincludes.h"
+#include "silcclient.h"
+#include "client_internal.h"
+
+/* Add one attribute that was found from hash table */
+
+static void silc_client_attributes_process_foreach(void *key, void *context,
+                                                  void *user_context)
+{
+  SilcAttribute attribute = (SilcAttribute)(SilcUInt32)key;
+  SilcAttributePayload attr = context;
+  SilcBuffer buffer = user_context;
+  const unsigned char *data;
+  SilcUInt32 data_len;
+
+  if (!context) {
+    SILC_LOG_DEBUG(("Attribute %d was not set", attribute));
+
+    /* USER_PUBLIC_KEY we have set earlier */
+    if (attribute == SILC_ATTRIBUTE_USER_PUBLIC_KEY)
+      return;
+
+    /* The requested attribute was not found */
+    buffer = silc_attribute_payload_encode(buffer, attribute,
+                                          SILC_ATTRIBUTE_FLAG_INVALID,
+                                          NULL, 0);
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Attribute %d found", attribute));
+  data = silc_attribute_get_data(attr, &data_len);
+  buffer = silc_attribute_payload_encode_data(buffer, attribute,
+                                             SILC_ATTRIBUTE_FLAG_VALID,
+                                             data, data_len);
+}
+
+/* Process list of attributes.  Returns reply to the requested attributes. */
+
+SilcBuffer silc_client_attributes_process(SilcClient client,
+                                         SilcSocketConnection sock,
+                                         SilcDList attrs)
+{
+  SilcClientConnection conn = sock->user_data;
+  SilcBuffer buffer = NULL;
+  SilcAttribute attribute;
+  SilcAttributePayload attr;
+  SilcAttributeObjPk pk;
+  unsigned char sign[2048];
+  SilcUInt32 sign_len;
+
+  SILC_LOG_DEBUG(("Process Requested Attributes"));
+
+  /* If nothing is set by application assume that we don't want to use
+     attributes, ignore the request. */
+  if (!conn->attrs)
+    return NULL;
+
+  /* Always put our public key. */
+  pk.type = "silc-rsa";
+  pk.data = silc_pkcs_public_key_encode(client->public_key, &pk.data_len);
+  buffer = silc_attribute_payload_encode(buffer,
+                                        SILC_ATTRIBUTE_USER_PUBLIC_KEY,
+                                        pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
+                                        SILC_ATTRIBUTE_FLAG_INVALID,
+                                        &pk, sizeof(pk));
+  silc_free(pk.data);
+
+  /* Go through all requested attributes */
+  silc_dlist_start(attrs);
+  while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
+    /* Put all attributes of this type */
+    attribute = silc_attribute_get_attribute(attr);
+
+    /* Ignore signature since we will compute it later */
+    if (attribute == SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE)
+      continue;
+
+    silc_hash_table_find_foreach(conn->attrs, (void *)(SilcUInt32)attribute,
+                                silc_client_attributes_process_foreach,
+                                buffer);
+  }
+
+  /* Finally compute the digital signature of all the data we provided. */
+  if (silc_pkcs_sign_with_hash(client->pkcs, client->internal->sha1hash,
+                              buffer->data, buffer->len,
+                              sign, &sign_len)) {
+    pk.type = NULL;
+    pk.data = sign;
+    pk.data_len = sign_len;
+    buffer =
+      silc_attribute_payload_encode(buffer,
+                                   SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE,
+                                   SILC_ATTRIBUTE_FLAG_VALID,
+                                   &pk, sizeof(pk));
+  }
+
+  return buffer;
+}
+
+static void silc_client_attribute_destruct(void *key, void *context,
+                                          void *user_context)
+{
+  silc_attribute_payload_free(context);
+}
+
+/* Add new attribute */
+
+SilcAttributePayload silc_client_attribute_add(SilcClient client,
+                                              SilcClientConnection conn,
+                                              SilcAttribute attribute,
+                                              void *object,
+                                              SilcUInt32 object_size)
+{
+  SilcAttributePayload attr;
+
+  attr = silc_attribute_payload_alloc(attribute, SILC_ATTRIBUTE_FLAG_VALID,
+                                     object, object_size);
+  if (!attr)
+    return NULL;
+
+  if (!conn->attrs)
+    conn->attrs = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL,
+                                       NULL, silc_client_attribute_destruct,
+                                       NULL, TRUE);
+  silc_hash_table_add(conn->attrs, (void *)(SilcUInt32)attribute, attr);
+  return attr;
+}
+
+/* Delete one attribute */
+
+bool silc_client_attribute_del(SilcClient client,
+                              SilcClientConnection conn,
+                              SilcAttributePayload attr)
+{
+  SilcAttribute attribute = silc_attribute_get_attribute(attr);
+  bool ret;
+
+  ret = silc_hash_table_del_by_context(conn->attrs,
+                                      (void *)(SilcUInt32)attribute, attr);
+
+  if (ret)
+    if (!silc_hash_table_count(conn->attrs)) {
+      silc_hash_table_free(conn->attrs);
+      conn->attrs = NULL;
+    }
+
+  return ret;
+}
+
+/* Return all attributes */
+
+const SilcHashTable silc_client_attributes_get(SilcClient client,
+                                              SilcClientConnection conn)
+{
+  return (const SilcHashTable)conn->attrs;
+}
+
+/* Construct a Requested Attributes buffer. If the `attribute' is zero (0)
+   then all attributes are requested.  Additionally `attribute' and
+   all variable arguments can be one requested attribute.  Always set
+   the last requested attribute to zero (0) to complete list of
+   requested attribute. */
+
+SilcBuffer silc_client_attributes_request(SilcAttribute attribute, ...)
+{
+  va_list va;
+  SilcBuffer buffer = NULL;
+
+  if (!attribute)
+    return silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
+                                         SILC_ATTRIBUTE_SERVICE,
+                                         SILC_ATTRIBUTE_STATUS_MOOD,
+                                         SILC_ATTRIBUTE_STATUS_FREETEXT,
+                                         SILC_ATTRIBUTE_STATUS_MESSAGE,
+                                         SILC_ATTRIBUTE_PREFERRED_LANGUAGE,
+                                         SILC_ATTRIBUTE_PREFERRED_CONTACT,
+                                         SILC_ATTRIBUTE_TIMEZONE,
+                                         SILC_ATTRIBUTE_GEOLOCATION,
+                                         SILC_ATTRIBUTE_DEVICE_INFO,
+                                         SILC_ATTRIBUTE_USER_PUBLIC_KEY, 0);
+
+  va_start(va, attribute);
+  while (attribute) {
+    buffer = silc_attribute_payload_encode(buffer, attribute, 0, NULL, 0);
+    attribute = (SilcAttribute)va_arg(va, SilcUInt32);
+  }
+  va_end(va);
+
+  return buffer;
+}
index 2fc79ea33a61f941522dc7fd02f80c62a3cc49e3..6d38c42d02d96ed340279b952e0020af83c8a7be 100644 (file)
@@ -308,7 +308,7 @@ void silc_client_channel_message(SilcClient client,
     SilcChannelClientResolve res = silc_calloc(1, sizeof(*res));
     res->payload = payload;
     res->channel_id = id;
     SilcChannelClientResolve res = silc_calloc(1, sizeof(*res));
     res->payload = payload;
     res->channel_id = id;
-    silc_client_get_client_by_id_resolve(client, conn, client_id,
+    silc_client_get_client_by_id_resolve(client, conn, client_id, NULL,
                                         silc_client_channel_message_cb,
                                         res);
     payload = NULL;
                                         silc_client_channel_message_cb,
                                         res);
     payload = NULL;
index aed0f01cc60ed7d8b5123343c90a6bb4f4674015..c335121fd70dc93c7c7a72c35347867fae491c42 100644 (file)
@@ -1148,7 +1148,7 @@ void silc_client_ftp(SilcClient client,
 
     /* Resolve the client */
     silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
 
     /* Resolve the client */
     silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
-                                        silc_client_ftp_resolve_cb,
+                                        NULL, silc_client_ftp_resolve_cb,
                                         silc_packet_context_dup(packet));
     silc_free(remote_id);
   }
                                         silc_packet_context_dup(packet));
     silc_free(remote_id);
   }
index 7cc004991d1efd33bb89f16031f52654a6ef8669..d5e6fc781fffa5345f5de29a9d3509ca44fcfdf1 100644 (file)
@@ -218,5 +218,8 @@ void silc_client_resume_session(SilcClient client,
                                SilcClientConnection conn,
                                SilcClientResumeSessionCallback callback,
                                void *context);
                                SilcClientConnection conn,
                                SilcClientResumeSessionCallback callback,
                                void *context);
+SilcBuffer silc_client_attributes_process(SilcClient client,
+                                         SilcSocketConnection sock,
+                                         SilcDList attrs);
 
 #endif
 
 #endif
index b9c78550e264b78dfbc93fbafdd8e8a447e7ed6b..3e9efd5fd9375df0773e79db6d5f8002d9216abe 100644 (file)
@@ -733,6 +733,7 @@ void silc_client_key_agreement(SilcClient client,
     return;
 
   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
     return;
 
   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
+                                      NULL,
                                       silc_client_key_agreement_resolve_cb,
                                       silc_packet_context_dup(packet));
   silc_free(remote_id);
                                       silc_client_key_agreement_resolve_cb,
                                       silc_packet_context_dup(packet));
   silc_free(remote_id);
index 7258dc923fafab2517e462e258d80e0f46b62180..bd3edd3ff3f9638411756962e20637c7058c1cfc 100644 (file)
@@ -38,7 +38,8 @@ SILC_TASK_CALLBACK(silc_client_notify_check_client)
   SilcClient client = res->context;
   SilcClientConnection conn = res->sock->user_data;
   SilcClientID *client_id = res->packet;
   SilcClient client = res->context;
   SilcClientConnection conn = res->sock->user_data;
   SilcClientID *client_id = res->packet;
-  silc_client_get_client_by_id_resolve(client, conn, client_id, NULL, NULL);
+  silc_client_get_client_by_id_resolve(client, conn, client_id,
+                                      NULL, NULL, NULL);
   silc_free(client_id);
   silc_socket_free(res->sock);
   silc_free(res);
   silc_free(client_id);
   silc_socket_free(res->sock);
   silc_free(res);
index 647790b552505ce485d55613ed299197870be9d5..dca5d000d1e93eb7843686fa18b5681a173806ef 100644 (file)
@@ -173,7 +173,7 @@ void silc_client_private_message(SilcClient client,
     }
 
     /* Resolve the client info */
     }
 
     /* Resolve the client info */
-    silc_client_get_client_by_id_resolve(client, conn, remote_id,
+    silc_client_get_client_by_id_resolve(client, conn, remote_id, NULL,
                                         silc_client_private_message_cb,
                                         silc_packet_context_dup(packet));
     return;
                                         silc_client_private_message_cb,
                                         silc_packet_context_dup(packet));
     return;
@@ -287,6 +287,7 @@ void silc_client_private_message_key(SilcClient client,
     return;
 
   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
     return;
 
   silc_client_get_client_by_id_resolve(client, sock->user_data, remote_id,
+                                      NULL,
                                       silc_client_private_message_key_cb,
                                       silc_packet_context_dup(packet));
   silc_free(remote_id);
                                       silc_client_private_message_key_cb,
                                       silc_packet_context_dup(packet));
   silc_free(remote_id);
index 4a4b74ffed7752a572764b6b8ffceb63308c18d4..83e6bb69c77debbac2ce804e9e31f383403be579 100644 (file)
@@ -209,8 +209,8 @@ SILC_CLIENT_CMD_FUNC(whois)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
-  SilcBuffer buffer;
-  unsigned char count[4];
+  SilcBuffer buffer, attrs = NULL;
+  unsigned char count[4], *tmp = NULL;
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
 
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
@@ -234,13 +234,21 @@ SILC_CLIENT_CMD_FUNC(whois)
                                            1, cmd->argv[1], 
                                            cmd->argv_lens[1]);
   } else {
                                            1, cmd->argv[1], 
                                            cmd->argv_lens[1]);
   } else {
-    int c = atoi(cmd->argv[2]);
-    memset(count, 0, sizeof(count));
-    SILC_PUT32_MSB(c, count);
+    if (!strcasecmp(cmd->argv[2], "-details"))
+      attrs = silc_client_attributes_request(0);
+
+    if (!attrs || cmd->argc > 3) {
+      int c = atoi(cmd->argc > 3 ? cmd->argv[3] : cmd->argv[2]);
+      SILC_PUT32_MSB(c, count);
+      tmp = count;
+    }
+
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
-                                           ++conn->cmd_ident, 2,
+                                           ++conn->cmd_ident, 3,
                                            1, cmd->argv[1], cmd->argv_lens[1],
                                            1, cmd->argv[1], cmd->argv_lens[1],
-                                           2, count, sizeof(count));
+                                           2, tmp ? tmp : NULL, tmp ? 4 : 0,
+                                           3, attrs ? attrs->data : NULL,
+                                           attrs ? attrs->len : 0);
   }
   silc_client_packet_send(cmd->client, cmd->conn->sock,
                          SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
   }
   silc_client_packet_send(cmd->client, cmd->conn->sock,
                          SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
@@ -2522,3 +2530,97 @@ void silc_client_commands_unregister(SilcClient client)
   SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
   SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
 }
   SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
   SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
 }
+
+/**** Client side incoming command handling **********************************/
+
+void silc_client_command_process_whois(SilcClient client,
+                                      SilcSocketConnection sock,
+                                      SilcCommandPayload payload,
+                                      SilcArgumentPayload args);
+
+/* Client is able to receive some command packets even though they are
+   special case.  Server may send WHOIS command to the client to retrieve
+   Requested Attributes information for WHOIS query the server is
+   processing. This function currently handles only the WHOIS command,
+   but if in the future for commands may arrive then this can be made
+   to support other commands too. */
+
+void silc_client_command_process(SilcClient client,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet)
+{
+  SilcCommandPayload payload;
+  SilcCommand command;
+  SilcArgumentPayload args;
+
+  /* Get command payload from packet */
+  payload = silc_command_payload_parse(packet->buffer->data,
+                                      packet->buffer->len);
+  if (!payload) {
+    /* Silently ignore bad reply packet */
+    SILC_LOG_DEBUG(("Bad command packet"));
+    return;
+  }
+
+  /* Get arguments */
+  args = silc_command_get_args(payload);
+  
+  /* Get the command */
+  command = silc_command_get(payload);
+  switch (command) {
+
+  case SILC_COMMAND_WHOIS:
+    /* Ignore everything if requested by application */
+    if (client->internal->params->ignore_requested_attributes)
+      break;
+
+    silc_client_command_process_whois(client, sock, payload, args);
+    break;
+
+  default:
+    break;
+  }
+
+  silc_command_payload_free(payload);
+}
+
+void silc_client_command_process_whois(SilcClient client,
+                                      SilcSocketConnection sock,
+                                      SilcCommandPayload payload,
+                                      SilcArgumentPayload args)
+{
+  SilcDList attrs;
+  unsigned char *tmp;
+  SilcUInt32 tmp_len;
+  SilcBuffer buffer, packet;
+
+  SILC_LOG_DEBUG(("Received WHOIS command"));
+
+  /* Try to take the Requested Attributes */
+  tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+  if (!tmp)
+    return;
+
+  attrs = silc_attribute_payload_parse(tmp, tmp_len);
+  if (!attrs)
+    return;
+
+  /* Process requested attributes */
+  buffer = silc_client_attributes_process(client, sock, attrs);
+  if (!buffer) {
+    silc_attribute_payload_list_free(attrs);
+    return;
+  }
+
+  /* Send the attributes back */
+  packet =
+    silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+                                        SILC_STATUS_OK, 0,
+                                        silc_command_get_ident(payload),
+                                        1, 11, buffer->data, buffer->len);
+  silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
+                         NULL, 0, NULL, NULL, packet->data, 
+                         packet->len, TRUE);
+  silc_buffer_free(packet);
+  silc_buffer_free(buffer);
+}
index b85d2e05a18399c4bb3fdf6ede4ed556c32e0f94..84663109522fed1265ec71443b0f3325fcdc0e97 100644 (file)
@@ -120,6 +120,9 @@ silc_client_command_pending_check(SilcClientConnection conn,
                                  SilcCommand command, 
                                  SilcUInt16 ident,
                                  SilcUInt32 *callbacks_count);
                                  SilcCommand command, 
                                  SilcUInt16 ident,
                                  SilcUInt32 *callbacks_count);
+void silc_client_command_process(SilcClient client,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet);
 SILC_CLIENT_CMD_FUNC(whois);
 SILC_CLIENT_CMD_FUNC(whowas);
 SILC_CLIENT_CMD_FUNC(identify);
 SILC_CLIENT_CMD_FUNC(whois);
 SILC_CLIENT_CMD_FUNC(whowas);
 SILC_CLIENT_CMD_FUNC(identify);
index 5772d41493df95e08f45791e0f42a8daaaa40f76..7277b8db9f287cbc4ebce1efc7fe67c80f4dce17 100644 (file)
@@ -241,13 +241,19 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
     client_entry->fingerprint_len = fingerprint_len;
   }
 
     client_entry->fingerprint_len = fingerprint_len;
   }
 
+  /* Take Requested Attributes if set. */
+  tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
+  if (tmp)
+    client_entry->attrs = silc_attribute_payload_parse(tmp, len);
+
   client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
 
   /* Notify application */
   if (!cmd->callbacks_count && notify)
     COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, 
                   has_channels ? &channels : NULL, mode, idle, 
   client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
 
   /* Notify application */
   if (!cmd->callbacks_count && notify)
     COMMAND_REPLY((ARGS, client_entry, nickname, username, realname, 
                   has_channels ? &channels : NULL, mode, idle, 
-                  fingerprint, has_user_modes ? &ch_user_modes : NULL));
+                  fingerprint, has_user_modes ? &ch_user_modes : NULL,
+                  client_entry->attrs));
 }
 
 /* Received reply for WHOIS command. This maybe called several times
 }
 
 /* Received reply for WHOIS command. This maybe called several times
index 92b1dc37c5a354e07811583e941d76d6b8c79002..82a2e05120b6b4c654c4347827b06a5f66986895 100644 (file)
@@ -547,6 +547,7 @@ SILC_CLIENT_CMD_FUNC(get_client_by_id_callback)
 void silc_client_get_client_by_id_resolve(SilcClient client,
                                          SilcClientConnection conn,
                                          SilcClientID *client_id,
 void silc_client_get_client_by_id_resolve(SilcClient client,
                                          SilcClientConnection conn,
                                          SilcClientID *client_id,
+                                         SilcBuffer attributes,
                                          SilcGetClientCallback completion,
                                          void *context)
 {
                                          SilcGetClientCallback completion,
                                          void *context)
 {
@@ -569,7 +570,9 @@ void silc_client_get_client_by_id_resolve(SilcClient client,
   /* Send the command */
   idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
   silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
   /* Send the command */
   idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
   silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
-                          1, 4, idp->data, idp->len);
+                          2, 3, attributes ? attributes->data : NULL,
+                          attributes ? attributes->len : 0,
+                          4, idp->data, idp->len);
   silc_buffer_free(idp);
 
   /* Add pending callback */
   silc_buffer_free(idp);
 
   /* Add pending callback */
index 7d9a89ec43a6245976034af7e47d60debb064d99..f6357b49900c5fe58804d4346c9941d8edcef40e 100644 (file)
@@ -43,6 +43,7 @@ struct SilcClientEntryStruct {
   SilcCipher send_key;         /* Private message key for sending */
   SilcCipher receive_key;      /* Private message key for receiving */
   SilcClientKeyAgreement ke;   /* Current key agreement context or NULL */
   SilcCipher send_key;         /* Private message key for sending */
   SilcCipher receive_key;      /* Private message key for receiving */
   SilcClientKeyAgreement ke;   /* Current key agreement context or NULL */
+  SilcDList attrs;             /* Requested Attributes (maybe NULL) */
   SilcEntryStatus status;      /* Status mask */
   SilcHashTable channels;      /* All channels client has joined */
   unsigned char *key;          /* Set only if appliation provided the
   SilcEntryStatus status;      /* Status mask */
   SilcHashTable channels;      /* All channels client has joined */
   unsigned char *key;          /* Set only if appliation provided the
index 85a55b4be73d8d7ca64ed297e8d05b521e5a0f81..e301f1581d0c08d04fcac2f5be456ac0d935441a 100644 (file)
@@ -561,6 +561,15 @@ typedef struct {
      nickname string whenever it needs the true nickname. */
   SilcNicknameFormatParse nickname_parse;
 
      nickname string whenever it needs the true nickname. */
   SilcNicknameFormatParse nickname_parse;
 
+  /* If this is set to TRUE then the client will ignore all incoming
+     Requested Attributes queries and does not reply anything back.  This
+     usually leads into situation where server does not anymore send
+     the queries after seeing that client does not reply anything back.
+     If your application does not support Requested Attributes or you do
+     not want to use them set this to TRUE.  See SilcAttribute and
+     silc_client_attribute_add for more information on attributes. */
+  bool ignore_requested_attributes;
+
 } SilcClientParams;
 /***/
 
 } SilcClientParams;
 /***/
 
@@ -1069,6 +1078,7 @@ SilcClientEntry silc_client_get_client_by_id(SilcClient client,
  *    silc_client_get_client_by_id_resolve(SilcClient client,
  *                                         SilcClientConnection conn,
  *                                         SilcClientID *client_id,
  *    silc_client_get_client_by_id_resolve(SilcClient client,
  *                                         SilcClientConnection conn,
  *                                         SilcClientID *client_id,
+ *                                         SilcBuffer attributes,
  *                                         SilcGetClientCallback completion,
  *                                         void *context);
  *
  *                                         SilcGetClientCallback completion,
  *                                         void *context);
  *
@@ -1080,10 +1090,18 @@ SilcClientEntry silc_client_get_client_by_id(SilcClient client,
  *    is its ID. When server returns the client information it will be
  *    cache and can be accessed locally at a later time.
  *
  *    is its ID. When server returns the client information it will be
  *    cache and can be accessed locally at a later time.
  *
+ *    If the `attributes' is non-NULL then the buffer includes Requested
+ *    Attributes which can be used to fetch very detailed information
+ *    about the user. If it is NULL then only normal WHOIS query is
+ *    made (for more information about attributes see SilcAttribute).
+ *    Caller may create the `attributes' with silc_client_attributes_request
+ *    function.
+ *
  ***/
 void silc_client_get_client_by_id_resolve(SilcClient client,
                                          SilcClientConnection conn,
                                          SilcClientID *client_id,
  ***/
 void silc_client_get_client_by_id_resolve(SilcClient client,
                                          SilcClientConnection conn,
                                          SilcClientID *client_id,
+                                         SilcBuffer attributes,
                                          SilcGetClientCallback completion,
                                          void *context);
 
                                          SilcGetClientCallback completion,
                                          void *context);
 
@@ -2181,6 +2199,103 @@ SilcClientFileError silc_client_file_close(SilcClient client,
                                           SilcClientConnection conn,
                                           SilcUInt32 session_id);
 
                                           SilcClientConnection conn,
                                           SilcUInt32 session_id);
 
+/****f* silcclient/SilcClientAPI/silc_client_attribute_add
+ *
+ * SYNOPSIS
+ *
+ *    SilcAttributePayload
+ *    silc_client_attribute_add(SilcClient client,
+ *                              SilcClientConnection conn,
+ *                              SilcAttribute attribute,
+ *                              void *object,
+ *                              SilcUInt32 object_size);
+ *
+ * DESCRIPTION
+ *
+ *    Add new Requsted Attribute for WHOIS command to the client library.
+ *    The `attribute' object indicated by `object' is added and allocated
+ *    SilcAttributePayload is returned.  The `object' must be of correct
+ *    type and of correct size.  See the SilcAttribute for object types
+ *    for different attributes.  You may also get all added attributes
+ *    from the client with silc_client_attributes_get function.
+ *
+ *    Requested Attributes are different personal information about the
+ *    user, status information and other information which other users
+ *    may query with WHOIS command.  Application may set these so that
+ *    if someone sends WHOIS query these attributes will be replied back
+ *    to the sender.  The library always puts the public key to the
+ *    Requested Attributes, but if application wishes to add additional
+ *    public keys (or certificates) it can be done with this interface.
+ *    Library also always computes digital signature of the attributes
+ *    automatically, so application does not need to do that.
+ *
+ ***/
+SilcAttributePayload silc_client_attribute_add(SilcClient client,
+                                              SilcClientConnection conn,
+                                              SilcAttribute attribute,
+                                              void *object,
+                                              SilcUInt32 object_size);
+
+/****f* silcclient/SilcClientAPI/silc_client_attribute_del
+ *
+ * SYNOPSIS
+ *
+ *    bool silc_client_attribute_del(SilcClient client,
+ *                                   SilcClientConnection conn,
+ *                                   SilcAttributePayload attr);
+ *
+ * DESCRIPTION
+ *
+ *    Delete the Requested Attribute indicated by `attribute' from the
+ *    client.  You may get all added attributes with the function
+ *    silc_client_attributes_get.  Returns TRUE if the attribute was
+ *    found and deleted.
+ *
+ ***/
+bool silc_client_attribute_del(SilcClient client,
+                              SilcClientConnection conn,
+                              SilcAttributePayload attr);
+
+/****f* silcclient/SilcClientAPI/silc_client_attributes_get
+ *
+ * SYNOPSIS
+ *
+ *    const SilcHashTable
+ *    silc_client_attributes_get(SilcClient client,
+ *                               SilcClientConnection conn);
+ *
+ * DESCRIPTION
+ *
+ *    Returns pointer to the SilcHashTable which includes all the added
+ *    Requested Attributes.  The caller must not free the hash table.
+ *    The caller may use SilcHashTableList and silc_hash_table_list to
+ *    traverse the table.  Each entry in the hash table is one added
+ *    SilcAttributePayload.  It is possible to delete a attribute
+ *    payload while traversing the table.
+ *
+ ***/
+const SilcHashTable silc_client_attributes_get(SilcClient client,
+                                              SilcClientConnection conn);
+
+/****f* silcclient/SilcClientAPI/silc_client_attributes_request
+ *
+ * SYNOPSIS
+ *
+ *    SilcBuffer silc_client_attributes_request(SilcAttribute attribute, ...);
+ *
+ * DESCRIPTION
+ *
+ *    Constructs a Requested Attributes buffer. If the `attribute' is zero (0)
+ *    then all attributes are requested.  Alternatively, `attribute' and
+ *    all variable arguments can each be requested attribute.  In this case
+ *    the last must be set to zero (0) to complete the variable list of
+ *    requested attributes.  See SilcAttribute for all attributes.
+ *    You can give the returned buffer as argument to for example
+ *    silc_client_get_client_by_id_resolve function.
+ *
+ ***/
+SilcBuffer silc_client_attributes_request(SilcAttribute attribute, ...);
+
 #include "client.h"
 #include "command.h"
 #include "command_reply.h"
 #include "client.h"
 #include "command.h"
 #include "command_reply.h"