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 SilcBufferStruct chpklist;
974 SILC_LOG_DEBUG(("Start"));
976 if (cmd->error != SILC_STATUS_OK) {
977 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
978 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
979 "Cannot join channel: %s", silc_get_status_message(cmd->error));
980 COMMAND_REPLY_ERROR(cmd->error);
984 argc = silc_argument_get_arg_num(cmd->args);
986 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
987 "Cannot join channel: Bad reply packet");
988 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
992 /* Get channel name */
993 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
995 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
996 "Cannot join channel: Bad reply packet");
997 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1002 /* Get Channel ID */
1003 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1005 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1006 "Cannot join channel: Bad reply packet");
1007 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1010 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1012 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1016 /* Get channel mode */
1017 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1019 SILC_GET32_MSB(mode, tmp);
1021 /* Get channel key */
1022 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1024 keyp = silc_buffer_alloc(len);
1025 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1026 silc_buffer_put(keyp, tmp, len);
1030 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1032 /* Check whether we have this channel entry already. */
1033 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1035 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
1036 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
1038 /* Create new channel entry */
1039 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1043 conn->current_channel = channel;
1044 channel->mode = mode;
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 */
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 if (channel->founder_key)
1134 silc_pkcs_public_key_free(channel->founder_key);
1135 channel->founder_key = NULL;
1136 silc_pkcs_public_key_payload_decode(tmp, len, &channel->founder_key);
1139 /* Get channel public key list */
1140 tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
1142 silc_buffer_set(&chpklist, tmp, len);
1145 silc_free(channel->topic);
1146 channel->topic = silc_memdup(topic, strlen(topic));
1149 /* Notify application */
1150 COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0,
1151 keyp ? keyp->head : NULL, NULL,
1152 NULL, topic, hmac, list_count, client_id_list,
1153 client_mode_list, channel->founder_key,
1154 tmp ? &chpklist : NULL));
1157 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1158 silc_client_command_reply_free(cmd);
1159 silc_buffer_free(keyp);
1160 silc_buffer_free(client_id_list);
1161 silc_buffer_free(client_mode_list);
1164 /* Received reply for MOTD command */
1166 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1168 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1169 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1171 char *motd = NULL, *cp, line[256];
1173 if (cmd->error != SILC_STATUS_OK) {
1174 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1175 "%s", silc_get_status_message(cmd->error));
1176 COMMAND_REPLY_ERROR(cmd->error);
1180 argc = silc_argument_get_arg_num(cmd->args);
1182 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1187 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1189 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1196 if (cp[i++] == '\n') {
1197 memset(line, 0, sizeof(line));
1198 silc_strncat(line, sizeof(line), cp, i - 1);
1204 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1213 /* Notify application */
1214 COMMAND_REPLY((SILC_ARGS, motd));
1217 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1218 silc_client_command_reply_free(cmd);
1221 /* Received reply tot he UMODE command. Save the current user mode */
1223 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1225 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1226 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1230 if (cmd->error != SILC_STATUS_OK) {
1231 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1232 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1233 COMMAND_REPLY_ERROR(cmd->error);
1237 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1239 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1243 SILC_GET32_MSB(mode, tmp);
1244 conn->local_entry->mode = mode;
1246 /* Notify application */
1247 COMMAND_REPLY((SILC_ARGS, mode));
1250 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1251 silc_client_command_reply_free(cmd);
1254 /* Received reply for CMODE command. */
1256 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1258 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1259 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1262 SilcChannelID *channel_id;
1263 SilcChannelEntry channel;
1265 SilcPublicKey public_key = NULL;
1266 SilcBufferStruct channel_pubkeys;
1268 if (cmd->error != SILC_STATUS_OK) {
1269 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1270 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1271 COMMAND_REPLY_ERROR(cmd->error);
1275 /* Take Channel ID */
1276 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1279 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1283 /* Get the channel entry */
1284 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1286 silc_free(channel_id);
1287 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1291 /* Get channel mode */
1292 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1294 silc_free(channel_id);
1295 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1300 SILC_GET32_MSB(mode, tmp);
1301 channel->mode = mode;
1303 /* Get founder public key */
1304 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
1306 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1310 /* Get channel public key(s) */
1311 tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
1313 silc_buffer_set(&channel_pubkeys, tmp, len);
1315 /* Notify application */
1316 COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
1317 tmp ? &channel_pubkeys : NULL));
1319 silc_free(channel_id);
1323 silc_pkcs_public_key_free(public_key);
1324 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1325 silc_client_command_reply_free(cmd);
1328 /* Received reply for CUMODE command */
1330 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1332 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1333 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1334 SilcClientID *client_id;
1335 SilcChannelID *channel_id;
1336 SilcClientEntry client_entry;
1337 SilcChannelEntry channel;
1338 SilcChannelUser chu;
1339 unsigned char *modev, *tmp, *id;
1340 SilcUInt32 len, mode;
1342 if (cmd->error != SILC_STATUS_OK) {
1343 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1344 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1345 COMMAND_REPLY_ERROR(cmd->error);
1349 /* Get channel mode */
1350 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1352 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1356 /* Take Channel ID */
1357 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1360 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1364 /* Get the channel entry */
1365 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1367 silc_free(channel_id);
1368 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1373 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1375 silc_free(channel_id);
1376 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1379 client_id = silc_id_payload_parse_id(id, len, NULL);
1381 silc_free(channel_id);
1382 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1386 /* Get client entry */
1387 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1388 if (!client_entry) {
1389 silc_free(channel_id);
1390 silc_free(client_id);
1391 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1396 SILC_GET32_MSB(mode, modev);
1397 chu = silc_client_on_channel(channel, client_entry);
1401 /* Notify application */
1402 COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry));
1403 silc_free(client_id);
1404 silc_free(channel_id);
1407 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1408 silc_client_command_reply_free(cmd);
1411 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1413 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1414 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1415 SilcClientID *client_id = NULL;
1416 SilcChannelID *channel_id = NULL;
1417 SilcClientEntry client_entry = NULL;
1418 SilcChannelEntry channel = NULL;
1422 if (cmd->error != SILC_STATUS_OK) {
1423 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1424 "Cannot kick: %s", silc_get_status_message(cmd->error));
1425 COMMAND_REPLY_ERROR(cmd->error);
1429 /* Take Channel ID */
1430 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1432 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1434 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1438 /* Get the channel entry */
1439 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1441 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1447 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1449 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1451 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1455 /* Get client entry */
1456 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1457 if (!client_entry) {
1458 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1463 /* Notify application */
1464 COMMAND_REPLY((SILC_ARGS, channel, client_entry));
1467 silc_free(channel_id);
1468 silc_free(client_id);
1469 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1470 silc_client_command_reply_free(cmd);
1473 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1475 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1476 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1478 if (cmd->error != SILC_STATUS_OK) {
1479 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1480 "%s", silc_get_status_message(cmd->error));
1481 COMMAND_REPLY_ERROR(cmd->error);
1485 /* Notify application */
1486 COMMAND_REPLY((SILC_ARGS));
1489 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1490 silc_client_command_reply_free(cmd);
1493 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1495 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1496 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1498 if (cmd->error != SILC_STATUS_OK) {
1499 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1500 "%s", silc_get_status_message(cmd->error));
1501 COMMAND_REPLY_ERROR(cmd->error);
1505 /* Notify application */
1506 COMMAND_REPLY((SILC_ARGS));
1509 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1510 silc_client_command_reply_free(cmd);
1513 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1515 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1516 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1519 if (cmd->error != SILC_STATUS_OK) {
1520 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1521 "%s", silc_get_status_message(cmd->error));
1522 COMMAND_REPLY_ERROR(cmd->error);
1526 /* Notify application */
1527 COMMAND_REPLY((SILC_ARGS));
1529 /* Generate the detachment data and deliver it to the client in the
1530 detach client operation */
1531 detach = silc_client_get_detach_data(cmd->client, conn);
1533 cmd->client->internal->ops->detach(cmd->client, conn,
1534 detach->data, detach->len);
1535 silc_buffer_free(detach);
1539 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1540 silc_client_command_reply_free(cmd);
1543 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1545 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1546 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1548 if (cmd->error != SILC_STATUS_OK) {
1549 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1550 "%s", silc_get_status_message(cmd->error));
1551 COMMAND_REPLY_ERROR(cmd->error);
1555 /* Notify application */
1556 COMMAND_REPLY((SILC_ARGS));
1559 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1560 silc_client_command_reply_free(cmd);
1563 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1565 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1566 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1567 SilcChannelEntry channel;
1568 SilcChannelID *channel_id;
1571 SilcBufferStruct buf;
1573 if (cmd->error != SILC_STATUS_OK) {
1574 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1575 "%s", silc_get_status_message(cmd->error));
1576 COMMAND_REPLY_ERROR(cmd->error);
1580 /* Take Channel ID */
1581 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1585 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1589 /* Get the channel entry */
1590 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1592 silc_free(channel_id);
1593 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1597 /* Get the ban list */
1598 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1600 silc_buffer_set(&buf, tmp, len);
1602 /* Notify application */
1603 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
1606 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1607 silc_client_command_reply_free(cmd);
1610 /* Reply to LEAVE command. */
1612 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1614 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1615 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1616 SilcChannelID *channel_id;
1617 SilcChannelEntry channel = NULL;
1618 SilcChannelUser chu;
1622 if (cmd->error != SILC_STATUS_OK) {
1623 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1624 "%s", silc_get_status_message(cmd->error));
1625 COMMAND_REPLY_ERROR(cmd->error);
1629 /* From protocol version 1.1 we get the channel ID of the left channel */
1630 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1632 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1636 /* Get the channel entry */
1637 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1639 silc_free(channel_id);
1640 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1644 /* Remove us from this channel. */
1645 chu = silc_client_on_channel(channel, conn->local_entry);
1647 silc_hash_table_del(chu->client->channels, chu->channel);
1648 silc_hash_table_del(chu->channel->user_list, chu->client);
1652 silc_free(channel_id);
1655 /* Notify application */
1656 COMMAND_REPLY((SILC_ARGS, channel));
1658 /* Now delete the channel. */
1660 silc_client_del_channel(cmd->client, conn, channel);
1663 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1664 silc_client_command_reply_free(cmd);
1667 /* Channel resolving callback for USERS command reply. */
1669 static void silc_client_command_reply_users_cb(SilcClient client,
1670 SilcClientConnection conn,
1671 SilcChannelEntry *channels,
1672 SilcUInt32 channels_count,
1675 if (!channels_count) {
1676 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1677 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1679 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1680 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1681 "%s", silc_get_status_message(cmd->error));
1682 COMMAND_REPLY_ERROR(cmd->error);
1683 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1684 silc_client_command_reply_free(cmd);
1688 silc_client_command_reply_users(context, NULL);
1692 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1696 SilcGetChannelCallback get_channel,
1697 SilcCommandCb get_clients)
1699 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1700 SilcChannelEntry channel;
1701 SilcClientEntry client_entry;
1702 SilcChannelUser chu;
1703 SilcChannelID *channel_id = NULL;
1704 SilcBufferStruct client_id_list, client_mode_list;
1706 SilcUInt32 tmp_len, list_count;
1708 unsigned char **res_argv = NULL;
1709 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1710 bool wait_res = FALSE;
1712 SILC_LOG_DEBUG(("Start"));
1714 /* Get channel ID */
1715 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1717 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1720 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1722 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1726 /* Get the list count */
1727 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1729 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1732 SILC_GET32_MSB(list_count, tmp);
1734 /* Get Client ID list */
1735 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1737 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1740 silc_buffer_set(&client_id_list, tmp, tmp_len);
1742 /* Get client mode list */
1743 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1745 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1748 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1750 /* Get channel entry */
1751 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1753 /* Resolve the channel from server */
1754 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1756 silc_free(channel_id);
1760 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1762 /* Cache the received Client ID's and modes. */
1763 for (i = 0; i < list_count; i++) {
1766 SilcClientID *client_id;
1769 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1771 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1776 SILC_GET32_MSB(mode, client_mode_list.data);
1778 /* Check if we have this client cached already. */
1779 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1780 if (!client_entry || !client_entry->username || !client_entry->realname) {
1782 /* No we don't have it (or it is incomplete in information), query
1783 it from the server. Assemble argument table that will be sent
1784 for the WHOIS command later. */
1785 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1787 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1789 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1791 res_argv[res_argc] = client_id_list.data;
1792 res_argv_lens[res_argc] = idp_len;
1793 res_argv_types[res_argc] = res_argc + 4;
1797 if (!silc_client_on_channel(channel, client_entry)) {
1798 chu = silc_calloc(1, sizeof(*chu));
1799 chu->client = client_entry;
1801 chu->channel = channel;
1802 silc_hash_table_add(channel->user_list, client_entry, chu);
1803 silc_hash_table_add(client_entry->channels, channel, chu);
1807 silc_free(client_id);
1808 silc_buffer_pull(&client_id_list, idp_len);
1809 silc_buffer_pull(&client_mode_list, 4);
1812 /* Query the client information from server if the list included clients
1813 that we don't know about. */
1817 /* Send the WHOIS command to server */
1818 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1819 silc_client_command_reply_whois_i, 0,
1821 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1822 res_argc, res_argv, res_argv_lens,
1823 res_argv_types, conn->cmd_ident);
1824 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1825 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1828 /* Register pending command callback. After we've received the WHOIS
1829 command reply we will reprocess this command reply by re-calling this
1830 USERS command reply callback. */
1831 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1834 silc_buffer_free(res_cmd);
1835 silc_free(channel_id);
1836 silc_free(res_argv);
1837 silc_free(res_argv_lens);
1838 silc_free(res_argv_types);
1845 silc_buffer_push(&client_id_list, (client_id_list.data -
1846 client_id_list.head));
1847 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1848 client_mode_list.head));
1850 /* Notify application */
1852 COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list,
1853 &client_mode_list));
1856 silc_free(channel_id);
1860 /* Reply to USERS command. Received list of client ID's and theirs modes
1861 on the channel we requested. */
1863 SILC_CLIENT_CMD_REPLY_FUNC(users)
1865 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1866 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1867 SilcClientCommandReplyContext r = (SilcClientCommandReplyContext)context2;
1869 SILC_LOG_DEBUG(("Start"));
1871 if (cmd->error != SILC_STATUS_OK) {
1872 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1873 "Query failed: %s", silc_get_status_message(cmd->error));
1874 COMMAND_REPLY_ERROR(cmd->error);
1878 if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) {
1879 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1880 /* Do not resolve anymore. Server may be sending us some non-existent
1881 Client ID (a bug in server), and we want to show the users list
1883 silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE,
1884 silc_client_command_reply_users_cb,
1885 silc_client_command_reply_users);
1888 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1889 "Query failed: %s", silc_get_status_message(cmd->error));
1890 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1895 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE,
1896 silc_client_command_reply_users_cb,
1897 silc_client_command_reply_users))
1901 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1902 silc_client_command_reply_free(cmd);
1905 /* Received command reply to GETKEY command. WE've received the remote
1906 client's public key. */
1908 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1910 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1911 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1912 SilcIDPayload idp = NULL;
1913 SilcClientID *client_id = NULL;
1914 SilcClientEntry client_entry;
1915 SilcServerID *server_id = NULL;
1916 SilcServerEntry server_entry;
1920 SilcPublicKey public_key = NULL;
1922 SILC_LOG_DEBUG(("Start"));
1924 if (cmd->error != SILC_STATUS_OK) {
1925 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1926 "%s", silc_get_status_message(cmd->error));
1927 COMMAND_REPLY_ERROR(cmd->error);
1931 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1933 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1936 idp = silc_id_payload_parse(tmp, len);
1938 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1942 /* Get the public key payload */
1943 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1945 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1949 id_type = silc_id_payload_get_type(idp);
1950 if (id_type == SILC_ID_CLIENT) {
1951 /* Received client's public key */
1952 client_id = silc_id_payload_get_id(idp);
1953 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1954 if (!client_entry) {
1955 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1959 /* Save fingerprint */
1960 if (!client_entry->fingerprint) {
1961 client_entry->fingerprint = silc_calloc(20, sizeof(unsigned char));
1962 client_entry->fingerprint_len = 20;
1963 silc_hash_make(cmd->client->sha1hash, tmp + 4, len - 4,
1964 client_entry->fingerprint);
1966 if (!client_entry->public_key) {
1967 client_entry->public_key = public_key;
1971 /* Notify application */
1972 COMMAND_REPLY((SILC_ARGS, id_type, client_entry,
1973 client_entry->public_key));
1974 } else if (id_type == SILC_ID_SERVER) {
1975 /* Received server's public key */
1976 server_id = silc_id_payload_get_id(idp);
1977 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1978 if (!server_entry) {
1979 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1983 /* Notify application */
1984 COMMAND_REPLY((SILC_ARGS, id_type, server_entry, public_key));
1988 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1990 silc_id_payload_free(idp);
1992 silc_pkcs_public_key_free(public_key);
1993 silc_free(client_id);
1994 silc_free(server_id);
1995 silc_client_command_reply_free(cmd);
1998 SILC_CLIENT_CMD_REPLY_FUNC(quit)
2000 silc_client_command_reply_free(context);
2004 /******************************************************************************
2006 Internal command reply functions
2008 ******************************************************************************/
2010 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
2012 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2013 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2015 COMMAND_CHECK_STATUS_I;
2017 /* Save WHOIS info */
2018 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
2020 /* Pending callbacks are not executed if this was an list entry */
2021 if (cmd->status != SILC_STATUS_OK &&
2022 cmd->status != SILC_STATUS_LIST_END) {
2023 silc_client_command_reply_free(cmd);
2028 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
2031 /* If we received notify for invalid ID we'll remove the ID if we
2033 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2034 SilcClientEntry client_entry;
2036 unsigned char *tmp =
2037 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2040 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2042 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2045 silc_client_del_client(cmd->client, conn, client_entry);
2046 silc_free(client_id);
2051 /* Unregister this command reply */
2052 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2053 NULL, silc_client_command_reply_whois_i,
2056 silc_client_command_reply_free(cmd);
2059 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2061 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2062 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2064 COMMAND_CHECK_STATUS_I;
2066 /* Save IDENTIFY info */
2067 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
2069 /* Pending callbacks are not executed if this was an list entry */
2070 if (cmd->status != SILC_STATUS_OK &&
2071 cmd->status != SILC_STATUS_LIST_END) {
2072 silc_client_command_reply_free(cmd);
2077 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2080 /* If we received notify for invalid ID we'll remove the ID if we
2082 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2083 SilcClientEntry client_entry;
2085 unsigned char *tmp =
2086 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2089 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2091 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2094 silc_client_del_client(cmd->client, conn, client_entry);
2095 silc_free(client_id);
2100 /* Unregister this command reply */
2101 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2102 NULL, silc_client_command_reply_identify_i,
2105 silc_client_command_reply_free(cmd);
2108 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2110 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2111 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2113 SilcServerEntry server;
2114 SilcServerID *server_id = NULL;
2115 char *server_name, *server_info;
2118 COMMAND_CHECK_STATUS_I;
2121 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2125 server_id = silc_id_payload_parse_id(tmp, len, NULL);
2129 /* Get server name */
2130 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2134 /* Get server info */
2135 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2139 /* See whether we have this server cached. If not create it. */
2140 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
2142 SILC_LOG_DEBUG(("New server entry"));
2143 silc_client_add_server(cmd->client, conn, server_name, server_info,
2144 silc_id_dup(server_id, SILC_ID_SERVER));
2148 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2149 silc_free(server_id);
2151 silc_client_command_reply_free(cmd);
2154 static void silc_client_command_reply_users_i_cb(SilcClient client,
2155 SilcClientConnection conn,
2156 SilcChannelEntry *channels,
2157 SilcUInt32 channels_count,
2160 if (!channels_count) {
2161 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2162 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2164 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2165 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2166 "%s", silc_get_status_message(cmd->error));
2167 COMMAND_REPLY_ERROR(cmd->error);
2168 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2169 silc_client_command_reply_free(cmd);
2173 silc_client_command_reply_users_i(context, NULL);
2176 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2178 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2180 COMMAND_CHECK_STATUS_I;
2182 /* Save USERS info */
2183 if (silc_client_command_reply_users_save(
2184 cmd, cmd->status, FALSE, TRUE,
2185 silc_client_command_reply_users_i_cb,
2186 silc_client_command_reply_users_i))
2190 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2193 /* Unregister this command reply */
2194 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2195 NULL, silc_client_command_reply_users_i,
2198 silc_client_command_reply_free(cmd);
2201 /* Private range commands, specific to this implementation (and compatible
2202 with SILC Server >= 0.9). */
2204 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2206 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2207 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2209 if (cmd->error != SILC_STATUS_OK) {
2210 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2211 "%s", silc_get_status_message(cmd->error));
2212 COMMAND_REPLY_ERROR(cmd->error);
2216 /* Notify application */
2217 COMMAND_REPLY((SILC_ARGS));
2220 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2221 silc_client_command_reply_free(cmd);
2224 SILC_CLIENT_CMD_REPLY_FUNC(close)
2226 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2227 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2229 if (cmd->error != SILC_STATUS_OK) {
2230 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2231 "%s", silc_get_status_message(cmd->error));
2232 COMMAND_REPLY_ERROR(cmd->error);
2236 /* Notify application */
2237 COMMAND_REPLY((SILC_ARGS));
2240 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2241 silc_client_command_reply_free(cmd);
2244 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2246 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2247 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2249 if (cmd->error != SILC_STATUS_OK) {
2250 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2251 "%s", silc_get_status_message(cmd->error));
2252 COMMAND_REPLY_ERROR(cmd->error);
2256 /* Notify application */
2257 COMMAND_REPLY((SILC_ARGS));
2260 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2261 silc_client_command_reply_free(cmd);