From 5d90b0684f07a8a51d5dff5cd108a328ec82ffa9 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Wed, 9 Oct 2002 19:02:38 +0000 Subject: [PATCH] Added Requested Attributes sending and receiving support to 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. --- CHANGES | 34 ++++ TODO | 14 +- apps/irssi/docs/help/in/whois.in | 27 ++- apps/irssi/src/silc/core/silc-servers.c | 2 +- lib/silcclient/Makefile.am | 1 + lib/silcclient/client.c | 17 +- lib/silcclient/client.h | 3 + lib/silcclient/client_attrs.c | 210 ++++++++++++++++++++++++ lib/silcclient/client_channel.c | 2 +- lib/silcclient/client_ftp.c | 2 +- lib/silcclient/client_internal.h | 3 + lib/silcclient/client_keyagr.c | 1 + lib/silcclient/client_notify.c | 3 +- lib/silcclient/client_prvmsg.c | 3 +- lib/silcclient/command.c | 116 ++++++++++++- lib/silcclient/command.h | 3 + lib/silcclient/command_reply.c | 8 +- lib/silcclient/idlist.c | 5 +- lib/silcclient/idlist.h | 1 + lib/silcclient/silcclient.h | 115 +++++++++++++ 20 files changed, 545 insertions(+), 25 deletions(-) create mode 100644 lib/silcclient/client_attrs.c diff --git a/CHANGES b/CHANGES index 81f21158..2f92996c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,37 @@ +Wed Oct 9 17:22:57 EEST 2002 Pekka Riikonen + + * 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 * Add also SERVICE attribute for server-constructed attribute diff --git a/TODO b/TODO index 2559986c..3bf55507 100644 --- 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 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 diff --git a/apps/irssi/docs/help/in/whois.in b/apps/irssi/docs/help/in/whois.in index f9ebe71d..274251b6 100644 --- a/apps/irssi/docs/help/in/whois.in +++ b/apps/irssi/docs/help/in/whois.in @@ -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 diff --git a/apps/irssi/src/silc/core/silc-servers.c b/apps/irssi/src/silc/core/silc-servers.c index 29cdca77..731298dd 100644 --- a/apps/irssi/src/silc/core/silc-servers.c +++ b/apps/irssi/src/silc/core/silc-servers.c @@ -391,7 +391,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server) /* SYNTAX: SILCOPER [-pubkey] */ /* SYNTAX: TOPIC [] */ /* SYNTAX: UMODE +|- */ -/* SYNTAX: WHOIS [@] [] */ +/* SYNTAX: WHOIS [@] [-details] [] */ /* SYNTAX: WHOWAS [@] [] */ /* SYNTAX: CLOSE [] */ /* SYNTAX: SHUTDOWN */ diff --git a/lib/silcclient/Makefile.am b/lib/silcclient/Makefile.am index 68d9f9d7..6eda8de3 100644 --- a/lib/silcclient/Makefile.am +++ b/lib/silcclient/Makefile.am @@ -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 \ diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 0d238bfa..45d81d04 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -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 || diff --git a/lib/silcclient/client.h b/lib/silcclient/client.h index 2073bc5a..6fbdbd4a 100644 --- a/lib/silcclient/client.h +++ b/lib/silcclient/client.h @@ -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 index 00000000..53693106 --- /dev/null +++ b/lib/silcclient/client_attrs.c @@ -0,0 +1,210 @@ +/* + + client_attrs.c + + Author: Pekka Riikonen + + 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; +} diff --git a/lib/silcclient/client_channel.c b/lib/silcclient/client_channel.c index 2fc79ea3..6d38c42d 100644 --- a/lib/silcclient/client_channel.c +++ b/lib/silcclient/client_channel.c @@ -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; diff --git a/lib/silcclient/client_ftp.c b/lib/silcclient/client_ftp.c index aed0f01c..c335121f 100644 --- a/lib/silcclient/client_ftp.c +++ b/lib/silcclient/client_ftp.c @@ -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); } diff --git a/lib/silcclient/client_internal.h b/lib/silcclient/client_internal.h index 7cc00499..d5e6fc78 100644 --- a/lib/silcclient/client_internal.h +++ b/lib/silcclient/client_internal.h @@ -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 diff --git a/lib/silcclient/client_keyagr.c b/lib/silcclient/client_keyagr.c index b9c78550..3e9efd5f 100644 --- a/lib/silcclient/client_keyagr.c +++ b/lib/silcclient/client_keyagr.c @@ -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); diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index 7258dc92..bd3edd3f 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -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); diff --git a/lib/silcclient/client_prvmsg.c b/lib/silcclient/client_prvmsg.c index 647790b5..dca5d000 100644 --- a/lib/silcclient/client_prvmsg.c +++ b/lib/silcclient/client_prvmsg.c @@ -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); diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 4a4b74ff..83e6bb69 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -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); +} diff --git a/lib/silcclient/command.h b/lib/silcclient/command.h index b85d2e05..84663109 100644 --- a/lib/silcclient/command.h +++ b/lib/silcclient/command.h @@ -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); diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index 5772d414..7277b8db 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -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 diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c index 92b1dc37..82a2e051 100644 --- a/lib/silcclient/idlist.c +++ b/lib/silcclient/idlist.c @@ -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 */ diff --git a/lib/silcclient/idlist.h b/lib/silcclient/idlist.h index 7d9a89ec..f6357b49 100644 --- a/lib/silcclient/idlist.h +++ b/lib/silcclient/idlist.h @@ -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 diff --git a/lib/silcclient/silcclient.h b/lib/silcclient/silcclient.h index 85a55b4b..e301f158 100644 --- a/lib/silcclient/silcclient.h +++ b/lib/silcclient/silcclient.h @@ -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" -- 2.24.0