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
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
 ==============================
 
+ 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
@@ -15,9 +18,6 @@ TODO/bugs in Irssi SILC client
 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
@@ -30,6 +30,10 @@ TODO/bugs In SILC Client Library
 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
@@ -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).
 
- 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
 
 
index f9ebe71de3837d4d0de75bcb0461b7547dcc9547..274251b60940d075cabdab2da9a74b12fdec850f 100644 (file)
@@ -1,9 +1,30 @@
 
 @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: WHOIS <nickname>[@<hostname>] [<count>] */
+/* SYNTAX: WHOIS <nickname>[@<hostname>] [-details] [<count>] */
 /* 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_attrs.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;
 
-  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) {
+
   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
@@ -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;
+
   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;
+
   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;
+
   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;
+
   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
@@ -1094,6 +1108,7 @@ void silc_client_packet_parse_type(SilcClient client,
                      "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 ||
index 2073bc5a0db7e5d09eb8f75048b647bd63b50f95..6fbdbd4a54919cd6599c11f976a2fcba5b200684 100644 (file)
@@ -131,6 +131,9 @@ struct SilcClientConnectionStruct {
   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;
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;
-    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;
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,
-                                        silc_client_ftp_resolve_cb,
+                                        NULL, silc_client_ftp_resolve_cb,
                                         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);
+SilcBuffer silc_client_attributes_process(SilcClient client,
+                                         SilcSocketConnection sock,
+                                         SilcDList attrs);
 
 #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,
+                                      NULL,
                                       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;
-  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);
index 647790b552505ce485d55613ed299197870be9d5..dca5d000d1e93eb7843686fa18b5681a173806ef 100644 (file)
@@ -173,7 +173,7 @@ void silc_client_private_message(SilcClient client,
     }
 
     /* 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;
@@ -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,
+                                      NULL,
                                       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;
-  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);
@@ -234,13 +234,21 @@ SILC_CLIENT_CMD_FUNC(whois)
                                            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,
-                                           ++conn->cmd_ident, 2,
+                                           ++conn->cmd_ident, 3,
                                            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,
@@ -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");
 }
+
+/**** 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);
+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);
index 5772d41493df95e08f45791e0f42a8daaaa40f76..7277b8db9f287cbc4ebce1efc7fe67c80f4dce17 100644 (file)
@@ -241,13 +241,19 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
     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, 
-                  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
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,
+                                         SilcBuffer attributes,
                                          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,
-                          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 */
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 */
+  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
index 85a55b4be73d8d7ca64ed297e8d05b521e5a0f81..e301f1581d0c08d04fcac2f5be456ac0d935441a 100644 (file)
@@ -561,6 +561,15 @@ typedef struct {
      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;
 /***/
 
@@ -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,
+ *                                         SilcBuffer attributes,
  *                                         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.
  *
+ *    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,
+                                         SilcBuffer attributes,
                                          SilcGetClientCallback completion,
                                          void *context);
 
@@ -2181,6 +2199,103 @@ SilcClientFileError silc_client_file_close(SilcClient client,
                                           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"