5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2004 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);
712 silc_free(channel->topic);
713 channel->topic = silc_memdup(topic, strlen(topic));
716 /* Notify application */
717 COMMAND_REPLY((SILC_ARGS, channel, topic));
720 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
721 silc_client_command_reply_free(cmd);
724 /* Received reply to invite command. */
726 SILC_CLIENT_CMD_REPLY_FUNC(invite)
728 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
729 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
730 SilcChannelEntry channel;
731 SilcChannelID *channel_id;
734 SilcBufferStruct buf;
736 if (cmd->error != SILC_STATUS_OK) {
737 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
738 "Cannot invite: %s", silc_get_status_message(cmd->error));
739 COMMAND_REPLY_ERROR(cmd->error);
743 /* Take Channel ID */
744 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
748 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
752 /* Get the channel entry */
753 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
755 silc_free(channel_id);
756 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
760 /* Get the invite list */
761 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
763 silc_buffer_set(&buf, tmp, len);
765 /* Notify application */
766 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
769 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
770 silc_client_command_reply_free(cmd);
773 /* Received reply to the KILL command. */
775 SILC_CLIENT_CMD_REPLY_FUNC(kill)
777 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
778 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
779 SilcClientID *client_id;
780 SilcClientEntry client_entry = NULL;
782 unsigned char *id_data;
784 if (cmd->error != SILC_STATUS_OK) {
785 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
786 "Cannot kill: %s", silc_get_status_message(cmd->error));
787 COMMAND_REPLY_ERROR(cmd->error);
791 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
793 client_id = silc_id_payload_parse_id(id_data, len, NULL);
795 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
799 /* Get the client entry, if exists */
800 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
801 silc_free(client_id);
804 /* Notify application */
805 COMMAND_REPLY((SILC_ARGS, client_entry));
808 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
809 silc_client_command_reply_free(cmd);
812 /* Received reply to INFO command. We receive the server ID and some
813 information about the server user requested. */
815 SILC_CLIENT_CMD_REPLY_FUNC(info)
817 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
818 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
820 SilcServerEntry server;
821 SilcServerID *server_id = NULL;
822 char *server_name, *server_info;
825 SILC_LOG_DEBUG(("Start"));
827 if (cmd->error != SILC_STATUS_OK) {
828 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
829 silc_get_status_message(cmd->error));
830 COMMAND_REPLY_ERROR(cmd->error);
835 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
839 server_id = silc_id_payload_parse_id(tmp, len, NULL);
843 /* Get server name */
844 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
848 /* Get server info */
849 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
853 /* See whether we have this server cached. If not create it. */
854 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
856 SILC_LOG_DEBUG(("New server entry"));
857 server = silc_client_add_server(cmd->client, conn, server_name,
859 silc_id_dup(server_id, SILC_ID_SERVER));
864 /* Notify application */
865 COMMAND_REPLY((SILC_ARGS, server, server->server_name, server->server_info));
868 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
869 silc_free(server_id);
870 silc_client_command_reply_free(cmd);
873 /* Received reply to STATS command. */
875 SILC_CLIENT_CMD_REPLY_FUNC(stats)
877 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
878 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
879 unsigned char *tmp, *buf = NULL;
880 SilcUInt32 len, buf_len = 0;
882 if (cmd->error != SILC_STATUS_OK) {
883 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
884 "%s", silc_get_status_message(cmd->error));
885 COMMAND_REPLY_ERROR(cmd->error);
890 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
894 /* Get statistics structure */
895 buf = silc_argument_get_arg_type(cmd->args, 3, &buf_len);
897 /* Notify application */
898 COMMAND_REPLY((SILC_ARGS, buf, buf_len));
901 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
902 silc_client_command_reply_free(cmd);
905 /* Received reply to PING command. The reply time is shown to user. */
907 SILC_CLIENT_CMD_REPLY_FUNC(ping)
909 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
910 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
913 time_t diff, curtime;
915 if (cmd->error != SILC_STATUS_OK) {
916 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
917 "%s", silc_get_status_message(cmd->error));
918 COMMAND_REPLY_ERROR(cmd->error);
922 curtime = time(NULL);
923 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
924 cmd->packet->src_id_type);
925 if (!id || !conn->internal->ping) {
926 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
930 for (i = 0; i < conn->internal->ping_count; i++) {
931 if (!conn->internal->ping[i].dest_id)
933 if (SILC_ID_SERVER_COMPARE(conn->internal->ping[i].dest_id, id)) {
934 diff = curtime - conn->internal->ping[i].start_time;
935 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
936 "Ping reply from %s: %d second%s",
937 conn->internal->ping[i].dest_name, diff,
938 diff == 1 ? "" : "s");
940 conn->internal->ping[i].start_time = 0;
941 silc_free(conn->internal->ping[i].dest_id);
942 conn->internal->ping[i].dest_id = NULL;
943 silc_free(conn->internal->ping[i].dest_name);
944 conn->internal->ping[i].dest_name = NULL;
951 /* Notify application */
952 COMMAND_REPLY((SILC_ARGS));
955 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
956 silc_client_command_reply_free(cmd);
959 /* Received reply for JOIN command. */
961 SILC_CLIENT_CMD_REPLY_FUNC(join)
963 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
964 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
965 SilcChannelEntry channel;
967 SilcChannelID *channel_id;
968 SilcUInt32 argc, mode = 0, len, list_count;
969 char *topic, *tmp, *channel_name = NULL, *hmac;
970 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
971 SilcPublicKey founder_key = NULL;
972 SilcBufferStruct chpklist;
975 SILC_LOG_DEBUG(("Start"));
977 if (cmd->error != SILC_STATUS_OK) {
978 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
979 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
980 "Cannot join channel: %s", silc_get_status_message(cmd->error));
981 COMMAND_REPLY_ERROR(cmd->error);
985 argc = silc_argument_get_arg_num(cmd->args);
987 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
988 "Cannot join channel: Bad reply packet");
989 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
993 /* Get channel name */
994 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
996 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
997 "Cannot join channel: Bad reply packet");
998 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1003 /* Get Channel ID */
1004 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1006 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1007 "Cannot join channel: Bad reply packet");
1008 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1011 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1013 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1017 /* Get channel mode */
1018 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1020 SILC_GET32_MSB(mode, tmp);
1022 /* Get channel key */
1023 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1025 keyp = silc_buffer_alloc(len);
1026 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1027 silc_buffer_put(keyp, tmp, len);
1031 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1033 /* Check whether we have this channel entry already. */
1034 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1036 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
1037 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
1039 /* Create new channel entry */
1040 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1044 conn->current_channel = channel;
1047 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1049 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1050 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1051 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1052 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1057 /* Get the list count */
1058 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1061 SILC_GET32_MSB(list_count, tmp);
1063 /* Get Client ID list */
1064 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1068 client_id_list = silc_buffer_alloc(len);
1069 silc_buffer_pull_tail(client_id_list, len);
1070 silc_buffer_put(client_id_list, tmp, len);
1072 /* Get client mode list */
1073 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1077 client_mode_list = silc_buffer_alloc(len);
1078 silc_buffer_pull_tail(client_mode_list, len);
1079 silc_buffer_put(client_mode_list, tmp, len);
1081 /* Add clients we received in the reply to the channel */
1082 for (i = 0; i < list_count; i++) {
1085 SilcClientID *client_id;
1086 SilcClientEntry client_entry;
1089 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1091 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1096 SILC_GET32_MSB(mode, client_mode_list->data);
1098 /* Check if we have this client cached already. */
1099 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1100 if (!client_entry) {
1101 /* No, we don't have it, add entry for it. */
1103 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1104 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1107 /* Join client to the channel */
1108 if (!silc_client_on_channel(channel, client_entry)) {
1109 chu = silc_calloc(1, sizeof(*chu));
1110 chu->client = client_entry;
1111 chu->channel = channel;
1113 silc_hash_table_add(channel->user_list, client_entry, chu);
1114 silc_hash_table_add(client_entry->channels, channel, chu);
1117 silc_free(client_id);
1118 silc_buffer_pull(client_id_list, idp_len);
1119 silc_buffer_pull(client_mode_list, 4);
1121 silc_buffer_push(client_id_list, client_id_list->data -
1122 client_id_list->head);
1123 silc_buffer_push(client_mode_list, client_mode_list->data -
1124 client_mode_list->head);
1126 /* Save channel key */
1127 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1128 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1130 /* Get founder key */
1131 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
1133 silc_pkcs_public_key_payload_decode(tmp, len, &founder_key);
1135 /* Get channel public key list */
1136 tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
1138 silc_buffer_set(&chpklist, tmp, len);
1141 silc_free(channel->topic);
1142 channel->topic = silc_memdup(topic, strlen(topic));
1145 /* Notify application */
1146 COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0,
1147 keyp ? keyp->head : NULL, NULL,
1148 NULL, topic, hmac, list_count, client_id_list,
1149 client_mode_list, founder_key, tmp ? &chpklist : NULL));
1152 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1153 silc_client_command_reply_free(cmd);
1155 silc_pkcs_public_key_free(founder_key);
1156 silc_buffer_free(keyp);
1157 silc_buffer_free(client_id_list);
1158 silc_buffer_free(client_mode_list);
1161 /* Received reply for MOTD command */
1163 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1165 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1166 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1168 char *motd = NULL, *cp, line[256];
1170 if (cmd->error != SILC_STATUS_OK) {
1171 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1172 "%s", silc_get_status_message(cmd->error));
1173 COMMAND_REPLY_ERROR(cmd->error);
1177 argc = silc_argument_get_arg_num(cmd->args);
1179 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1184 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1186 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1193 if (cp[i++] == '\n') {
1194 memset(line, 0, sizeof(line));
1195 silc_strncat(line, sizeof(line), cp, i - 1);
1201 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1210 /* Notify application */
1211 COMMAND_REPLY((SILC_ARGS, motd));
1214 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1215 silc_client_command_reply_free(cmd);
1218 /* Received reply tot he UMODE command. Save the current user mode */
1220 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1222 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1223 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1227 if (cmd->error != SILC_STATUS_OK) {
1228 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1229 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1230 COMMAND_REPLY_ERROR(cmd->error);
1234 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1236 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1240 SILC_GET32_MSB(mode, tmp);
1241 conn->local_entry->mode = mode;
1243 /* Notify application */
1244 COMMAND_REPLY((SILC_ARGS, mode));
1247 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1248 silc_client_command_reply_free(cmd);
1251 /* Received reply for CMODE command. */
1253 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1255 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1256 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1259 SilcChannelID *channel_id;
1260 SilcChannelEntry channel;
1262 SilcPublicKey public_key = NULL;
1263 SilcBufferStruct channel_pubkeys;
1265 if (cmd->error != SILC_STATUS_OK) {
1266 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1267 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1268 COMMAND_REPLY_ERROR(cmd->error);
1272 /* Take Channel ID */
1273 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1276 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1280 /* Get the channel entry */
1281 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1283 silc_free(channel_id);
1284 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1288 /* Get channel mode */
1289 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1291 silc_free(channel_id);
1292 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1297 SILC_GET32_MSB(mode, tmp);
1298 channel->mode = mode;
1300 /* Get founder public key */
1301 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
1303 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1307 /* Get channel public key(s) */
1308 tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
1310 silc_buffer_set(&channel_pubkeys, tmp, len);
1312 /* Notify application */
1313 COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
1314 tmp ? &channel_pubkeys : NULL));
1316 silc_free(channel_id);
1320 silc_pkcs_public_key_free(public_key);
1321 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1322 silc_client_command_reply_free(cmd);
1325 /* Received reply for CUMODE command */
1327 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1329 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1330 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1331 SilcClientID *client_id;
1332 SilcChannelID *channel_id;
1333 SilcClientEntry client_entry;
1334 SilcChannelEntry channel;
1335 SilcChannelUser chu;
1336 unsigned char *modev, *tmp, *id;
1337 SilcUInt32 len, mode;
1339 if (cmd->error != SILC_STATUS_OK) {
1340 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1341 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1342 COMMAND_REPLY_ERROR(cmd->error);
1346 /* Get channel mode */
1347 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1349 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1353 /* Take Channel ID */
1354 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1357 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1361 /* Get the channel entry */
1362 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1364 silc_free(channel_id);
1365 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1370 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1372 silc_free(channel_id);
1373 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1376 client_id = silc_id_payload_parse_id(id, len, NULL);
1378 silc_free(channel_id);
1379 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1383 /* Get client entry */
1384 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1385 if (!client_entry) {
1386 silc_free(channel_id);
1387 silc_free(client_id);
1388 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1393 SILC_GET32_MSB(mode, modev);
1394 chu = silc_client_on_channel(channel, client_entry);
1398 /* Notify application */
1399 COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry));
1400 silc_free(client_id);
1401 silc_free(channel_id);
1404 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1405 silc_client_command_reply_free(cmd);
1408 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1410 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1411 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1412 SilcClientID *client_id = NULL;
1413 SilcChannelID *channel_id = NULL;
1414 SilcClientEntry client_entry = NULL;
1415 SilcChannelEntry channel = NULL;
1419 if (cmd->error != SILC_STATUS_OK) {
1420 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1421 "Cannot kick: %s", silc_get_status_message(cmd->error));
1422 COMMAND_REPLY_ERROR(cmd->error);
1426 /* Take Channel ID */
1427 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1429 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1431 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1435 /* Get the channel entry */
1436 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1438 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1444 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1446 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1448 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1452 /* Get client entry */
1453 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1454 if (!client_entry) {
1455 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1460 /* Notify application */
1461 COMMAND_REPLY((SILC_ARGS, channel, client_entry));
1464 silc_free(channel_id);
1465 silc_free(client_id);
1466 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1467 silc_client_command_reply_free(cmd);
1470 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1472 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1473 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1475 if (cmd->error != SILC_STATUS_OK) {
1476 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1477 "%s", silc_get_status_message(cmd->error));
1478 COMMAND_REPLY_ERROR(cmd->error);
1482 /* Notify application */
1483 COMMAND_REPLY((SILC_ARGS));
1486 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1487 silc_client_command_reply_free(cmd);
1490 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1492 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1493 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1495 if (cmd->error != SILC_STATUS_OK) {
1496 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1497 "%s", silc_get_status_message(cmd->error));
1498 COMMAND_REPLY_ERROR(cmd->error);
1502 /* Notify application */
1503 COMMAND_REPLY((SILC_ARGS));
1506 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1507 silc_client_command_reply_free(cmd);
1510 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1512 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1513 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1516 if (cmd->error != SILC_STATUS_OK) {
1517 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1518 "%s", silc_get_status_message(cmd->error));
1519 COMMAND_REPLY_ERROR(cmd->error);
1523 /* Notify application */
1524 COMMAND_REPLY((SILC_ARGS));
1526 /* Generate the detachment data and deliver it to the client in the
1527 detach client operation */
1528 detach = silc_client_get_detach_data(cmd->client, conn);
1530 cmd->client->internal->ops->detach(cmd->client, conn,
1531 detach->data, detach->len);
1532 silc_buffer_free(detach);
1536 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1537 silc_client_command_reply_free(cmd);
1540 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1542 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1543 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1545 if (cmd->error != SILC_STATUS_OK) {
1546 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1547 "%s", silc_get_status_message(cmd->error));
1548 COMMAND_REPLY_ERROR(cmd->error);
1552 /* Notify application */
1553 COMMAND_REPLY((SILC_ARGS));
1556 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1557 silc_client_command_reply_free(cmd);
1560 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1562 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1563 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1564 SilcChannelEntry channel;
1565 SilcChannelID *channel_id;
1568 SilcBufferStruct buf;
1570 if (cmd->error != SILC_STATUS_OK) {
1571 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1572 "%s", silc_get_status_message(cmd->error));
1573 COMMAND_REPLY_ERROR(cmd->error);
1577 /* Take Channel ID */
1578 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1582 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1586 /* Get the channel entry */
1587 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1589 silc_free(channel_id);
1590 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1594 /* Get the ban list */
1595 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1597 silc_buffer_set(&buf, tmp, len);
1599 /* Notify application */
1600 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
1603 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1604 silc_client_command_reply_free(cmd);
1607 /* Reply to LEAVE command. */
1609 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1611 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1612 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1613 SilcChannelID *channel_id;
1614 SilcChannelEntry channel = NULL;
1615 SilcChannelUser chu;
1619 if (cmd->error != SILC_STATUS_OK) {
1620 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1621 "%s", silc_get_status_message(cmd->error));
1622 COMMAND_REPLY_ERROR(cmd->error);
1626 /* From protocol version 1.1 we get the channel ID of the left channel */
1627 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1629 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1633 /* Get the channel entry */
1634 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1636 silc_free(channel_id);
1637 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1641 /* Remove us from this channel. */
1642 chu = silc_client_on_channel(channel, conn->local_entry);
1644 silc_hash_table_del(chu->client->channels, chu->channel);
1645 silc_hash_table_del(chu->channel->user_list, chu->client);
1649 silc_free(channel_id);
1652 /* Notify application */
1653 COMMAND_REPLY((SILC_ARGS, channel));
1655 /* Now delete the channel. */
1657 silc_client_del_channel(cmd->client, conn, channel);
1660 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1661 silc_client_command_reply_free(cmd);
1664 /* Channel resolving callback for USERS command reply. */
1666 static void silc_client_command_reply_users_cb(SilcClient client,
1667 SilcClientConnection conn,
1668 SilcChannelEntry *channels,
1669 SilcUInt32 channels_count,
1672 if (!channels_count) {
1673 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1674 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1676 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1677 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1678 "%s", silc_get_status_message(cmd->error));
1679 COMMAND_REPLY_ERROR(cmd->error);
1680 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1681 silc_client_command_reply_free(cmd);
1685 silc_client_command_reply_users(context, NULL);
1689 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1693 SilcGetChannelCallback get_channel,
1694 SilcCommandCb get_clients)
1696 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1697 SilcChannelEntry channel;
1698 SilcClientEntry client_entry;
1699 SilcChannelUser chu;
1700 SilcChannelID *channel_id = NULL;
1701 SilcBufferStruct client_id_list, client_mode_list;
1703 SilcUInt32 tmp_len, list_count;
1705 unsigned char **res_argv = NULL;
1706 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1707 bool wait_res = FALSE;
1709 SILC_LOG_DEBUG(("Start"));
1711 /* Get channel ID */
1712 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1714 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1717 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1719 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1723 /* Get the list count */
1724 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1726 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1729 SILC_GET32_MSB(list_count, tmp);
1731 /* Get Client ID list */
1732 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1734 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1737 silc_buffer_set(&client_id_list, tmp, tmp_len);
1739 /* Get client mode list */
1740 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1742 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1745 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1747 /* Get channel entry */
1748 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1750 /* Resolve the channel from server */
1751 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1753 silc_free(channel_id);
1757 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1759 /* Cache the received Client ID's and modes. */
1760 for (i = 0; i < list_count; i++) {
1763 SilcClientID *client_id;
1766 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1768 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1773 SILC_GET32_MSB(mode, client_mode_list.data);
1775 /* Check if we have this client cached already. */
1776 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1777 if (!client_entry || !client_entry->username || !client_entry->realname) {
1779 /* No we don't have it (or it is incomplete in information), query
1780 it from the server. Assemble argument table that will be sent
1781 for the WHOIS command later. */
1782 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1784 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1786 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1788 res_argv[res_argc] = client_id_list.data;
1789 res_argv_lens[res_argc] = idp_len;
1790 res_argv_types[res_argc] = res_argc + 4;
1794 if (!silc_client_on_channel(channel, client_entry)) {
1795 chu = silc_calloc(1, sizeof(*chu));
1796 chu->client = client_entry;
1798 chu->channel = channel;
1799 silc_hash_table_add(channel->user_list, client_entry, chu);
1800 silc_hash_table_add(client_entry->channels, channel, chu);
1804 silc_free(client_id);
1805 silc_buffer_pull(&client_id_list, idp_len);
1806 silc_buffer_pull(&client_mode_list, 4);
1809 /* Query the client information from server if the list included clients
1810 that we don't know about. */
1814 /* Send the WHOIS command to server */
1815 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1816 silc_client_command_reply_whois_i, 0,
1818 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1819 res_argc, res_argv, res_argv_lens,
1820 res_argv_types, conn->cmd_ident);
1821 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1822 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1825 /* Register pending command callback. After we've received the WHOIS
1826 command reply we will reprocess this command reply by re-calling this
1827 USERS command reply callback. */
1828 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1831 silc_buffer_free(res_cmd);
1832 silc_free(channel_id);
1833 silc_free(res_argv);
1834 silc_free(res_argv_lens);
1835 silc_free(res_argv_types);
1842 silc_buffer_push(&client_id_list, (client_id_list.data -
1843 client_id_list.head));
1844 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1845 client_mode_list.head));
1847 /* Notify application */
1849 COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list,
1850 &client_mode_list));
1853 silc_free(channel_id);
1857 /* Reply to USERS command. Received list of client ID's and theirs modes
1858 on the channel we requested. */
1860 SILC_CLIENT_CMD_REPLY_FUNC(users)
1862 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1863 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1864 SilcClientCommandReplyContext r = (SilcClientCommandReplyContext)context2;
1866 SILC_LOG_DEBUG(("Start"));
1868 if (cmd->error != SILC_STATUS_OK) {
1869 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1870 "Query failed: %s", silc_get_status_message(cmd->error));
1871 COMMAND_REPLY_ERROR(cmd->error);
1875 if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) {
1876 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1877 /* Do not resolve anymore. Server may be sending us some non-existent
1878 Client ID (a bug in server), and we want to show the users list
1880 silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE,
1881 silc_client_command_reply_users_cb,
1882 silc_client_command_reply_users);
1885 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1886 "Query failed: %s", silc_get_status_message(cmd->error));
1887 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1892 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE,
1893 silc_client_command_reply_users_cb,
1894 silc_client_command_reply_users))
1898 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1899 silc_client_command_reply_free(cmd);
1902 /* Received command reply to GETKEY command. WE've received the remote
1903 client's public key. */
1905 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1907 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1908 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1909 SilcIDPayload idp = NULL;
1910 SilcClientID *client_id = NULL;
1911 SilcClientEntry client_entry;
1912 SilcServerID *server_id = NULL;
1913 SilcServerEntry server_entry;
1917 SilcPublicKey public_key = NULL;
1919 SILC_LOG_DEBUG(("Start"));
1921 if (cmd->error != SILC_STATUS_OK) {
1922 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1923 "%s", silc_get_status_message(cmd->error));
1924 COMMAND_REPLY_ERROR(cmd->error);
1928 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1930 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1933 idp = silc_id_payload_parse(tmp, len);
1935 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1939 /* Get the public key payload */
1940 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1942 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1946 id_type = silc_id_payload_get_type(idp);
1947 if (id_type == SILC_ID_CLIENT) {
1948 /* Received client's public key */
1949 client_id = silc_id_payload_get_id(idp);
1950 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1951 if (!client_entry) {
1952 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1956 /* Save fingerprint */
1957 if (!client_entry->fingerprint) {
1958 client_entry->fingerprint = silc_calloc(20, sizeof(unsigned char));
1959 client_entry->fingerprint_len = 20;
1960 silc_hash_make(cmd->client->sha1hash, tmp + 4, len - 4,
1961 client_entry->fingerprint);
1964 /* Notify application */
1965 COMMAND_REPLY((SILC_ARGS, id_type, client_entry, public_key));
1966 } else if (id_type == SILC_ID_SERVER) {
1967 /* Received server's public key */
1968 server_id = silc_id_payload_get_id(idp);
1969 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1970 if (!server_entry) {
1971 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1975 /* Notify application */
1976 COMMAND_REPLY((SILC_ARGS, id_type, server_entry, public_key));
1980 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1982 silc_id_payload_free(idp);
1984 silc_pkcs_public_key_free(public_key);
1985 silc_free(client_id);
1986 silc_free(server_id);
1987 silc_client_command_reply_free(cmd);
1990 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1992 silc_client_command_reply_free(context);
1996 /******************************************************************************
1998 Internal command reply functions
2000 ******************************************************************************/
2002 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
2004 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2005 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2007 COMMAND_CHECK_STATUS_I;
2009 /* Save WHOIS info */
2010 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
2012 /* Pending callbacks are not executed if this was an list entry */
2013 if (cmd->status != SILC_STATUS_OK &&
2014 cmd->status != SILC_STATUS_LIST_END) {
2015 silc_client_command_reply_free(cmd);
2020 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
2023 /* If we received notify for invalid ID we'll remove the ID if we
2025 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2026 SilcClientEntry client_entry;
2028 unsigned char *tmp =
2029 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2032 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2034 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2037 silc_client_del_client(cmd->client, conn, client_entry);
2038 silc_free(client_id);
2043 /* Unregister this command reply */
2044 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2045 NULL, silc_client_command_reply_whois_i,
2048 silc_client_command_reply_free(cmd);
2051 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2053 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2054 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2056 COMMAND_CHECK_STATUS_I;
2058 /* Save IDENTIFY info */
2059 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
2061 /* Pending callbacks are not executed if this was an list entry */
2062 if (cmd->status != SILC_STATUS_OK &&
2063 cmd->status != SILC_STATUS_LIST_END) {
2064 silc_client_command_reply_free(cmd);
2069 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2072 /* If we received notify for invalid ID we'll remove the ID if we
2074 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2075 SilcClientEntry client_entry;
2077 unsigned char *tmp =
2078 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2081 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2083 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2086 silc_client_del_client(cmd->client, conn, client_entry);
2087 silc_free(client_id);
2092 /* Unregister this command reply */
2093 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2094 NULL, silc_client_command_reply_identify_i,
2097 silc_client_command_reply_free(cmd);
2100 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2102 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2103 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2105 SilcServerEntry server;
2106 SilcServerID *server_id = NULL;
2107 char *server_name, *server_info;
2110 COMMAND_CHECK_STATUS_I;
2113 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2117 server_id = silc_id_payload_parse_id(tmp, len, NULL);
2121 /* Get server name */
2122 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2126 /* Get server info */
2127 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2131 /* See whether we have this server cached. If not create it. */
2132 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
2134 SILC_LOG_DEBUG(("New server entry"));
2135 silc_client_add_server(cmd->client, conn, server_name, server_info,
2136 silc_id_dup(server_id, SILC_ID_SERVER));
2140 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2141 silc_free(server_id);
2143 silc_client_command_reply_free(cmd);
2146 static void silc_client_command_reply_users_i_cb(SilcClient client,
2147 SilcClientConnection conn,
2148 SilcChannelEntry *channels,
2149 SilcUInt32 channels_count,
2152 if (!channels_count) {
2153 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2154 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2156 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2157 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2158 "%s", silc_get_status_message(cmd->error));
2159 COMMAND_REPLY_ERROR(cmd->error);
2160 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2161 silc_client_command_reply_free(cmd);
2165 silc_client_command_reply_users_i(context, NULL);
2168 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2170 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2172 COMMAND_CHECK_STATUS_I;
2174 /* Save USERS info */
2175 if (silc_client_command_reply_users_save(
2176 cmd, cmd->status, FALSE, TRUE,
2177 silc_client_command_reply_users_i_cb,
2178 silc_client_command_reply_users_i))
2182 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2185 /* Unregister this command reply */
2186 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2187 NULL, silc_client_command_reply_users_i,
2190 silc_client_command_reply_free(cmd);
2193 /* Private range commands, specific to this implementation (and compatible
2194 with SILC Server >= 0.9). */
2196 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2198 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2199 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2201 if (cmd->error != SILC_STATUS_OK) {
2202 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2203 "%s", silc_get_status_message(cmd->error));
2204 COMMAND_REPLY_ERROR(cmd->error);
2208 /* Notify application */
2209 COMMAND_REPLY((SILC_ARGS));
2212 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2213 silc_client_command_reply_free(cmd);
2216 SILC_CLIENT_CMD_REPLY_FUNC(close)
2218 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2219 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2221 if (cmd->error != SILC_STATUS_OK) {
2222 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2223 "%s", silc_get_status_message(cmd->error));
2224 COMMAND_REPLY_ERROR(cmd->error);
2228 /* Notify application */
2229 COMMAND_REPLY((SILC_ARGS));
2232 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2233 silc_client_command_reply_free(cmd);
2236 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2238 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2239 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2241 if (cmd->error != SILC_STATUS_OK) {
2242 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2243 "%s", silc_get_status_message(cmd->error));
2244 COMMAND_REPLY_ERROR(cmd->error);
2248 /* Notify application */
2249 COMMAND_REPLY((SILC_ARGS));
2252 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2253 silc_client_command_reply_free(cmd);