5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 * Command reply functions are "the otherside" of the command functions.
22 * Reply to a command sent by server is handled by these functions.
24 * The arguments received from server are also passed to the calling
25 * application through command_reply client operation. The arguments are
26 * exactly same and in same order as the server sent it. However, ID's are
27 * not sent to the application. Instead, corresponding ID entry is sent
28 * to the application. For example, instead of sending Client ID the
29 * corresponding SilcClientEntry is sent to the application. The case is
30 * same with for example Channel ID's. This way application has all the
31 * necessary data already in hand without redundant searching. If ID is
32 * received but ID entry does not exist, NULL is sent.
35 #include "silcincludes.h"
36 #include "silcclient.h"
37 #include "client_internal.h"
39 #define SAY cmd->client->internal->ops->say
41 /* All functions that call the COMMAND_CHECK_STATUS macro must have
42 out: and err: goto labels. out label should call the pending
43 command replies, and the err label just handle error condition. */
45 #define COMMAND_CHECK_STATUS \
47 SILC_LOG_DEBUG(("Start")); \
48 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
49 if (SILC_STATUS_IS_ERROR(cmd->status)) { \
51 COMMAND_REPLY_ERROR; \
54 /* List of errors */ \
55 COMMAND_REPLY_ERROR; \
56 if (cmd->status == SILC_STATUS_LIST_END) \
62 /* Same as COMMAND_CHECK_STATUS but doesn't call client operation */
63 #define COMMAND_CHECK_STATUS_I \
65 SILC_LOG_DEBUG(("Start")); \
66 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
67 if (SILC_STATUS_IS_ERROR(cmd->status)) \
69 if (cmd->status == SILC_STATUS_LIST_END) \
75 /* Process received command reply. */
77 void silc_client_command_reply_process(SilcClient client,
78 SilcSocketConnection sock,
79 SilcPacketContext *packet)
81 SilcBuffer buffer = packet->buffer;
82 SilcClientCommand cmd;
83 SilcClientCommandReplyContext ctx;
84 SilcCommandPayload payload;
86 SilcCommandCb reply = NULL;
88 /* Get command reply payload from packet */
89 payload = silc_command_payload_parse(buffer->data, buffer->len);
91 /* Silently ignore bad reply packet */
92 SILC_LOG_DEBUG(("Bad command reply packet"));
96 /* Allocate command reply context. This must be free'd by the
97 command reply routine receiving it. */
98 ctx = silc_calloc(1, sizeof(*ctx));
100 ctx->client = client;
102 ctx->payload = payload;
103 ctx->args = silc_command_get_args(ctx->payload);
104 ctx->packet = packet;
105 ctx->ident = silc_command_get_ident(ctx->payload);
106 silc_command_get_status(ctx->payload, &ctx->status, &ctx->error);
108 /* Check for pending commands and mark to be exeucted */
110 silc_client_command_pending_check(sock->user_data, ctx,
111 silc_command_get(ctx->payload),
112 ctx->ident, &ctx->callbacks_count);
114 /* Execute command reply */
116 command = silc_command_get(ctx->payload);
118 /* Try to find matching the command identifier */
119 silc_list_start(client->internal->commands);
120 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
121 if (cmd->cmd == command && !cmd->ident)
123 if (cmd->cmd == command && cmd->ident == ctx->ident) {
124 (*cmd->reply)((void *)ctx, NULL);
129 if (cmd == SILC_LIST_END) {
131 /* No specific identifier for command reply, call first one found */
138 /* Duplicate Command Reply Context by adding reference counter. The context
139 won't be free'd untill it hits zero. */
141 SilcClientCommandReplyContext
142 silc_client_command_reply_dup(SilcClientCommandReplyContext cmd)
145 SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
146 cmd->users - 1, cmd->users));
150 /* Free command reply context and its internals. */
152 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
155 SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
156 cmd->users + 1, cmd->users));
157 if (cmd->users < 1) {
158 silc_command_payload_free(cmd->payload);
164 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
168 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
169 SilcClientID *client_id;
170 SilcClientEntry client_entry = NULL;
172 unsigned char *id_data, *tmp;
173 char *nickname = NULL, *username = NULL;
174 char *realname = NULL;
175 SilcUInt32 idle = 0, mode = 0;
176 SilcBufferStruct channels, ch_user_modes;
177 bool has_channels = FALSE, has_user_modes = FALSE;
178 unsigned char *fingerprint;
179 SilcUInt32 fingerprint_len;
181 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
188 client_id = silc_id_payload_parse_id(id_data, len, NULL);
195 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
196 username = silc_argument_get_arg_type(cmd->args, 4, &len);
197 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
198 if (!nickname || !username || !realname) {
204 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
206 silc_buffer_set(&channels, tmp, len);
210 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
212 SILC_GET32_MSB(mode, tmp);
214 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
216 SILC_GET32_MSB(idle, tmp);
218 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
220 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
222 silc_buffer_set(&ch_user_modes, tmp, len);
223 has_user_modes = TRUE;
226 /* Check if we have this client cached already. */
227 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
229 SILC_LOG_DEBUG(("Adding new client entry"));
231 silc_client_add_client(cmd->client, conn, nickname, username, realname,
234 silc_client_update_client(cmd->client, conn, client_entry,
235 nickname, username, realname, mode);
236 silc_free(client_id);
239 if (fingerprint && !client_entry->fingerprint) {
240 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
241 client_entry->fingerprint_len = fingerprint_len;
244 /* Take Requested Attributes if set. */
245 tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
247 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
249 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
251 /* Notify application */
252 if (!cmd->callbacks_count && notify)
253 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
254 has_channels ? &channels : NULL, mode, idle,
255 fingerprint, has_user_modes ? &ch_user_modes : NULL,
256 client_entry->attrs));
259 /* Received reply for WHOIS command. This maybe called several times
260 for one WHOIS command as server may reply with list of results. */
262 SILC_CLIENT_CMD_REPLY_FUNC(whois)
264 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
265 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
267 COMMAND_CHECK_STATUS;
269 /* Save WHOIS info */
270 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
272 /* Pending callbacks are not executed if this was an list entry */
273 if (cmd->status != SILC_STATUS_OK &&
274 cmd->status != SILC_STATUS_LIST_END) {
275 silc_client_command_reply_free(cmd);
280 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
283 /* If we received notify for invalid ID we'll remove the ID if we
285 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
286 SilcClientEntry client_entry;
289 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
292 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
294 client_entry = silc_client_get_client_by_id(cmd->client, conn,
297 silc_client_del_client(cmd->client, conn, client_entry);
298 silc_free(client_id);
303 silc_client_command_reply_free(cmd);
306 /* Received reply for WHOWAS command. */
308 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
310 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
311 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
312 SilcClientID *client_id;
313 SilcClientEntry client_entry = NULL;
315 unsigned char *id_data;
316 char *nickname, *username;
317 char *realname = NULL;
319 COMMAND_CHECK_STATUS;
321 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
327 client_id = silc_id_payload_parse_id(id_data, len, NULL);
333 /* Get the client entry, if exists */
334 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
335 silc_free(client_id);
337 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
338 username = silc_argument_get_arg_type(cmd->args, 4, &len);
339 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
340 if (!nickname || !username) {
345 /* Notify application. We don't save any history information to any
346 cache. Just pass the data to the application for displaying on
348 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
350 /* Pending callbacks are not executed if this was an list entry */
351 if (cmd->status != SILC_STATUS_OK &&
352 cmd->status != SILC_STATUS_LIST_END) {
353 silc_client_command_reply_free(cmd);
358 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
360 silc_client_command_reply_free(cmd);
364 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
368 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
369 SilcClient client = cmd->client;
370 SilcClientID *client_id = NULL;
371 SilcServerID *server_id = NULL;
372 SilcChannelID *channel_id = NULL;
373 SilcClientEntry client_entry;
374 SilcServerEntry server_entry;
375 SilcChannelEntry channel_entry;
377 unsigned char *id_data;
378 char *name = NULL, *info = NULL;
379 SilcIDPayload idp = NULL;
382 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
388 idp = silc_id_payload_parse(id_data, len);
395 name = silc_argument_get_arg_type(cmd->args, 3, &len);
396 info = silc_argument_get_arg_type(cmd->args, 4, &len);
398 id_type = silc_id_payload_get_type(idp);
402 client_id = silc_id_payload_get_id(idp);
404 SILC_LOG_DEBUG(("Received client information"));
406 /* Check if we have this client cached already. */
407 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
409 SILC_LOG_DEBUG(("Adding new client entry"));
411 silc_client_add_client(cmd->client, conn, name, info, NULL,
412 silc_id_dup(client_id, id_type), 0);
414 silc_client_update_client(cmd->client, conn, client_entry,
415 name, info, NULL, 0);
418 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
420 /* Notify application */
422 COMMAND_REPLY((ARGS, client_entry, name, info));
426 server_id = silc_id_payload_get_id(idp);
428 SILC_LOG_DEBUG(("Received server information"));
430 /* Check if we have this server cached already. */
431 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
433 SILC_LOG_DEBUG(("Adding new server entry"));
434 server_entry = silc_client_add_server(cmd->client, conn, name, info,
435 silc_id_dup(server_id, id_type));
442 silc_client_update_server(client, conn, server_entry, name, info);
445 server_entry->resolve_cmd_ident = 0;
447 /* Notify application */
449 COMMAND_REPLY((ARGS, server_entry, name, info));
452 case SILC_ID_CHANNEL:
453 channel_id = silc_id_payload_get_id(idp);
455 SILC_LOG_DEBUG(("Received channel information"));
457 /* Check if we have this channel cached already. */
458 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
459 if (!channel_entry) {
463 /* Add new channel entry */
464 channel_entry = silc_client_add_channel(client, conn, name, 0,
469 /* Notify application */
471 COMMAND_REPLY((ARGS, channel_entry, name, info));
475 silc_id_payload_free(idp);
476 silc_free(client_id);
477 silc_free(server_id);
478 silc_free(channel_id);
481 /* Received reply for IDENTIFY command. This maybe called several times
482 for one IDENTIFY command as server may reply with list of results.
483 This is totally silent and does not print anything on screen. */
485 SILC_CLIENT_CMD_REPLY_FUNC(identify)
487 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
488 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
490 COMMAND_CHECK_STATUS;
492 /* Save IDENTIFY info */
493 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
495 /* Pending callbacks are not executed if this was an list entry */
496 if (cmd->status != SILC_STATUS_OK &&
497 cmd->status != SILC_STATUS_LIST_END) {
498 silc_client_command_reply_free(cmd);
503 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
506 /* If we received notify for invalid ID we'll remove the ID if we
508 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
509 SilcClientEntry client_entry;
512 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
515 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
517 client_entry = silc_client_get_client_by_id(cmd->client, conn,
520 silc_client_del_client(cmd->client, conn, client_entry);
521 silc_free(client_id);
526 silc_client_command_reply_free(cmd);
529 /* Received reply for command NICK. If everything went without errors
530 we just received our new Client ID. */
532 SILC_CLIENT_CMD_REPLY_FUNC(nick)
534 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
535 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
538 SilcUInt32 argc, len;
540 SILC_LOG_DEBUG(("Start"));
542 if (cmd->error != SILC_STATUS_OK) {
543 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
544 "Cannot set nickname: %s",
545 silc_get_status_message(cmd->error));
550 argc = silc_argument_get_arg_num(cmd->args);
551 if (argc < 2 || argc > 3) {
552 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
553 "Cannot set nickname: bad reply to command");
558 /* Take received Client ID */
559 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
560 idp = silc_id_payload_parse(tmp, len);
565 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
567 /* Take the new nickname too */
568 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
570 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
572 silc_free(conn->nickname);
573 conn->nickname = strdup(tmp);
574 conn->local_entry->nickname = conn->nickname;
575 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
576 silc_idcache_add(conn->client_cache, strdup(tmp),
577 conn->local_entry->id, conn->local_entry, 0, NULL);
580 /* Notify application */
581 COMMAND_REPLY((ARGS, conn->local_entry, conn->local_entry->nickname));
584 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
585 silc_client_command_reply_free(cmd);
588 /* Received reply to the LIST command. */
590 SILC_CLIENT_CMD_REPLY_FUNC(list)
592 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
593 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
594 unsigned char *tmp, *name, *topic;
595 SilcUInt32 usercount = 0, len;
596 SilcChannelID *channel_id = NULL;
597 SilcChannelEntry channel_entry;
599 COMMAND_CHECK_STATUS;
601 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
607 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
613 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
619 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
620 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
622 SILC_GET32_MSB(usercount, tmp);
624 /* Check whether the channel exists, and add it to cache if it doesn't. */
625 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
627 if (!channel_entry) {
628 /* Add new channel entry */
629 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
631 if (!channel_entry) {
638 /* Notify application */
639 COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount));
641 /* Pending callbacks are not executed if this was an list entry */
642 if (cmd->status != SILC_STATUS_OK &&
643 cmd->status != SILC_STATUS_LIST_END) {
644 silc_client_command_reply_free(cmd);
649 silc_free(channel_id);
650 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
652 silc_client_command_reply_free(cmd);
655 /* Received reply to topic command. */
657 SILC_CLIENT_CMD_REPLY_FUNC(topic)
659 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
660 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
661 SilcChannelEntry channel;
662 SilcChannelID *channel_id = NULL;
665 SilcUInt32 argc, len;
667 if (cmd->error != SILC_STATUS_OK) {
668 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
669 "%s", silc_get_status_message(cmd->error));
674 argc = silc_argument_get_arg_num(cmd->args);
675 if (argc < 1 || argc > 3) {
680 /* Take Channel ID */
681 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
686 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
690 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
694 /* Get the channel entry */
695 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
697 silc_free(channel_id);
702 /* Notify application */
703 COMMAND_REPLY((ARGS, channel, topic));
706 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
707 silc_client_command_reply_free(cmd);
710 /* Received reply to invite command. */
712 SILC_CLIENT_CMD_REPLY_FUNC(invite)
714 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
715 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
716 SilcChannelEntry channel;
717 SilcChannelID *channel_id;
721 if (cmd->error != SILC_STATUS_OK) {
722 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
723 "%s", silc_get_status_message(cmd->error));
728 /* Take Channel ID */
729 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
733 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
737 /* Get the channel entry */
738 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
740 silc_free(channel_id);
745 /* Get the invite list */
746 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
748 /* Notify application */
749 COMMAND_REPLY((ARGS, channel, tmp));
752 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
753 silc_client_command_reply_free(cmd);
756 /* Received reply to the KILL command. */
758 SILC_CLIENT_CMD_REPLY_FUNC(kill)
760 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
761 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
763 if (cmd->error != SILC_STATUS_OK) {
764 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
765 "%s", silc_get_status_message(cmd->error));
770 /* Notify application */
771 COMMAND_REPLY((ARGS));
774 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
775 silc_client_command_reply_free(cmd);
778 /* Received reply to INFO command. We receive the server ID and some
779 information about the server user requested. */
781 SILC_CLIENT_CMD_REPLY_FUNC(info)
783 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
784 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
786 SilcServerEntry server;
787 SilcServerID *server_id = NULL;
788 char *server_name, *server_info;
791 SILC_LOG_DEBUG(("Start"));
793 if (cmd->error != SILC_STATUS_OK) {
794 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
795 silc_get_status_message(cmd->error));
801 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
805 server_id = silc_id_payload_parse_id(tmp, len, NULL);
809 /* Get server name */
810 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
814 /* Get server info */
815 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
819 /* See whether we have this server cached. If not create it. */
820 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
822 SILC_LOG_DEBUG(("New server entry"));
823 server = silc_client_add_server(cmd->client, conn, server_name,
825 silc_id_dup(server_id, SILC_ID_SERVER));
830 /* Notify application */
831 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
834 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
835 silc_free(server_id);
836 silc_client_command_reply_free(cmd);
839 /* Received reply to STATS command. */
841 SILC_CLIENT_CMD_REPLY_FUNC(stats)
843 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
844 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
845 unsigned char *tmp, *buf = NULL;
846 SilcUInt32 len, buf_len = 0;
848 if (cmd->error != SILC_STATUS_OK) {
849 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
850 "%s", silc_get_status_message(cmd->error));
856 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
860 /* Get statistics structure */
861 buf = silc_argument_get_arg_type(cmd->args, 3, &buf_len);
863 /* Notify application */
864 COMMAND_REPLY((ARGS, buf, buf_len));
867 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
868 silc_client_command_reply_free(cmd);
871 /* Received reply to PING command. The reply time is shown to user. */
873 SILC_CLIENT_CMD_REPLY_FUNC(ping)
875 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
876 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
879 time_t diff, curtime;
881 if (cmd->error != SILC_STATUS_OK) {
882 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
883 "%s", silc_get_status_message(cmd->error));
888 curtime = time(NULL);
889 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
890 cmd->packet->src_id_type);
891 if (!id || !conn->ping) {
896 for (i = 0; i < conn->ping_count; i++) {
897 if (!conn->ping[i].dest_id)
899 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
900 diff = curtime - conn->ping[i].start_time;
901 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
902 "Ping reply from %s: %d second%s",
903 conn->ping[i].dest_name, diff,
904 diff == 1 ? "" : "s");
906 conn->ping[i].start_time = 0;
907 silc_free(conn->ping[i].dest_id);
908 conn->ping[i].dest_id = NULL;
909 silc_free(conn->ping[i].dest_name);
910 conn->ping[i].dest_name = NULL;
917 /* Notify application */
918 COMMAND_REPLY((ARGS));
921 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
922 silc_client_command_reply_free(cmd);
925 /* Received reply for JOIN command. */
927 SILC_CLIENT_CMD_REPLY_FUNC(join)
929 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
930 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
931 SilcChannelEntry channel;
933 SilcChannelID *channel_id;
934 SilcUInt32 argc, mode = 0, len, list_count;
935 char *topic, *tmp, *channel_name = NULL, *hmac;
936 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
939 SILC_LOG_DEBUG(("Start"));
941 if (cmd->error != SILC_STATUS_OK) {
942 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
943 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
944 "%s", silc_get_status_message(cmd->error));
949 argc = silc_argument_get_arg_num(cmd->args);
951 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
952 "Cannot join channel: Bad reply packet");
957 /* Get channel name */
958 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
960 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
961 "Cannot join channel: Bad reply packet");
968 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
970 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
971 "Cannot join channel: Bad reply packet");
975 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
981 /* Get channel mode */
982 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
984 SILC_GET32_MSB(mode, tmp);
986 /* Get channel key */
987 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
989 keyp = silc_buffer_alloc(len);
990 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
991 silc_buffer_put(keyp, tmp, len);
995 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
997 /* Check whether we have this channel entry already. */
998 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1000 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
1001 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
1003 /* Create new channel entry */
1004 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1008 conn->current_channel = channel;
1011 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1013 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1014 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1015 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1016 COMMAND_REPLY_ERROR;
1021 /* Get the list count */
1022 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1025 SILC_GET32_MSB(list_count, tmp);
1027 /* Get Client ID list */
1028 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1032 client_id_list = silc_buffer_alloc(len);
1033 silc_buffer_pull_tail(client_id_list, len);
1034 silc_buffer_put(client_id_list, tmp, len);
1036 /* Get client mode list */
1037 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1041 client_mode_list = silc_buffer_alloc(len);
1042 silc_buffer_pull_tail(client_mode_list, len);
1043 silc_buffer_put(client_mode_list, tmp, len);
1045 /* Add clients we received in the reply to the channel */
1046 for (i = 0; i < list_count; i++) {
1049 SilcClientID *client_id;
1050 SilcClientEntry client_entry;
1053 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1055 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1060 SILC_GET32_MSB(mode, client_mode_list->data);
1062 /* Check if we have this client cached already. */
1063 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1064 if (!client_entry) {
1065 /* No, we don't have it, add entry for it. */
1067 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1068 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1071 /* Join client to the channel */
1072 if (!silc_client_on_channel(channel, client_entry)) {
1073 chu = silc_calloc(1, sizeof(*chu));
1074 chu->client = client_entry;
1075 chu->channel = channel;
1077 silc_hash_table_add(channel->user_list, client_entry, chu);
1078 silc_hash_table_add(client_entry->channels, channel, chu);
1081 silc_free(client_id);
1082 silc_buffer_pull(client_id_list, idp_len);
1083 silc_buffer_pull(client_mode_list, 4);
1085 silc_buffer_push(client_id_list, client_id_list->data -
1086 client_id_list->head);
1087 silc_buffer_push(client_mode_list, client_mode_list->data -
1088 client_mode_list->head);
1090 /* Save channel key */
1091 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1092 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1094 /* Notify application */
1095 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1096 keyp ? keyp->head : NULL, NULL,
1097 NULL, topic, hmac, list_count, client_id_list,
1101 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1102 silc_client_command_reply_free(cmd);
1105 silc_buffer_free(keyp);
1107 silc_buffer_free(client_id_list);
1108 if (client_mode_list)
1109 silc_buffer_free(client_mode_list);
1112 /* Received reply for MOTD command */
1114 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1116 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1117 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1119 char *motd = NULL, *cp, line[256];
1121 if (cmd->error != SILC_STATUS_OK) {
1122 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1123 "%s", silc_get_status_message(cmd->error));
1124 COMMAND_REPLY_ERROR;
1128 argc = silc_argument_get_arg_num(cmd->args);
1130 COMMAND_REPLY_ERROR;
1135 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1137 COMMAND_REPLY_ERROR;
1144 if (cp[i++] == '\n') {
1145 memset(line, 0, sizeof(line));
1146 strncat(line, cp, i - 1);
1152 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1161 /* Notify application */
1162 COMMAND_REPLY((ARGS, motd));
1165 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1166 silc_client_command_reply_free(cmd);
1169 /* Received reply tot he UMODE command. Save the current user mode */
1171 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1173 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1174 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1178 if (cmd->error != SILC_STATUS_OK) {
1179 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1180 "%s", silc_get_status_message(cmd->error));
1181 COMMAND_REPLY_ERROR;
1185 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1187 COMMAND_REPLY_ERROR;
1191 SILC_GET32_MSB(mode, tmp);
1192 conn->local_entry->mode = mode;
1194 /* Notify application */
1195 COMMAND_REPLY((ARGS, mode));
1198 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1199 silc_client_command_reply_free(cmd);
1202 /* Received reply for CMODE command. */
1204 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1206 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1207 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1210 SilcChannelID *channel_id;
1211 SilcChannelEntry channel;
1214 if (cmd->error != SILC_STATUS_OK) {
1215 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1216 "%s", silc_get_status_message(cmd->error));
1217 COMMAND_REPLY_ERROR;
1221 /* Take Channel ID */
1222 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1225 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1229 /* Get the channel entry */
1230 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1232 silc_free(channel_id);
1233 COMMAND_REPLY_ERROR;
1237 /* Get channel mode */
1238 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1240 silc_free(channel_id);
1241 COMMAND_REPLY_ERROR;
1246 SILC_GET32_MSB(mode, tmp);
1247 channel->mode = mode;
1249 /* Notify application */
1250 COMMAND_REPLY((ARGS, channel, mode));
1252 silc_free(channel_id);
1255 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1256 silc_client_command_reply_free(cmd);
1259 /* Received reply for CUMODE command */
1261 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1263 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1264 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1265 SilcClientID *client_id;
1266 SilcChannelID *channel_id;
1267 SilcClientEntry client_entry;
1268 SilcChannelEntry channel;
1269 SilcChannelUser chu;
1270 unsigned char *modev, *tmp, *id;
1271 SilcUInt32 len, mode;
1273 if (cmd->error != SILC_STATUS_OK) {
1274 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1275 "%s", silc_get_status_message(cmd->error));
1276 COMMAND_REPLY_ERROR;
1280 /* Get channel mode */
1281 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1283 COMMAND_REPLY_ERROR;
1287 /* Take Channel ID */
1288 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1291 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1295 /* Get the channel entry */
1296 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1298 silc_free(channel_id);
1299 COMMAND_REPLY_ERROR;
1304 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1306 silc_free(channel_id);
1307 COMMAND_REPLY_ERROR;
1310 client_id = silc_id_payload_parse_id(id, len, NULL);
1312 silc_free(channel_id);
1313 COMMAND_REPLY_ERROR;
1317 /* Get client entry */
1318 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1319 if (!client_entry) {
1320 silc_free(channel_id);
1321 silc_free(client_id);
1322 COMMAND_REPLY_ERROR;
1327 SILC_GET32_MSB(mode, modev);
1328 chu = silc_client_on_channel(channel, client_entry);
1332 /* Notify application */
1333 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1334 silc_free(client_id);
1335 silc_free(channel_id);
1338 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1339 silc_client_command_reply_free(cmd);
1342 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1344 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1345 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1347 if (cmd->error != SILC_STATUS_OK) {
1348 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1349 "%s", silc_get_status_message(cmd->error));
1350 COMMAND_REPLY_ERROR;
1354 /* Notify application */
1355 COMMAND_REPLY((ARGS));
1358 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1359 silc_client_command_reply_free(cmd);
1362 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1364 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1365 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1367 if (cmd->error != SILC_STATUS_OK) {
1368 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1369 "%s", silc_get_status_message(cmd->error));
1370 COMMAND_REPLY_ERROR;
1374 /* Notify application */
1375 COMMAND_REPLY((ARGS));
1378 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1379 silc_client_command_reply_free(cmd);
1382 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1384 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1385 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1387 if (cmd->error != SILC_STATUS_OK) {
1388 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1389 "%s", silc_get_status_message(cmd->error));
1390 COMMAND_REPLY_ERROR;
1394 /* Notify application */
1395 COMMAND_REPLY((ARGS));
1398 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1399 silc_client_command_reply_free(cmd);
1402 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1404 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1405 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1408 if (cmd->error != SILC_STATUS_OK) {
1409 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1410 "%s", silc_get_status_message(cmd->error));
1411 COMMAND_REPLY_ERROR;
1415 /* Notify application */
1416 COMMAND_REPLY((ARGS));
1418 /* Generate the detachment data and deliver it to the client in the
1419 detach client operation */
1420 detach = silc_client_get_detach_data(cmd->client, conn);
1422 cmd->client->internal->ops->detach(cmd->client, conn,
1423 detach->data, detach->len);
1424 silc_buffer_free(detach);
1428 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1429 silc_client_command_reply_free(cmd);
1432 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1434 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1435 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1437 if (cmd->error != SILC_STATUS_OK) {
1438 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1439 "%s", silc_get_status_message(cmd->error));
1440 COMMAND_REPLY_ERROR;
1444 /* Notify application */
1445 COMMAND_REPLY((ARGS));
1448 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1449 silc_client_command_reply_free(cmd);
1452 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1454 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1455 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1456 SilcChannelEntry channel;
1457 SilcChannelID *channel_id;
1461 if (cmd->error != SILC_STATUS_OK) {
1462 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1463 "%s", silc_get_status_message(cmd->error));
1464 COMMAND_REPLY_ERROR;
1468 /* Take Channel ID */
1469 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1473 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1477 /* Get the channel entry */
1478 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1480 silc_free(channel_id);
1481 COMMAND_REPLY_ERROR;
1485 /* Get the ban list */
1486 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1488 /* Notify application */
1489 COMMAND_REPLY((ARGS, channel, tmp));
1492 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1493 silc_client_command_reply_free(cmd);
1496 /* Reply to LEAVE command. */
1498 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1500 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1501 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1502 SilcChannelID *channel_id;
1503 SilcChannelEntry channel = NULL;
1507 if (cmd->error != SILC_STATUS_OK) {
1508 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1509 "%s", silc_get_status_message(cmd->error));
1510 COMMAND_REPLY_ERROR;
1514 /* From protocol version 1.1 we get the channel ID of the left channel */
1515 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1517 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1521 /* Get the channel entry */
1522 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1524 silc_free(channel_id);
1525 COMMAND_REPLY_ERROR;
1529 silc_free(channel_id);
1532 /* Notify application */
1533 COMMAND_REPLY((ARGS, channel));
1536 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1537 silc_client_command_reply_free(cmd);
1540 /* Channel resolving callback for USERS command reply. */
1542 static void silc_client_command_reply_users_cb(SilcClient client,
1543 SilcClientConnection conn,
1544 SilcChannelEntry *channels,
1545 SilcUInt32 channels_count,
1548 if (!channels_count) {
1549 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1550 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1552 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1553 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1554 "%s", silc_get_status_message(cmd->error));
1555 COMMAND_REPLY_ERROR;
1556 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1557 silc_client_command_reply_free(cmd);
1561 silc_client_command_reply_users(context, NULL);
1565 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1568 SilcGetChannelCallback get_channel,
1569 SilcCommandCb get_clients)
1571 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1572 SilcChannelEntry channel;
1573 SilcClientEntry client_entry;
1574 SilcChannelUser chu;
1575 SilcChannelID *channel_id = NULL;
1576 SilcBufferStruct client_id_list, client_mode_list;
1578 SilcUInt32 tmp_len, list_count;
1580 unsigned char **res_argv = NULL;
1581 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1582 bool wait_res = FALSE;
1584 SILC_LOG_DEBUG(("Start"));
1586 /* Get channel ID */
1587 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1589 COMMAND_REPLY_ERROR;
1592 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1594 COMMAND_REPLY_ERROR;
1598 /* Get the list count */
1599 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1601 COMMAND_REPLY_ERROR;
1604 SILC_GET32_MSB(list_count, tmp);
1606 /* Get Client ID list */
1607 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1609 COMMAND_REPLY_ERROR;
1612 silc_buffer_set(&client_id_list, tmp, tmp_len);
1614 /* Get client mode list */
1615 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1617 COMMAND_REPLY_ERROR;
1620 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1622 /* Get channel entry */
1623 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1625 /* Resolve the channel from server */
1626 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1628 silc_free(channel_id);
1632 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1634 /* Cache the received Client ID's and modes. */
1635 for (i = 0; i < list_count; i++) {
1638 SilcClientID *client_id;
1641 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1643 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1648 SILC_GET32_MSB(mode, client_mode_list.data);
1650 /* Check if we have this client cached already. */
1651 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1652 if (!client_entry || !client_entry->username || !client_entry->realname) {
1653 /* No we don't have it (or it is incomplete in information), query
1654 it from the server. Assemble argument table that will be sent
1655 for the WHOIS command later. */
1656 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1658 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1660 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1662 res_argv[res_argc] = client_id_list.data;
1663 res_argv_lens[res_argc] = idp_len;
1664 res_argv_types[res_argc] = res_argc + 4;
1667 if (!silc_client_on_channel(channel, client_entry)) {
1668 chu = silc_calloc(1, sizeof(*chu));
1669 chu->client = client_entry;
1671 chu->channel = channel;
1672 silc_hash_table_add(channel->user_list, client_entry, chu);
1673 silc_hash_table_add(client_entry->channels, channel, chu);
1677 silc_free(client_id);
1678 silc_buffer_pull(&client_id_list, idp_len);
1679 silc_buffer_pull(&client_mode_list, 4);
1682 /* Query the client information from server if the list included clients
1683 that we don't know about. */
1687 /* Send the WHOIS command to server */
1688 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1689 silc_client_command_reply_whois_i, 0,
1691 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1692 res_argc, res_argv, res_argv_lens,
1693 res_argv_types, conn->cmd_ident);
1694 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1695 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1698 /* Register pending command callback. After we've received the WHOIS
1699 command reply we will reprocess this command reply by re-calling this
1700 USERS command reply callback. */
1701 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1704 silc_buffer_free(res_cmd);
1705 silc_free(channel_id);
1706 silc_free(res_argv);
1707 silc_free(res_argv_lens);
1708 silc_free(res_argv_types);
1715 silc_buffer_push(&client_id_list, (client_id_list.data -
1716 client_id_list.head));
1717 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1718 client_mode_list.head));
1720 /* Notify application */
1722 COMMAND_REPLY((ARGS, channel, list_count, &client_id_list,
1723 &client_mode_list));
1726 silc_free(channel_id);
1730 /* Reply to USERS command. Received list of client ID's and theirs modes
1731 on the channel we requested. */
1733 SILC_CLIENT_CMD_REPLY_FUNC(users)
1735 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1736 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1738 SILC_LOG_DEBUG(("Start"));
1740 if (cmd->error != SILC_STATUS_OK) {
1741 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1742 "%s", silc_get_status_message(cmd->error));
1743 COMMAND_REPLY_ERROR;
1747 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
1748 silc_client_command_reply_users_cb,
1749 silc_client_command_reply_users))
1753 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1754 silc_client_command_reply_free(cmd);
1757 /* Received command reply to GETKEY command. WE've received the remote
1758 client's public key. */
1760 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1762 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1763 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1764 SilcIDPayload idp = NULL;
1765 SilcClientID *client_id = NULL;
1766 SilcClientEntry client_entry;
1767 SilcServerID *server_id = NULL;
1768 SilcServerEntry server_entry;
1770 unsigned char *tmp, *pk;
1774 SilcPublicKey public_key = NULL;
1776 SILC_LOG_DEBUG(("Start"));
1778 if (cmd->error != SILC_STATUS_OK) {
1779 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1780 "%s", silc_get_status_message(cmd->error));
1781 COMMAND_REPLY_ERROR;
1785 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1787 COMMAND_REPLY_ERROR;
1790 idp = silc_id_payload_parse(tmp, len);
1792 COMMAND_REPLY_ERROR;
1796 /* Get the public key payload */
1797 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1799 /* Decode the public key */
1800 SILC_GET16_MSB(pk_len, tmp);
1801 SILC_GET16_MSB(type, tmp + 2);
1804 if (type == SILC_SKE_PK_TYPE_SILC)
1805 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1809 id_type = silc_id_payload_get_type(idp);
1810 if (id_type == SILC_ID_CLIENT) {
1811 /* Received client's public key */
1812 client_id = silc_id_payload_get_id(idp);
1813 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1814 if (!client_entry) {
1815 COMMAND_REPLY_ERROR;
1819 /* Notify application */
1820 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1821 } else if (id_type == SILC_ID_SERVER) {
1822 /* Received server's public key */
1823 server_id = silc_id_payload_get_id(idp);
1824 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1825 if (!server_entry) {
1826 COMMAND_REPLY_ERROR;
1830 /* Notify application */
1831 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1835 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1837 silc_id_payload_free(idp);
1839 silc_pkcs_public_key_free(public_key);
1840 silc_free(client_id);
1841 silc_free(server_id);
1842 silc_client_command_reply_free(cmd);
1845 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1847 silc_client_command_reply_free(context);
1851 /******************************************************************************
1853 Internal command reply functions
1855 ******************************************************************************/
1857 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1859 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1860 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1862 COMMAND_CHECK_STATUS_I;
1864 /* Save WHOIS info */
1865 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1867 /* Pending callbacks are not executed if this was an list entry */
1868 if (cmd->status != SILC_STATUS_OK &&
1869 cmd->status != SILC_STATUS_LIST_END) {
1870 silc_client_command_reply_free(cmd);
1875 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1878 /* If we received notify for invalid ID we'll remove the ID if we
1880 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1881 SilcClientEntry client_entry;
1883 unsigned char *tmp =
1884 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1887 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1889 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1892 silc_client_del_client(cmd->client, conn, client_entry);
1893 silc_free(client_id);
1898 /* Unregister this command reply */
1899 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1900 NULL, silc_client_command_reply_whois_i,
1903 silc_client_command_reply_free(cmd);
1906 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1908 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1909 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1911 COMMAND_CHECK_STATUS_I;
1913 /* Save IDENTIFY info */
1914 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1916 /* Pending callbacks are not executed if this was an list entry */
1917 if (cmd->status != SILC_STATUS_OK &&
1918 cmd->status != SILC_STATUS_LIST_END) {
1919 silc_client_command_reply_free(cmd);
1924 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1927 /* If we received notify for invalid ID we'll remove the ID if we
1929 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1930 SilcClientEntry client_entry;
1932 unsigned char *tmp =
1933 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1936 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1938 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1941 silc_client_del_client(cmd->client, conn, client_entry);
1942 silc_free(client_id);
1947 /* Unregister this command reply */
1948 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1949 NULL, silc_client_command_reply_identify_i,
1952 silc_client_command_reply_free(cmd);
1955 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1957 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1958 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1960 SilcServerEntry server;
1961 SilcServerID *server_id = NULL;
1962 char *server_name, *server_info;
1965 COMMAND_CHECK_STATUS_I;
1968 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1972 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1976 /* Get server name */
1977 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1981 /* Get server info */
1982 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1986 /* See whether we have this server cached. If not create it. */
1987 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1989 SILC_LOG_DEBUG(("New server entry"));
1990 silc_client_add_server(cmd->client, conn, server_name, server_info,
1991 silc_id_dup(server_id, SILC_ID_SERVER));
1995 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1996 silc_free(server_id);
1998 silc_client_command_reply_free(cmd);
2001 static void silc_client_command_reply_users_i_cb(SilcClient client,
2002 SilcClientConnection conn,
2003 SilcChannelEntry *channels,
2004 SilcUInt32 channels_count,
2007 if (!channels_count) {
2008 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2009 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2011 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2012 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2013 "%s", silc_get_status_message(cmd->error));
2014 COMMAND_REPLY_ERROR;
2015 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2016 silc_client_command_reply_free(cmd);
2020 silc_client_command_reply_users_i(context, NULL);
2023 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2025 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2027 COMMAND_CHECK_STATUS_I;
2029 /* Save USERS info */
2030 if (silc_client_command_reply_users_save(
2031 cmd, cmd->status, FALSE,
2032 silc_client_command_reply_users_i_cb,
2033 silc_client_command_reply_users_i))
2037 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2040 /* Unregister this command reply */
2041 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2042 NULL, silc_client_command_reply_users_i,
2045 silc_client_command_reply_free(cmd);
2048 /* Private range commands, specific to this implementation (and compatible
2049 with SILC Server >= 0.9). */
2051 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2053 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2054 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2056 if (cmd->error != SILC_STATUS_OK) {
2057 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2058 "%s", silc_get_status_message(cmd->error));
2059 COMMAND_REPLY_ERROR;
2063 /* Notify application */
2064 COMMAND_REPLY((ARGS));
2067 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2068 silc_client_command_reply_free(cmd);
2071 SILC_CLIENT_CMD_REPLY_FUNC(close)
2073 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2074 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2076 if (cmd->error != SILC_STATUS_OK) {
2077 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2078 "%s", silc_get_status_message(cmd->error));
2079 COMMAND_REPLY_ERROR;
2083 /* Notify application */
2084 COMMAND_REPLY((ARGS));
2087 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2088 silc_client_command_reply_free(cmd);
2091 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2093 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2094 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2096 if (cmd->error != SILC_STATUS_OK) {
2097 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2098 "%s", silc_get_status_message(cmd->error));
2099 COMMAND_REPLY_ERROR;
2103 /* Notify application */
2104 COMMAND_REPLY((ARGS));
2107 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2108 silc_client_command_reply_free(cmd);