5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2003 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(cmd->status); \
54 /* List of errors */ \
55 COMMAND_REPLY_ERROR(cmd->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);
184 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
188 client_id = silc_id_payload_parse_id(id_data, len, NULL);
191 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
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) {
200 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
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 if (client_entry->attrs)
248 silc_attribute_payload_list_free(client_entry->attrs);
249 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
252 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
254 /* Notify application */
255 if (!cmd->callbacks_count && notify)
256 COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname,
257 has_channels ? &channels : NULL, mode, idle,
258 fingerprint, has_user_modes ? &ch_user_modes : NULL,
259 client_entry->attrs));
262 /* Received reply for WHOIS command. This maybe called several times
263 for one WHOIS command as server may reply with list of results. */
265 SILC_CLIENT_CMD_REPLY_FUNC(whois)
267 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
268 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
270 COMMAND_CHECK_STATUS;
272 /* Save WHOIS info */
273 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
275 /* Pending callbacks are not executed if this was an list entry */
276 if (cmd->status != SILC_STATUS_OK &&
277 cmd->status != SILC_STATUS_LIST_END) {
278 silc_client_command_reply_free(cmd);
283 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
286 /* If we received notify for invalid ID we'll remove the ID if we
288 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
289 SilcClientEntry client_entry;
292 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
295 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
297 client_entry = silc_client_get_client_by_id(cmd->client, conn,
300 silc_client_del_client(cmd->client, conn, client_entry);
301 silc_free(client_id);
306 silc_client_command_reply_free(cmd);
309 /* Received reply for WHOWAS command. */
311 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
313 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
314 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
315 SilcClientID *client_id;
316 SilcClientEntry client_entry = NULL;
318 unsigned char *id_data;
319 char *nickname, *username;
320 char *realname = NULL;
322 COMMAND_CHECK_STATUS;
324 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
326 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
330 client_id = silc_id_payload_parse_id(id_data, len, NULL);
332 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
336 /* Get the client entry, if exists */
337 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
338 silc_free(client_id);
340 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
341 username = silc_argument_get_arg_type(cmd->args, 4, &len);
342 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
343 if (!nickname || !username) {
344 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
348 /* Notify application. We don't save any history information to any
349 cache. Just pass the data to the application for displaying on
351 COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname));
353 /* Pending callbacks are not executed if this was an list entry */
354 if (cmd->status != SILC_STATUS_OK &&
355 cmd->status != SILC_STATUS_LIST_END) {
356 silc_client_command_reply_free(cmd);
361 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
363 silc_client_command_reply_free(cmd);
367 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
371 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
372 SilcClient client = cmd->client;
373 SilcClientID *client_id = NULL;
374 SilcServerID *server_id = NULL;
375 SilcChannelID *channel_id = NULL;
376 SilcClientEntry client_entry;
377 SilcServerEntry server_entry;
378 SilcChannelEntry channel_entry;
380 unsigned char *id_data;
381 char *name = NULL, *info = NULL;
382 SilcIDPayload idp = NULL;
385 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
388 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
391 idp = silc_id_payload_parse(id_data, len);
394 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
398 name = silc_argument_get_arg_type(cmd->args, 3, &len);
399 info = silc_argument_get_arg_type(cmd->args, 4, &len);
401 id_type = silc_id_payload_get_type(idp);
405 client_id = silc_id_payload_get_id(idp);
407 SILC_LOG_DEBUG(("Received client information"));
409 /* Check if we have this client cached already. */
410 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
412 SILC_LOG_DEBUG(("Adding new client entry"));
414 silc_client_add_client(cmd->client, conn, name, info, NULL,
415 silc_id_dup(client_id, id_type), 0);
417 silc_client_update_client(cmd->client, conn, client_entry,
418 name, info, NULL, 0);
421 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
423 /* Notify application */
425 COMMAND_REPLY((SILC_ARGS, client_entry, name, info));
429 server_id = silc_id_payload_get_id(idp);
431 SILC_LOG_DEBUG(("Received server information"));
433 /* Check if we have this server cached already. */
434 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
436 SILC_LOG_DEBUG(("Adding new server entry"));
437 server_entry = silc_client_add_server(cmd->client, conn, name, info,
438 silc_id_dup(server_id, id_type));
441 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
445 silc_client_update_server(client, conn, server_entry, name, info);
448 server_entry->resolve_cmd_ident = 0;
450 /* Notify application */
452 COMMAND_REPLY((SILC_ARGS, server_entry, name, info));
455 case SILC_ID_CHANNEL:
456 channel_id = silc_id_payload_get_id(idp);
458 SILC_LOG_DEBUG(("Received channel information"));
460 /* Check if we have this channel cached already. */
461 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
462 if (!channel_entry) {
466 /* Add new channel entry */
467 channel_entry = silc_client_add_channel(client, conn, name, 0,
472 /* Notify application */
474 COMMAND_REPLY((SILC_ARGS, channel_entry, name, info));
478 silc_id_payload_free(idp);
479 silc_free(client_id);
480 silc_free(server_id);
481 silc_free(channel_id);
484 /* Received reply for IDENTIFY command. This maybe called several times
485 for one IDENTIFY command as server may reply with list of results.
486 This is totally silent and does not print anything on screen. */
488 SILC_CLIENT_CMD_REPLY_FUNC(identify)
490 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
491 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
493 COMMAND_CHECK_STATUS;
495 /* Save IDENTIFY info */
496 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
498 /* Pending callbacks are not executed if this was an list entry */
499 if (cmd->status != SILC_STATUS_OK &&
500 cmd->status != SILC_STATUS_LIST_END) {
501 silc_client_command_reply_free(cmd);
506 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
509 /* If we received notify for invalid ID we'll remove the ID if we
511 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
512 SilcClientEntry client_entry;
515 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
518 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
520 client_entry = silc_client_get_client_by_id(cmd->client, conn,
523 silc_client_del_client(cmd->client, conn, client_entry);
524 silc_free(client_id);
529 silc_client_command_reply_free(cmd);
532 /* Received reply for command NICK. If everything went without errors
533 we just received our new Client ID. */
535 SILC_CLIENT_CMD_REPLY_FUNC(nick)
537 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
538 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
541 SilcUInt32 argc, len;
542 SilcClientID old_client_id;
544 SILC_LOG_DEBUG(("Start"));
546 if (cmd->error != SILC_STATUS_OK) {
547 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
548 "Cannot set nickname: %s",
549 silc_get_status_message(cmd->error));
550 COMMAND_REPLY_ERROR(cmd->error);
554 argc = silc_argument_get_arg_num(cmd->args);
555 if (argc < 2 || argc > 3) {
556 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
557 "Cannot set nickname: bad reply to command");
558 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
562 /* Save old Client ID */
563 old_client_id = *conn->local_id;
565 /* Take received Client ID */
566 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
567 idp = silc_id_payload_parse(tmp, len);
569 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
572 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
574 /* Take the new nickname too */
575 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
577 silc_idcache_del_by_context(conn->internal->client_cache,
580 silc_free(conn->nickname);
581 conn->nickname = strdup(tmp);
582 conn->local_entry->nickname = conn->nickname;
583 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
584 silc_idcache_add(conn->internal->client_cache, strdup(tmp),
585 conn->local_entry->id, conn->local_entry, 0, NULL);
588 /* Notify application */
589 COMMAND_REPLY((SILC_ARGS, conn->local_entry, conn->local_entry->nickname,
590 (const SilcClientID *)&old_client_id));
593 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
594 silc_client_command_reply_free(cmd);
597 /* Received reply to the LIST command. */
599 SILC_CLIENT_CMD_REPLY_FUNC(list)
601 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
602 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
603 unsigned char *tmp, *name, *topic;
604 SilcUInt32 usercount = 0, len;
605 SilcChannelID *channel_id = NULL;
606 SilcChannelEntry channel_entry;
608 COMMAND_CHECK_STATUS;
610 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
612 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
616 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
618 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
622 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
624 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
628 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
629 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
631 SILC_GET32_MSB(usercount, tmp);
633 /* Check whether the channel exists, and add it to cache if it doesn't. */
634 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
636 if (!channel_entry) {
637 /* Add new channel entry */
638 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
640 if (!channel_entry) {
641 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
647 /* Notify application */
648 COMMAND_REPLY((SILC_ARGS, channel_entry, name, topic, usercount));
650 /* Pending callbacks are not executed if this was an list entry */
651 if (cmd->status != SILC_STATUS_OK &&
652 cmd->status != SILC_STATUS_LIST_END) {
653 silc_client_command_reply_free(cmd);
658 silc_free(channel_id);
659 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
661 silc_client_command_reply_free(cmd);
664 /* Received reply to topic command. */
666 SILC_CLIENT_CMD_REPLY_FUNC(topic)
668 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
669 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
670 SilcChannelEntry channel;
671 SilcChannelID *channel_id = NULL;
674 SilcUInt32 argc, len;
676 if (cmd->error != SILC_STATUS_OK) {
677 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
678 "Cannot set topic: %s", silc_get_status_message(cmd->error));
679 COMMAND_REPLY_ERROR(cmd->error);
683 argc = silc_argument_get_arg_num(cmd->args);
684 if (argc < 1 || argc > 3) {
685 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
689 /* Take Channel ID */
690 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
695 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
699 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
703 /* Get the channel entry */
704 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
706 silc_free(channel_id);
707 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
711 /* Notify application */
712 COMMAND_REPLY((SILC_ARGS, channel, topic));
715 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
716 silc_client_command_reply_free(cmd);
719 /* Received reply to invite command. */
721 SILC_CLIENT_CMD_REPLY_FUNC(invite)
723 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
724 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
725 SilcChannelEntry channel;
726 SilcChannelID *channel_id;
729 SilcBufferStruct buf;
731 if (cmd->error != SILC_STATUS_OK) {
732 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
733 "Cannot invite: %s", silc_get_status_message(cmd->error));
734 COMMAND_REPLY_ERROR(cmd->error);
738 /* Take Channel ID */
739 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
743 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
747 /* Get the channel entry */
748 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
750 silc_free(channel_id);
751 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
755 /* Get the invite list */
756 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
758 silc_buffer_set(&buf, tmp, len);
760 /* Notify application */
761 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
764 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
765 silc_client_command_reply_free(cmd);
768 /* Received reply to the KILL command. */
770 SILC_CLIENT_CMD_REPLY_FUNC(kill)
772 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
773 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
774 SilcClientID *client_id;
775 SilcClientEntry client_entry = NULL;
777 unsigned char *id_data;
779 if (cmd->error != SILC_STATUS_OK) {
780 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
781 "Cannot kill: %s", silc_get_status_message(cmd->error));
782 COMMAND_REPLY_ERROR(cmd->error);
786 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
788 client_id = silc_id_payload_parse_id(id_data, len, NULL);
790 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
794 /* Get the client entry, if exists */
795 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
796 silc_free(client_id);
799 /* Notify application */
800 COMMAND_REPLY((SILC_ARGS, client_entry));
803 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
804 silc_client_command_reply_free(cmd);
807 /* Received reply to INFO command. We receive the server ID and some
808 information about the server user requested. */
810 SILC_CLIENT_CMD_REPLY_FUNC(info)
812 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
813 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
815 SilcServerEntry server;
816 SilcServerID *server_id = NULL;
817 char *server_name, *server_info;
820 SILC_LOG_DEBUG(("Start"));
822 if (cmd->error != SILC_STATUS_OK) {
823 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
824 silc_get_status_message(cmd->error));
825 COMMAND_REPLY_ERROR(cmd->error);
830 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
834 server_id = silc_id_payload_parse_id(tmp, len, NULL);
838 /* Get server name */
839 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
843 /* Get server info */
844 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
848 /* See whether we have this server cached. If not create it. */
849 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
851 SILC_LOG_DEBUG(("New server entry"));
852 server = silc_client_add_server(cmd->client, conn, server_name,
854 silc_id_dup(server_id, SILC_ID_SERVER));
859 /* Notify application */
860 COMMAND_REPLY((SILC_ARGS, server, server->server_name, server->server_info));
863 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
864 silc_free(server_id);
865 silc_client_command_reply_free(cmd);
868 /* Received reply to STATS command. */
870 SILC_CLIENT_CMD_REPLY_FUNC(stats)
872 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
873 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
874 unsigned char *tmp, *buf = NULL;
875 SilcUInt32 len, buf_len = 0;
877 if (cmd->error != SILC_STATUS_OK) {
878 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
879 "%s", silc_get_status_message(cmd->error));
880 COMMAND_REPLY_ERROR(cmd->error);
885 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
889 /* Get statistics structure */
890 buf = silc_argument_get_arg_type(cmd->args, 3, &buf_len);
892 /* Notify application */
893 COMMAND_REPLY((SILC_ARGS, buf, buf_len));
896 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
897 silc_client_command_reply_free(cmd);
900 /* Received reply to PING command. The reply time is shown to user. */
902 SILC_CLIENT_CMD_REPLY_FUNC(ping)
904 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
905 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
908 time_t diff, curtime;
910 if (cmd->error != SILC_STATUS_OK) {
911 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
912 "%s", silc_get_status_message(cmd->error));
913 COMMAND_REPLY_ERROR(cmd->error);
917 curtime = time(NULL);
918 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
919 cmd->packet->src_id_type);
920 if (!id || !conn->internal->ping) {
921 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
925 for (i = 0; i < conn->internal->ping_count; i++) {
926 if (!conn->internal->ping[i].dest_id)
928 if (SILC_ID_SERVER_COMPARE(conn->internal->ping[i].dest_id, id)) {
929 diff = curtime - conn->internal->ping[i].start_time;
930 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
931 "Ping reply from %s: %d second%s",
932 conn->internal->ping[i].dest_name, diff,
933 diff == 1 ? "" : "s");
935 conn->internal->ping[i].start_time = 0;
936 silc_free(conn->internal->ping[i].dest_id);
937 conn->internal->ping[i].dest_id = NULL;
938 silc_free(conn->internal->ping[i].dest_name);
939 conn->internal->ping[i].dest_name = NULL;
946 /* Notify application */
947 COMMAND_REPLY((SILC_ARGS));
950 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
951 silc_client_command_reply_free(cmd);
954 /* Received reply for JOIN command. */
956 SILC_CLIENT_CMD_REPLY_FUNC(join)
958 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
959 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
960 SilcChannelEntry channel;
962 SilcChannelID *channel_id;
963 SilcUInt32 argc, mode = 0, len, list_count;
964 char *topic, *tmp, *channel_name = NULL, *hmac;
965 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
966 SilcPublicKey founder_key = NULL;
967 SilcBufferStruct chpklist;
970 SILC_LOG_DEBUG(("Start"));
972 if (cmd->error != SILC_STATUS_OK) {
973 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
974 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
975 "Cannot join channel: %s", silc_get_status_message(cmd->error));
976 COMMAND_REPLY_ERROR(cmd->error);
980 argc = silc_argument_get_arg_num(cmd->args);
982 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
983 "Cannot join channel: Bad reply packet");
984 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
988 /* Get channel name */
989 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
991 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
992 "Cannot join channel: Bad reply packet");
993 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
999 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1001 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1002 "Cannot join channel: Bad reply packet");
1003 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1006 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1008 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1012 /* Get channel mode */
1013 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1015 SILC_GET32_MSB(mode, tmp);
1017 /* Get channel key */
1018 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1020 keyp = silc_buffer_alloc(len);
1021 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1022 silc_buffer_put(keyp, tmp, len);
1026 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1028 /* Check whether we have this channel entry already. */
1029 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1031 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
1032 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
1034 /* Create new channel entry */
1035 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1039 conn->current_channel = channel;
1042 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1044 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1045 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1046 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1047 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1052 /* Get the list count */
1053 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1056 SILC_GET32_MSB(list_count, tmp);
1058 /* Get Client ID list */
1059 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1063 client_id_list = silc_buffer_alloc(len);
1064 silc_buffer_pull_tail(client_id_list, len);
1065 silc_buffer_put(client_id_list, tmp, len);
1067 /* Get client mode list */
1068 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1072 client_mode_list = silc_buffer_alloc(len);
1073 silc_buffer_pull_tail(client_mode_list, len);
1074 silc_buffer_put(client_mode_list, tmp, len);
1076 /* Add clients we received in the reply to the channel */
1077 for (i = 0; i < list_count; i++) {
1080 SilcClientID *client_id;
1081 SilcClientEntry client_entry;
1084 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1086 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1091 SILC_GET32_MSB(mode, client_mode_list->data);
1093 /* Check if we have this client cached already. */
1094 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1095 if (!client_entry) {
1096 /* No, we don't have it, add entry for it. */
1098 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1099 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1102 /* Join client to the channel */
1103 if (!silc_client_on_channel(channel, client_entry)) {
1104 chu = silc_calloc(1, sizeof(*chu));
1105 chu->client = client_entry;
1106 chu->channel = channel;
1108 silc_hash_table_add(channel->user_list, client_entry, chu);
1109 silc_hash_table_add(client_entry->channels, channel, chu);
1112 silc_free(client_id);
1113 silc_buffer_pull(client_id_list, idp_len);
1114 silc_buffer_pull(client_mode_list, 4);
1116 silc_buffer_push(client_id_list, client_id_list->data -
1117 client_id_list->head);
1118 silc_buffer_push(client_mode_list, client_mode_list->data -
1119 client_mode_list->head);
1121 /* Save channel key */
1122 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1123 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1125 /* Get founder key */
1126 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
1128 silc_pkcs_public_key_payload_decode(tmp, len, &founder_key);
1130 /* Get channel public key list */
1131 tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
1133 silc_buffer_set(&chpklist, tmp, len);
1135 /* Notify application */
1136 COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0,
1137 keyp ? keyp->head : NULL, NULL,
1138 NULL, topic, hmac, list_count, client_id_list,
1139 client_mode_list, founder_key, tmp ? &chpklist : NULL));
1142 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1143 silc_client_command_reply_free(cmd);
1145 silc_pkcs_public_key_free(founder_key);
1146 silc_buffer_free(keyp);
1147 silc_buffer_free(client_id_list);
1148 silc_buffer_free(client_mode_list);
1151 /* Received reply for MOTD command */
1153 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1155 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1156 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1158 char *motd = NULL, *cp, line[256];
1160 if (cmd->error != SILC_STATUS_OK) {
1161 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1162 "%s", silc_get_status_message(cmd->error));
1163 COMMAND_REPLY_ERROR(cmd->error);
1167 argc = silc_argument_get_arg_num(cmd->args);
1169 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1174 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1176 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1183 if (cp[i++] == '\n') {
1184 memset(line, 0, sizeof(line));
1185 silc_strncat(line, sizeof(line), cp, i - 1);
1191 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1200 /* Notify application */
1201 COMMAND_REPLY((SILC_ARGS, motd));
1204 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1205 silc_client_command_reply_free(cmd);
1208 /* Received reply tot he UMODE command. Save the current user mode */
1210 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1212 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1213 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1217 if (cmd->error != SILC_STATUS_OK) {
1218 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1219 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1220 COMMAND_REPLY_ERROR(cmd->error);
1224 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1226 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1230 SILC_GET32_MSB(mode, tmp);
1231 conn->local_entry->mode = mode;
1233 /* Notify application */
1234 COMMAND_REPLY((SILC_ARGS, mode));
1237 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1238 silc_client_command_reply_free(cmd);
1241 /* Received reply for CMODE command. */
1243 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1245 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1246 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1249 SilcChannelID *channel_id;
1250 SilcChannelEntry channel;
1252 SilcPublicKey public_key = NULL;
1253 SilcBufferStruct channel_pubkeys;
1255 if (cmd->error != SILC_STATUS_OK) {
1256 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1257 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1258 COMMAND_REPLY_ERROR(cmd->error);
1262 /* Take Channel ID */
1263 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1266 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1270 /* Get the channel entry */
1271 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1273 silc_free(channel_id);
1274 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1278 /* Get channel mode */
1279 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1281 silc_free(channel_id);
1282 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1287 SILC_GET32_MSB(mode, tmp);
1288 channel->mode = mode;
1290 /* Get founder public key */
1291 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
1293 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1297 /* Get channel public key(s) */
1298 tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
1300 silc_buffer_set(&channel_pubkeys, tmp, len);
1302 /* Notify application */
1303 COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
1304 tmp ? &channel_pubkeys : NULL));
1306 silc_free(channel_id);
1310 silc_pkcs_public_key_free(public_key);
1311 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1312 silc_client_command_reply_free(cmd);
1315 /* Received reply for CUMODE command */
1317 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1319 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1320 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1321 SilcClientID *client_id;
1322 SilcChannelID *channel_id;
1323 SilcClientEntry client_entry;
1324 SilcChannelEntry channel;
1325 SilcChannelUser chu;
1326 unsigned char *modev, *tmp, *id;
1327 SilcUInt32 len, mode;
1329 if (cmd->error != SILC_STATUS_OK) {
1330 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1331 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1332 COMMAND_REPLY_ERROR(cmd->error);
1336 /* Get channel mode */
1337 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1339 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1343 /* Take Channel ID */
1344 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1347 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1351 /* Get the channel entry */
1352 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1354 silc_free(channel_id);
1355 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1360 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1362 silc_free(channel_id);
1363 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1366 client_id = silc_id_payload_parse_id(id, len, NULL);
1368 silc_free(channel_id);
1369 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1373 /* Get client entry */
1374 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1375 if (!client_entry) {
1376 silc_free(channel_id);
1377 silc_free(client_id);
1378 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1383 SILC_GET32_MSB(mode, modev);
1384 chu = silc_client_on_channel(channel, client_entry);
1388 /* Notify application */
1389 COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry));
1390 silc_free(client_id);
1391 silc_free(channel_id);
1394 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1395 silc_client_command_reply_free(cmd);
1398 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1400 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1401 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1402 SilcClientID *client_id = NULL;
1403 SilcChannelID *channel_id = NULL;
1404 SilcClientEntry client_entry = NULL;
1405 SilcChannelEntry channel = NULL;
1409 if (cmd->error != SILC_STATUS_OK) {
1410 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1411 "Cannot kick: %s", silc_get_status_message(cmd->error));
1412 COMMAND_REPLY_ERROR(cmd->error);
1416 /* Take Channel ID */
1417 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1419 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1421 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1425 /* Get the channel entry */
1426 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1428 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1434 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1436 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1438 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1442 /* Get client entry */
1443 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1444 if (!client_entry) {
1445 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1450 /* Notify application */
1451 COMMAND_REPLY((SILC_ARGS, channel, client_entry));
1454 silc_free(channel_id);
1455 silc_free(client_id);
1456 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1457 silc_client_command_reply_free(cmd);
1460 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1462 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1463 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1465 if (cmd->error != SILC_STATUS_OK) {
1466 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1467 "%s", silc_get_status_message(cmd->error));
1468 COMMAND_REPLY_ERROR(cmd->error);
1472 /* Notify application */
1473 COMMAND_REPLY((SILC_ARGS));
1476 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1477 silc_client_command_reply_free(cmd);
1480 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1482 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1483 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1485 if (cmd->error != SILC_STATUS_OK) {
1486 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1487 "%s", silc_get_status_message(cmd->error));
1488 COMMAND_REPLY_ERROR(cmd->error);
1492 /* Notify application */
1493 COMMAND_REPLY((SILC_ARGS));
1496 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1497 silc_client_command_reply_free(cmd);
1500 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1502 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1503 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1506 if (cmd->error != SILC_STATUS_OK) {
1507 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1508 "%s", silc_get_status_message(cmd->error));
1509 COMMAND_REPLY_ERROR(cmd->error);
1513 /* Notify application */
1514 COMMAND_REPLY((SILC_ARGS));
1516 /* Generate the detachment data and deliver it to the client in the
1517 detach client operation */
1518 detach = silc_client_get_detach_data(cmd->client, conn);
1520 cmd->client->internal->ops->detach(cmd->client, conn,
1521 detach->data, detach->len);
1522 silc_buffer_free(detach);
1526 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1527 silc_client_command_reply_free(cmd);
1530 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1532 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1533 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1535 if (cmd->error != SILC_STATUS_OK) {
1536 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1537 "%s", silc_get_status_message(cmd->error));
1538 COMMAND_REPLY_ERROR(cmd->error);
1542 /* Notify application */
1543 COMMAND_REPLY((SILC_ARGS));
1546 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1547 silc_client_command_reply_free(cmd);
1550 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1552 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1553 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1554 SilcChannelEntry channel;
1555 SilcChannelID *channel_id;
1558 SilcBufferStruct buf;
1560 if (cmd->error != SILC_STATUS_OK) {
1561 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1562 "%s", silc_get_status_message(cmd->error));
1563 COMMAND_REPLY_ERROR(cmd->error);
1567 /* Take Channel ID */
1568 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1572 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1576 /* Get the channel entry */
1577 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1579 silc_free(channel_id);
1580 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1584 /* Get the ban list */
1585 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1587 silc_buffer_set(&buf, tmp, len);
1589 /* Notify application */
1590 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
1593 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1594 silc_client_command_reply_free(cmd);
1597 /* Reply to LEAVE command. */
1599 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1601 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1602 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1603 SilcChannelID *channel_id;
1604 SilcChannelEntry channel = NULL;
1605 SilcChannelUser chu;
1609 if (cmd->error != SILC_STATUS_OK) {
1610 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1611 "%s", silc_get_status_message(cmd->error));
1612 COMMAND_REPLY_ERROR(cmd->error);
1616 /* From protocol version 1.1 we get the channel ID of the left channel */
1617 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1619 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1623 /* Get the channel entry */
1624 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1626 silc_free(channel_id);
1627 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1631 /* Remove us from this channel. */
1632 chu = silc_client_on_channel(channel, conn->local_entry);
1634 silc_hash_table_del(chu->client->channels, chu->channel);
1635 silc_hash_table_del(chu->channel->user_list, chu->client);
1639 silc_free(channel_id);
1642 /* Notify application */
1643 COMMAND_REPLY((SILC_ARGS, channel));
1645 /* Now delete the channel. */
1647 silc_client_del_channel(cmd->client, conn, channel);
1650 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1651 silc_client_command_reply_free(cmd);
1654 /* Channel resolving callback for USERS command reply. */
1656 static void silc_client_command_reply_users_cb(SilcClient client,
1657 SilcClientConnection conn,
1658 SilcChannelEntry *channels,
1659 SilcUInt32 channels_count,
1662 if (!channels_count) {
1663 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1664 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1666 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1667 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1668 "%s", silc_get_status_message(cmd->error));
1669 COMMAND_REPLY_ERROR(cmd->error);
1670 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1671 silc_client_command_reply_free(cmd);
1675 silc_client_command_reply_users(context, NULL);
1679 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1683 SilcGetChannelCallback get_channel,
1684 SilcCommandCb get_clients)
1686 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1687 SilcChannelEntry channel;
1688 SilcClientEntry client_entry;
1689 SilcChannelUser chu;
1690 SilcChannelID *channel_id = NULL;
1691 SilcBufferStruct client_id_list, client_mode_list;
1693 SilcUInt32 tmp_len, list_count;
1695 unsigned char **res_argv = NULL;
1696 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1697 bool wait_res = FALSE;
1699 SILC_LOG_DEBUG(("Start"));
1701 /* Get channel ID */
1702 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1704 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1707 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1709 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1713 /* Get the list count */
1714 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1716 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1719 SILC_GET32_MSB(list_count, tmp);
1721 /* Get Client ID list */
1722 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1724 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1727 silc_buffer_set(&client_id_list, tmp, tmp_len);
1729 /* Get client mode list */
1730 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1732 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1735 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1737 /* Get channel entry */
1738 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1740 /* Resolve the channel from server */
1741 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1743 silc_free(channel_id);
1747 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1749 /* Cache the received Client ID's and modes. */
1750 for (i = 0; i < list_count; i++) {
1753 SilcClientID *client_id;
1756 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1758 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1763 SILC_GET32_MSB(mode, client_mode_list.data);
1765 /* Check if we have this client cached already. */
1766 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1767 if (!client_entry || !client_entry->username || !client_entry->realname) {
1769 /* No we don't have it (or it is incomplete in information), query
1770 it from the server. Assemble argument table that will be sent
1771 for the WHOIS command later. */
1772 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1774 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1776 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1778 res_argv[res_argc] = client_id_list.data;
1779 res_argv_lens[res_argc] = idp_len;
1780 res_argv_types[res_argc] = res_argc + 4;
1784 if (!silc_client_on_channel(channel, client_entry)) {
1785 chu = silc_calloc(1, sizeof(*chu));
1786 chu->client = client_entry;
1788 chu->channel = channel;
1789 silc_hash_table_add(channel->user_list, client_entry, chu);
1790 silc_hash_table_add(client_entry->channels, channel, chu);
1794 silc_free(client_id);
1795 silc_buffer_pull(&client_id_list, idp_len);
1796 silc_buffer_pull(&client_mode_list, 4);
1799 /* Query the client information from server if the list included clients
1800 that we don't know about. */
1804 /* Send the WHOIS command to server */
1805 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1806 silc_client_command_reply_whois_i, 0,
1808 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1809 res_argc, res_argv, res_argv_lens,
1810 res_argv_types, conn->cmd_ident);
1811 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1812 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1815 /* Register pending command callback. After we've received the WHOIS
1816 command reply we will reprocess this command reply by re-calling this
1817 USERS command reply callback. */
1818 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1821 silc_buffer_free(res_cmd);
1822 silc_free(channel_id);
1823 silc_free(res_argv);
1824 silc_free(res_argv_lens);
1825 silc_free(res_argv_types);
1832 silc_buffer_push(&client_id_list, (client_id_list.data -
1833 client_id_list.head));
1834 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1835 client_mode_list.head));
1837 /* Notify application */
1839 COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list,
1840 &client_mode_list));
1843 silc_free(channel_id);
1847 /* Reply to USERS command. Received list of client ID's and theirs modes
1848 on the channel we requested. */
1850 SILC_CLIENT_CMD_REPLY_FUNC(users)
1852 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1853 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1854 SilcClientCommandReplyContext r = (SilcClientCommandReplyContext)context2;
1856 SILC_LOG_DEBUG(("Start"));
1858 if (cmd->error != SILC_STATUS_OK) {
1859 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1860 "Query failed: %s", silc_get_status_message(cmd->error));
1861 COMMAND_REPLY_ERROR(cmd->error);
1865 if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) {
1866 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1867 /* Do not resolve anymore. Server may be sending us some non-existent
1868 Client ID (a bug in server), and we want to show the users list
1870 silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE,
1871 silc_client_command_reply_users_cb,
1872 silc_client_command_reply_users);
1875 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1876 "Query failed: %s", silc_get_status_message(cmd->error));
1877 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1882 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE,
1883 silc_client_command_reply_users_cb,
1884 silc_client_command_reply_users))
1888 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1889 silc_client_command_reply_free(cmd);
1892 /* Received command reply to GETKEY command. WE've received the remote
1893 client's public key. */
1895 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1897 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1898 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1899 SilcIDPayload idp = NULL;
1900 SilcClientID *client_id = NULL;
1901 SilcClientEntry client_entry;
1902 SilcServerID *server_id = NULL;
1903 SilcServerEntry server_entry;
1907 SilcPublicKey public_key = NULL;
1909 SILC_LOG_DEBUG(("Start"));
1911 if (cmd->error != SILC_STATUS_OK) {
1912 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1913 "%s", silc_get_status_message(cmd->error));
1914 COMMAND_REPLY_ERROR(cmd->error);
1918 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1920 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1923 idp = silc_id_payload_parse(tmp, len);
1925 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1929 /* Get the public key payload */
1930 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1932 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1936 id_type = silc_id_payload_get_type(idp);
1937 if (id_type == SILC_ID_CLIENT) {
1938 /* Received client's public key */
1939 client_id = silc_id_payload_get_id(idp);
1940 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1941 if (!client_entry) {
1942 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1946 /* Save fingerprint */
1947 if (!client_entry->fingerprint) {
1948 client_entry->fingerprint = silc_calloc(20, sizeof(unsigned char));
1949 client_entry->fingerprint_len = 20;
1950 silc_hash_make(cmd->client->sha1hash, tmp + 4, len - 4,
1951 client_entry->fingerprint);
1954 /* Notify application */
1955 COMMAND_REPLY((SILC_ARGS, id_type, client_entry, public_key));
1956 } else if (id_type == SILC_ID_SERVER) {
1957 /* Received server's public key */
1958 server_id = silc_id_payload_get_id(idp);
1959 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1960 if (!server_entry) {
1961 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1965 /* Notify application */
1966 COMMAND_REPLY((SILC_ARGS, id_type, server_entry, public_key));
1970 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1972 silc_id_payload_free(idp);
1974 silc_pkcs_public_key_free(public_key);
1975 silc_free(client_id);
1976 silc_free(server_id);
1977 silc_client_command_reply_free(cmd);
1980 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1982 silc_client_command_reply_free(context);
1986 /******************************************************************************
1988 Internal command reply functions
1990 ******************************************************************************/
1992 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1994 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1995 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1997 COMMAND_CHECK_STATUS_I;
1999 /* Save WHOIS info */
2000 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
2002 /* Pending callbacks are not executed if this was an list entry */
2003 if (cmd->status != SILC_STATUS_OK &&
2004 cmd->status != SILC_STATUS_LIST_END) {
2005 silc_client_command_reply_free(cmd);
2010 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
2013 /* If we received notify for invalid ID we'll remove the ID if we
2015 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2016 SilcClientEntry client_entry;
2018 unsigned char *tmp =
2019 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2022 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2024 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2027 silc_client_del_client(cmd->client, conn, client_entry);
2028 silc_free(client_id);
2033 /* Unregister this command reply */
2034 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2035 NULL, silc_client_command_reply_whois_i,
2038 silc_client_command_reply_free(cmd);
2041 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2043 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2044 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2046 COMMAND_CHECK_STATUS_I;
2048 /* Save IDENTIFY info */
2049 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
2051 /* Pending callbacks are not executed if this was an list entry */
2052 if (cmd->status != SILC_STATUS_OK &&
2053 cmd->status != SILC_STATUS_LIST_END) {
2054 silc_client_command_reply_free(cmd);
2059 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2062 /* If we received notify for invalid ID we'll remove the ID if we
2064 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2065 SilcClientEntry client_entry;
2067 unsigned char *tmp =
2068 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2071 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2073 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2076 silc_client_del_client(cmd->client, conn, client_entry);
2077 silc_free(client_id);
2082 /* Unregister this command reply */
2083 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2084 NULL, silc_client_command_reply_identify_i,
2087 silc_client_command_reply_free(cmd);
2090 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2092 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2093 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2095 SilcServerEntry server;
2096 SilcServerID *server_id = NULL;
2097 char *server_name, *server_info;
2100 COMMAND_CHECK_STATUS_I;
2103 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2107 server_id = silc_id_payload_parse_id(tmp, len, NULL);
2111 /* Get server name */
2112 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2116 /* Get server info */
2117 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2121 /* See whether we have this server cached. If not create it. */
2122 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
2124 SILC_LOG_DEBUG(("New server entry"));
2125 silc_client_add_server(cmd->client, conn, server_name, server_info,
2126 silc_id_dup(server_id, SILC_ID_SERVER));
2130 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2131 silc_free(server_id);
2133 silc_client_command_reply_free(cmd);
2136 static void silc_client_command_reply_users_i_cb(SilcClient client,
2137 SilcClientConnection conn,
2138 SilcChannelEntry *channels,
2139 SilcUInt32 channels_count,
2142 if (!channels_count) {
2143 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2144 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2146 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2147 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2148 "%s", silc_get_status_message(cmd->error));
2149 COMMAND_REPLY_ERROR(cmd->error);
2150 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2151 silc_client_command_reply_free(cmd);
2155 silc_client_command_reply_users_i(context, NULL);
2158 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2160 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2162 COMMAND_CHECK_STATUS_I;
2164 /* Save USERS info */
2165 if (silc_client_command_reply_users_save(
2166 cmd, cmd->status, FALSE, TRUE,
2167 silc_client_command_reply_users_i_cb,
2168 silc_client_command_reply_users_i))
2172 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2175 /* Unregister this command reply */
2176 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2177 NULL, silc_client_command_reply_users_i,
2180 silc_client_command_reply_free(cmd);
2183 /* Private range commands, specific to this implementation (and compatible
2184 with SILC Server >= 0.9). */
2186 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2188 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2189 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2191 if (cmd->error != SILC_STATUS_OK) {
2192 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2193 "%s", silc_get_status_message(cmd->error));
2194 COMMAND_REPLY_ERROR(cmd->error);
2198 /* Notify application */
2199 COMMAND_REPLY((SILC_ARGS));
2202 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2203 silc_client_command_reply_free(cmd);
2206 SILC_CLIENT_CMD_REPLY_FUNC(close)
2208 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2209 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2211 if (cmd->error != SILC_STATUS_OK) {
2212 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2213 "%s", silc_get_status_message(cmd->error));
2214 COMMAND_REPLY_ERROR(cmd->error);
2218 /* Notify application */
2219 COMMAND_REPLY((SILC_ARGS));
2222 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2223 silc_client_command_reply_free(cmd);
2226 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2228 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2229 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2231 if (cmd->error != SILC_STATUS_OK) {
2232 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2233 "%s", silc_get_status_message(cmd->error));
2234 COMMAND_REPLY_ERROR(cmd->error);
2238 /* Notify application */
2239 COMMAND_REPLY((SILC_ARGS));
2242 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2243 silc_client_command_reply_free(cmd);