5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2005 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;
584 /* Normalize nickname */
585 tmp = silc_identifier_check(conn->nickname, strlen(conn->nickname),
586 SILC_STRING_UTF8, 128, NULL);
588 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_NICKNAME);
592 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
594 silc_idcache_add(conn->internal->client_cache, tmp,
595 conn->local_entry->id, conn->local_entry, 0, NULL);
598 /* Notify application */
599 COMMAND_REPLY((SILC_ARGS, conn->local_entry, conn->local_entry->nickname,
600 (const SilcClientID *)&old_client_id));
603 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
604 silc_client_command_reply_free(cmd);
607 /* Received reply to the LIST command. */
609 SILC_CLIENT_CMD_REPLY_FUNC(list)
611 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
612 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
613 unsigned char *tmp, *name, *topic;
614 SilcUInt32 usercount = 0, len;
615 SilcChannelID *channel_id = NULL;
616 SilcChannelEntry channel_entry;
618 COMMAND_CHECK_STATUS;
620 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
622 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
626 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
628 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
632 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
634 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
638 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
639 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
641 SILC_GET32_MSB(usercount, tmp);
643 /* Check whether the channel exists, and add it to cache if it doesn't. */
644 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
646 if (!channel_entry) {
647 /* Add new channel entry */
648 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
650 if (!channel_entry) {
651 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
657 /* Notify application */
658 COMMAND_REPLY((SILC_ARGS, channel_entry, name, topic, usercount));
660 /* Pending callbacks are not executed if this was an list entry */
661 if (cmd->status != SILC_STATUS_OK &&
662 cmd->status != SILC_STATUS_LIST_END) {
663 silc_client_command_reply_free(cmd);
668 silc_free(channel_id);
669 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
671 silc_client_command_reply_free(cmd);
674 /* Received reply to topic command. */
676 SILC_CLIENT_CMD_REPLY_FUNC(topic)
678 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
679 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
680 SilcChannelEntry channel;
681 SilcChannelID *channel_id = NULL;
684 SilcUInt32 argc, len;
686 if (cmd->error != SILC_STATUS_OK) {
687 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
688 "Cannot set topic: %s", silc_get_status_message(cmd->error));
689 COMMAND_REPLY_ERROR(cmd->error);
693 argc = silc_argument_get_arg_num(cmd->args);
694 if (argc < 1 || argc > 3) {
695 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
699 /* Take Channel ID */
700 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
705 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
709 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
713 /* Get the channel entry */
714 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
716 silc_free(channel_id);
717 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
722 silc_free(channel->topic);
723 channel->topic = silc_memdup(topic, strlen(topic));
726 /* Notify application */
727 COMMAND_REPLY((SILC_ARGS, channel, topic));
730 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
731 silc_client_command_reply_free(cmd);
734 /* Received reply to invite command. */
736 SILC_CLIENT_CMD_REPLY_FUNC(invite)
738 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
739 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
740 SilcChannelEntry channel;
741 SilcChannelID *channel_id;
744 SilcBufferStruct buf;
746 if (cmd->error != SILC_STATUS_OK) {
747 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
748 "Cannot invite: %s", silc_get_status_message(cmd->error));
749 COMMAND_REPLY_ERROR(cmd->error);
753 /* Take Channel ID */
754 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
758 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
762 /* Get the channel entry */
763 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
765 silc_free(channel_id);
766 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
770 /* Get the invite list */
771 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
773 silc_buffer_set(&buf, tmp, len);
775 /* Notify application */
776 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
779 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
780 silc_client_command_reply_free(cmd);
783 /* Received reply to the KILL command. */
785 SILC_CLIENT_CMD_REPLY_FUNC(kill)
787 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
788 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
789 SilcClientID *client_id;
790 SilcClientEntry client_entry = NULL;
792 unsigned char *id_data;
794 if (cmd->error != SILC_STATUS_OK) {
795 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
796 "Cannot kill: %s", silc_get_status_message(cmd->error));
797 COMMAND_REPLY_ERROR(cmd->error);
801 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
803 client_id = silc_id_payload_parse_id(id_data, len, NULL);
805 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
809 /* Get the client entry, if exists */
810 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
811 silc_free(client_id);
814 /* Notify application */
815 COMMAND_REPLY((SILC_ARGS, client_entry));
818 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
819 silc_client_command_reply_free(cmd);
822 /* Received reply to INFO command. We receive the server ID and some
823 information about the server user requested. */
825 SILC_CLIENT_CMD_REPLY_FUNC(info)
827 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
828 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
830 SilcServerEntry server;
831 SilcServerID *server_id = NULL;
832 char *server_name, *server_info;
835 SILC_LOG_DEBUG(("Start"));
837 if (cmd->error != SILC_STATUS_OK) {
838 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
839 silc_get_status_message(cmd->error));
840 COMMAND_REPLY_ERROR(cmd->error);
845 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
849 server_id = silc_id_payload_parse_id(tmp, len, NULL);
853 /* Get server name */
854 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
858 /* Get server info */
859 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
863 /* See whether we have this server cached. If not create it. */
864 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
866 SILC_LOG_DEBUG(("New server entry"));
867 server = silc_client_add_server(cmd->client, conn, server_name,
869 silc_id_dup(server_id, SILC_ID_SERVER));
874 /* Notify application */
875 COMMAND_REPLY((SILC_ARGS, server, server->server_name, server->server_info));
878 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
879 silc_free(server_id);
880 silc_client_command_reply_free(cmd);
883 /* Received reply to STATS command. */
885 SILC_CLIENT_CMD_REPLY_FUNC(stats)
887 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
888 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
889 unsigned char *tmp, *buf = NULL;
890 SilcUInt32 len, buf_len = 0;
892 if (cmd->error != SILC_STATUS_OK) {
893 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
894 "%s", silc_get_status_message(cmd->error));
895 COMMAND_REPLY_ERROR(cmd->error);
900 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
904 /* Get statistics structure */
905 buf = silc_argument_get_arg_type(cmd->args, 3, &buf_len);
907 /* Notify application */
908 COMMAND_REPLY((SILC_ARGS, buf, buf_len));
911 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
912 silc_client_command_reply_free(cmd);
915 /* Received reply to PING command. The reply time is shown to user. */
917 SILC_CLIENT_CMD_REPLY_FUNC(ping)
919 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
920 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
923 time_t diff, curtime;
925 if (cmd->error != SILC_STATUS_OK) {
926 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
927 "%s", silc_get_status_message(cmd->error));
928 COMMAND_REPLY_ERROR(cmd->error);
932 curtime = time(NULL);
933 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
934 cmd->packet->src_id_type);
935 if (!id || !conn->internal->ping) {
936 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
940 for (i = 0; i < conn->internal->ping_count; i++) {
941 if (!conn->internal->ping[i].dest_id)
943 if (SILC_ID_SERVER_COMPARE(conn->internal->ping[i].dest_id, id)) {
944 diff = curtime - conn->internal->ping[i].start_time;
945 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
946 "Ping reply from %s: %d second%s",
947 conn->internal->ping[i].dest_name, diff,
948 diff == 1 ? "" : "s");
950 conn->internal->ping[i].start_time = 0;
951 silc_free(conn->internal->ping[i].dest_id);
952 conn->internal->ping[i].dest_id = NULL;
953 silc_free(conn->internal->ping[i].dest_name);
954 conn->internal->ping[i].dest_name = NULL;
961 /* Notify application */
962 COMMAND_REPLY((SILC_ARGS));
965 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
966 silc_client_command_reply_free(cmd);
969 /* Received reply for JOIN command. */
971 SILC_CLIENT_CMD_REPLY_FUNC(join)
973 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
974 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
975 SilcChannelEntry channel;
977 SilcChannelID *channel_id;
978 SilcUInt32 argc, mode = 0, len, list_count;
979 char *topic, *tmp, *channel_name = NULL, *hmac;
980 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
981 SilcBufferStruct chpklist;
984 SILC_LOG_DEBUG(("Start"));
986 if (cmd->error != SILC_STATUS_OK) {
987 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
988 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
989 "Cannot join channel: %s", silc_get_status_message(cmd->error));
990 COMMAND_REPLY_ERROR(cmd->error);
994 argc = silc_argument_get_arg_num(cmd->args);
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);
1002 /* Get channel name */
1003 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
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);
1012 /* Get Channel ID */
1013 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1015 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1016 "Cannot join channel: Bad reply packet");
1017 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1020 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1022 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1026 /* Get channel mode */
1027 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1029 SILC_GET32_MSB(mode, tmp);
1031 /* Get channel key */
1032 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1034 keyp = silc_buffer_alloc(len);
1035 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1036 silc_buffer_put(keyp, tmp, len);
1040 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1042 /* Check whether we have this channel entry already. */
1043 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1045 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
1046 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
1048 /* Create new channel entry */
1049 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1053 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_CHANNEL);
1057 conn->current_channel = channel;
1058 channel->mode = mode;
1061 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1063 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1064 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1065 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1066 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1071 /* Get the list count */
1072 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1075 SILC_GET32_MSB(list_count, tmp);
1077 /* Get Client ID list */
1078 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1082 client_id_list = silc_buffer_alloc(len);
1083 silc_buffer_pull_tail(client_id_list, len);
1084 silc_buffer_put(client_id_list, tmp, len);
1086 /* Get client mode list */
1087 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1091 client_mode_list = silc_buffer_alloc(len);
1092 silc_buffer_pull_tail(client_mode_list, len);
1093 silc_buffer_put(client_mode_list, tmp, len);
1095 /* Add clients we received in the reply to the channel */
1096 for (i = 0; i < list_count; i++) {
1099 SilcClientID *client_id;
1100 SilcClientEntry client_entry;
1103 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1105 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1110 SILC_GET32_MSB(mode, client_mode_list->data);
1112 /* Check if we have this client cached already. */
1113 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1114 if (!client_entry) {
1115 /* No, we don't have it, add entry for it. */
1117 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1118 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1121 /* Join client to the channel */
1122 if (!silc_client_on_channel(channel, client_entry)) {
1123 chu = silc_calloc(1, sizeof(*chu));
1124 chu->client = client_entry;
1125 chu->channel = channel;
1127 silc_hash_table_add(channel->user_list, client_entry, chu);
1128 silc_hash_table_add(client_entry->channels, channel, chu);
1131 silc_free(client_id);
1132 silc_buffer_pull(client_id_list, idp_len);
1133 silc_buffer_pull(client_mode_list, 4);
1135 silc_buffer_push(client_id_list, client_id_list->data -
1136 client_id_list->head);
1137 silc_buffer_push(client_mode_list, client_mode_list->data -
1138 client_mode_list->head);
1140 /* Save channel key */
1142 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1144 /* Get founder key */
1145 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
1147 if (channel->founder_key)
1148 silc_pkcs_public_key_free(channel->founder_key);
1149 channel->founder_key = NULL;
1150 silc_pkcs_public_key_payload_decode(tmp, len, &channel->founder_key);
1153 /* Get user limit */
1154 tmp = silc_argument_get_arg_type(cmd->args, 17, &len);
1155 if (tmp && len == 4)
1156 SILC_GET32_MSB(channel->user_limit, tmp);
1157 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1158 channel->user_limit = 0;
1160 /* Get channel public key list */
1161 tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
1163 silc_buffer_set(&chpklist, tmp, len);
1166 silc_free(channel->topic);
1167 channel->topic = silc_memdup(topic, strlen(topic));
1170 /* Notify application */
1171 COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0,
1172 keyp ? keyp->head : NULL, NULL,
1173 NULL, topic, hmac, list_count, client_id_list,
1174 client_mode_list, channel->founder_key,
1175 tmp ? &chpklist : NULL, channel->user_limit));
1178 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1179 silc_client_command_reply_free(cmd);
1180 silc_buffer_free(keyp);
1181 silc_buffer_free(client_id_list);
1182 silc_buffer_free(client_mode_list);
1185 /* Received reply for MOTD command */
1187 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1189 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1190 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1192 char *motd = NULL, *cp, line[256];
1194 if (cmd->error != SILC_STATUS_OK) {
1195 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1196 "%s", silc_get_status_message(cmd->error));
1197 COMMAND_REPLY_ERROR(cmd->error);
1201 argc = silc_argument_get_arg_num(cmd->args);
1203 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1208 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1210 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1217 if (cp[i++] == '\n') {
1218 memset(line, 0, sizeof(line));
1219 silc_strncat(line, sizeof(line), cp, i - 1);
1225 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1234 /* Notify application */
1235 COMMAND_REPLY((SILC_ARGS, motd));
1238 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1239 silc_client_command_reply_free(cmd);
1242 /* Received reply tot he UMODE command. Save the current user mode */
1244 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1246 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1247 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1251 if (cmd->error != SILC_STATUS_OK) {
1252 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1253 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1254 COMMAND_REPLY_ERROR(cmd->error);
1258 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1260 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1264 SILC_GET32_MSB(mode, tmp);
1265 conn->local_entry->mode = mode;
1267 /* Notify application */
1268 COMMAND_REPLY((SILC_ARGS, mode));
1271 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1272 silc_client_command_reply_free(cmd);
1275 /* Received reply for CMODE command. */
1277 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1279 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1280 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1283 SilcChannelID *channel_id;
1284 SilcChannelEntry channel;
1286 SilcPublicKey public_key = NULL;
1287 SilcBufferStruct channel_pubkeys;
1289 if (cmd->error != SILC_STATUS_OK) {
1290 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1291 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1292 COMMAND_REPLY_ERROR(cmd->error);
1296 /* Take Channel ID */
1297 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1300 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1304 /* Get the channel entry */
1305 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1307 silc_free(channel_id);
1308 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1312 /* Get channel mode */
1313 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1315 silc_free(channel_id);
1316 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1321 SILC_GET32_MSB(mode, tmp);
1322 channel->mode = mode;
1324 /* Get founder public key */
1325 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
1327 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1331 /* Get user limit */
1332 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
1333 if (tmp && len == 4)
1334 SILC_GET32_MSB(channel->user_limit, tmp);
1335 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1336 channel->user_limit = 0;
1338 /* Get channel public key(s) */
1339 tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
1341 silc_buffer_set(&channel_pubkeys, tmp, len);
1343 /* Notify application */
1344 COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
1345 tmp ? &channel_pubkeys : NULL, channel->user_limit));
1347 silc_free(channel_id);
1351 silc_pkcs_public_key_free(public_key);
1352 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1353 silc_client_command_reply_free(cmd);
1356 /* Received reply for CUMODE command */
1358 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1360 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1361 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1362 SilcClientID *client_id;
1363 SilcChannelID *channel_id;
1364 SilcClientEntry client_entry;
1365 SilcChannelEntry channel;
1366 SilcChannelUser chu;
1367 unsigned char *modev, *tmp, *id;
1368 SilcUInt32 len, mode;
1370 if (cmd->error != SILC_STATUS_OK) {
1371 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1372 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1373 COMMAND_REPLY_ERROR(cmd->error);
1377 /* Get channel mode */
1378 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1380 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1384 /* Take Channel ID */
1385 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1388 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1392 /* Get the channel entry */
1393 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1395 silc_free(channel_id);
1396 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1401 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1403 silc_free(channel_id);
1404 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1407 client_id = silc_id_payload_parse_id(id, len, NULL);
1409 silc_free(channel_id);
1410 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1414 /* Get client entry */
1415 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1416 if (!client_entry) {
1417 silc_free(channel_id);
1418 silc_free(client_id);
1419 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1424 SILC_GET32_MSB(mode, modev);
1425 chu = silc_client_on_channel(channel, client_entry);
1429 /* Notify application */
1430 COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry));
1431 silc_free(client_id);
1432 silc_free(channel_id);
1435 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1436 silc_client_command_reply_free(cmd);
1439 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1441 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1442 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1443 SilcClientID *client_id = NULL;
1444 SilcChannelID *channel_id = NULL;
1445 SilcClientEntry client_entry = NULL;
1446 SilcChannelEntry channel = NULL;
1450 if (cmd->error != SILC_STATUS_OK) {
1451 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1452 "Cannot kick: %s", silc_get_status_message(cmd->error));
1453 COMMAND_REPLY_ERROR(cmd->error);
1457 /* Take Channel ID */
1458 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1460 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1462 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1466 /* Get the channel entry */
1467 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1469 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1475 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1477 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1479 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1483 /* Get client entry */
1484 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1485 if (!client_entry) {
1486 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1491 /* Notify application */
1492 COMMAND_REPLY((SILC_ARGS, channel, client_entry));
1495 silc_free(channel_id);
1496 silc_free(client_id);
1497 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1498 silc_client_command_reply_free(cmd);
1501 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1503 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1504 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1506 if (cmd->error != SILC_STATUS_OK) {
1507 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1508 "%s", silc_get_status_message(cmd->error));
1509 COMMAND_REPLY_ERROR(cmd->error);
1513 /* Notify application */
1514 COMMAND_REPLY((SILC_ARGS));
1517 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1518 silc_client_command_reply_free(cmd);
1521 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1523 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1524 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1526 if (cmd->error != SILC_STATUS_OK) {
1527 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1528 "%s", silc_get_status_message(cmd->error));
1529 COMMAND_REPLY_ERROR(cmd->error);
1533 /* Notify application */
1534 COMMAND_REPLY((SILC_ARGS));
1537 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1538 silc_client_command_reply_free(cmd);
1541 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1543 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1544 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1547 if (cmd->error != SILC_STATUS_OK) {
1548 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1549 "%s", silc_get_status_message(cmd->error));
1550 COMMAND_REPLY_ERROR(cmd->error);
1554 /* Notify application */
1555 COMMAND_REPLY((SILC_ARGS));
1557 /* Generate the detachment data and deliver it to the client in the
1558 detach client operation */
1559 detach = silc_client_get_detach_data(cmd->client, conn);
1561 cmd->client->internal->ops->detach(cmd->client, conn,
1562 detach->data, detach->len);
1563 silc_buffer_free(detach);
1567 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1568 silc_client_command_reply_free(cmd);
1571 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1573 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1574 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1576 if (cmd->error != SILC_STATUS_OK) {
1577 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1578 "%s", silc_get_status_message(cmd->error));
1579 COMMAND_REPLY_ERROR(cmd->error);
1583 /* Notify application */
1584 COMMAND_REPLY((SILC_ARGS));
1587 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1588 silc_client_command_reply_free(cmd);
1591 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1593 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1594 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1595 SilcChannelEntry channel;
1596 SilcChannelID *channel_id;
1599 SilcBufferStruct buf;
1601 if (cmd->error != SILC_STATUS_OK) {
1602 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1603 "%s", silc_get_status_message(cmd->error));
1604 COMMAND_REPLY_ERROR(cmd->error);
1608 /* Take Channel ID */
1609 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1613 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1617 /* Get the channel entry */
1618 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1620 silc_free(channel_id);
1621 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1625 /* Get the ban list */
1626 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1628 silc_buffer_set(&buf, tmp, len);
1630 /* Notify application */
1631 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
1634 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1635 silc_client_command_reply_free(cmd);
1638 /* Reply to LEAVE command. */
1640 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1642 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1643 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1644 SilcChannelID *channel_id;
1645 SilcChannelEntry channel = NULL;
1646 SilcChannelUser chu;
1650 if (cmd->error != SILC_STATUS_OK) {
1651 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1652 "%s", silc_get_status_message(cmd->error));
1653 COMMAND_REPLY_ERROR(cmd->error);
1657 /* From protocol version 1.1 we get the channel ID of the left channel */
1658 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1660 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1664 /* Get the channel entry */
1665 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1667 silc_free(channel_id);
1668 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1672 /* Remove us from this channel. */
1673 chu = silc_client_on_channel(channel, conn->local_entry);
1675 silc_hash_table_del(chu->client->channels, chu->channel);
1676 silc_hash_table_del(chu->channel->user_list, chu->client);
1680 silc_free(channel_id);
1683 /* Notify application */
1684 COMMAND_REPLY((SILC_ARGS, channel));
1686 /* Now delete the channel. */
1688 silc_client_del_channel(cmd->client, conn, channel);
1691 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1692 silc_client_command_reply_free(cmd);
1695 /* Channel resolving callback for USERS command reply. */
1697 static void silc_client_command_reply_users_cb(SilcClient client,
1698 SilcClientConnection conn,
1699 SilcChannelEntry *channels,
1700 SilcUInt32 channels_count,
1703 if (!channels_count) {
1704 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1705 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1707 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1708 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1709 "%s", silc_get_status_message(cmd->error));
1710 COMMAND_REPLY_ERROR(cmd->error);
1711 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1712 silc_client_command_reply_free(cmd);
1716 silc_client_command_reply_users(context, NULL);
1720 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1724 SilcGetChannelCallback get_channel,
1725 SilcCommandCb get_clients)
1727 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1728 SilcChannelEntry channel;
1729 SilcClientEntry client_entry;
1730 SilcChannelUser chu;
1731 SilcChannelID *channel_id = NULL;
1732 SilcBufferStruct client_id_list, client_mode_list;
1734 SilcUInt32 tmp_len, list_count;
1736 unsigned char **res_argv = NULL;
1737 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1738 bool wait_res = FALSE;
1740 SILC_LOG_DEBUG(("Start"));
1742 /* Get channel ID */
1743 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1745 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1748 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1750 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1754 /* Get the list count */
1755 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1757 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1760 SILC_GET32_MSB(list_count, tmp);
1762 /* Get Client ID list */
1763 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1765 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1768 silc_buffer_set(&client_id_list, tmp, tmp_len);
1770 /* Get client mode list */
1771 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1773 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1776 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1778 /* Get channel entry */
1779 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1781 /* Resolve the channel from server */
1782 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1784 silc_free(channel_id);
1788 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1790 /* Cache the received Client ID's and modes. */
1791 for (i = 0; i < list_count; i++) {
1794 SilcClientID *client_id;
1797 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1799 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1804 SILC_GET32_MSB(mode, client_mode_list.data);
1806 /* Check if we have this client cached already. */
1807 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1808 if (!client_entry || !client_entry->username || !client_entry->realname) {
1810 /* No we don't have it (or it is incomplete in information), query
1811 it from the server. Assemble argument table that will be sent
1812 for the WHOIS command later. */
1813 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1815 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1817 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1819 res_argv[res_argc] = client_id_list.data;
1820 res_argv_lens[res_argc] = idp_len;
1821 res_argv_types[res_argc] = res_argc + 4;
1825 if (!silc_client_on_channel(channel, client_entry)) {
1826 chu = silc_calloc(1, sizeof(*chu));
1827 chu->client = client_entry;
1829 chu->channel = channel;
1830 silc_hash_table_add(channel->user_list, client_entry, chu);
1831 silc_hash_table_add(client_entry->channels, channel, chu);
1835 silc_free(client_id);
1836 silc_buffer_pull(&client_id_list, idp_len);
1837 silc_buffer_pull(&client_mode_list, 4);
1840 /* Query the client information from server if the list included clients
1841 that we don't know about. */
1845 /* Send the WHOIS command to server */
1846 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1847 silc_client_command_reply_whois_i, 0,
1849 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1850 res_argc, res_argv, res_argv_lens,
1851 res_argv_types, conn->cmd_ident);
1852 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1853 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1856 /* Register pending command callback. After we've received the WHOIS
1857 command reply we will reprocess this command reply by re-calling this
1858 USERS command reply callback. */
1859 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1862 silc_buffer_free(res_cmd);
1863 silc_free(channel_id);
1864 silc_free(res_argv);
1865 silc_free(res_argv_lens);
1866 silc_free(res_argv_types);
1873 silc_buffer_push(&client_id_list, (client_id_list.data -
1874 client_id_list.head));
1875 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1876 client_mode_list.head));
1878 /* Notify application */
1880 COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list,
1881 &client_mode_list));
1884 silc_free(channel_id);
1888 /* Reply to USERS command. Received list of client ID's and theirs modes
1889 on the channel we requested. */
1891 SILC_CLIENT_CMD_REPLY_FUNC(users)
1893 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1894 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1895 SilcClientCommandReplyContext r = (SilcClientCommandReplyContext)context2;
1897 SILC_LOG_DEBUG(("Start"));
1899 if (cmd->error != SILC_STATUS_OK) {
1900 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1901 "Query failed: %s", silc_get_status_message(cmd->error));
1902 COMMAND_REPLY_ERROR(cmd->error);
1906 if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) {
1907 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1908 /* Do not resolve anymore. Server may be sending us some non-existent
1909 Client ID (a bug in server), and we want to show the users list
1911 silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE,
1912 silc_client_command_reply_users_cb,
1913 silc_client_command_reply_users);
1916 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1917 "Query failed: %s", silc_get_status_message(cmd->error));
1918 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1923 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE,
1924 silc_client_command_reply_users_cb,
1925 silc_client_command_reply_users))
1929 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1930 silc_client_command_reply_free(cmd);
1933 /* Received command reply to GETKEY command. WE've received the remote
1934 client's public key. */
1936 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1938 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1939 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1940 SilcIDPayload idp = NULL;
1941 SilcClientID *client_id = NULL;
1942 SilcClientEntry client_entry;
1943 SilcServerID *server_id = NULL;
1944 SilcServerEntry server_entry;
1948 SilcPublicKey public_key = NULL;
1950 SILC_LOG_DEBUG(("Start"));
1952 if (cmd->error != SILC_STATUS_OK) {
1953 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1954 "%s", silc_get_status_message(cmd->error));
1955 COMMAND_REPLY_ERROR(cmd->error);
1959 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1961 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1964 idp = silc_id_payload_parse(tmp, len);
1966 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1970 /* Get the public key payload */
1971 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1973 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1978 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1982 id_type = silc_id_payload_get_type(idp);
1983 if (id_type == SILC_ID_CLIENT) {
1984 /* Received client's public key */
1985 client_id = silc_id_payload_get_id(idp);
1986 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1987 if (!client_entry) {
1988 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1992 /* Save fingerprint */
1993 if (!client_entry->fingerprint) {
1994 client_entry->fingerprint = silc_calloc(20, sizeof(unsigned char));
1995 client_entry->fingerprint_len = 20;
1996 silc_hash_make(cmd->client->sha1hash, tmp + 4, len - 4,
1997 client_entry->fingerprint);
1999 if (!client_entry->public_key) {
2000 client_entry->public_key = public_key;
2004 /* Notify application */
2005 COMMAND_REPLY((SILC_ARGS, id_type, client_entry,
2006 client_entry->public_key));
2007 } else if (id_type == SILC_ID_SERVER) {
2008 /* Received server's public key */
2009 server_id = silc_id_payload_get_id(idp);
2010 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
2011 if (!server_entry) {
2012 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2016 /* Notify application */
2017 COMMAND_REPLY((SILC_ARGS, id_type, server_entry, public_key));
2021 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
2023 silc_id_payload_free(idp);
2025 silc_pkcs_public_key_free(public_key);
2026 silc_free(client_id);
2027 silc_free(server_id);
2028 silc_client_command_reply_free(cmd);
2031 SILC_CLIENT_CMD_REPLY_FUNC(quit)
2033 silc_client_command_reply_free(context);
2037 /******************************************************************************
2039 Internal command reply functions
2041 ******************************************************************************/
2043 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
2045 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2046 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2048 COMMAND_CHECK_STATUS_I;
2050 /* Save WHOIS info */
2051 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
2053 /* Pending callbacks are not executed if this was an list entry */
2054 if (cmd->status != SILC_STATUS_OK &&
2055 cmd->status != SILC_STATUS_LIST_END) {
2056 silc_client_command_reply_free(cmd);
2061 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
2064 /* If we received notify for invalid ID we'll remove the ID if we
2066 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2067 SilcClientEntry client_entry;
2069 unsigned char *tmp =
2070 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2073 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2075 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2078 silc_client_del_client(cmd->client, conn, client_entry);
2079 silc_free(client_id);
2084 /* Unregister this command reply */
2085 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2086 NULL, silc_client_command_reply_whois_i,
2089 silc_client_command_reply_free(cmd);
2092 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2094 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2095 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2097 COMMAND_CHECK_STATUS_I;
2099 /* Save IDENTIFY info */
2100 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
2102 /* Pending callbacks are not executed if this was an list entry */
2103 if (cmd->status != SILC_STATUS_OK &&
2104 cmd->status != SILC_STATUS_LIST_END) {
2105 silc_client_command_reply_free(cmd);
2110 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2113 /* If we received notify for invalid ID we'll remove the ID if we
2115 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2116 SilcClientEntry client_entry;
2118 unsigned char *tmp =
2119 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2122 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2124 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2127 silc_client_del_client(cmd->client, conn, client_entry);
2128 silc_free(client_id);
2133 /* Unregister this command reply */
2134 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2135 NULL, silc_client_command_reply_identify_i,
2138 silc_client_command_reply_free(cmd);
2141 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2143 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2144 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2146 SilcServerEntry server;
2147 SilcServerID *server_id = NULL;
2148 char *server_name, *server_info;
2151 COMMAND_CHECK_STATUS_I;
2154 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2158 server_id = silc_id_payload_parse_id(tmp, len, NULL);
2162 /* Get server name */
2163 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2167 /* Get server info */
2168 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2172 /* See whether we have this server cached. If not create it. */
2173 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
2175 SILC_LOG_DEBUG(("New server entry"));
2176 silc_client_add_server(cmd->client, conn, server_name, server_info,
2177 silc_id_dup(server_id, SILC_ID_SERVER));
2181 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2182 silc_free(server_id);
2184 silc_client_command_reply_free(cmd);
2187 static void silc_client_command_reply_users_i_cb(SilcClient client,
2188 SilcClientConnection conn,
2189 SilcChannelEntry *channels,
2190 SilcUInt32 channels_count,
2193 if (!channels_count) {
2194 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2195 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2197 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2198 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2199 "%s", silc_get_status_message(cmd->error));
2200 COMMAND_REPLY_ERROR(cmd->error);
2201 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2202 silc_client_command_reply_free(cmd);
2206 silc_client_command_reply_users_i(context, NULL);
2209 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2211 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2213 COMMAND_CHECK_STATUS_I;
2215 /* Save USERS info */
2216 if (silc_client_command_reply_users_save(
2217 cmd, cmd->status, FALSE, TRUE,
2218 silc_client_command_reply_users_i_cb,
2219 silc_client_command_reply_users_i))
2223 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2226 /* Unregister this command reply */
2227 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2228 NULL, silc_client_command_reply_users_i,
2231 silc_client_command_reply_free(cmd);
2234 /* Private range commands, specific to this implementation (and compatible
2235 with SILC Server >= 0.9). */
2237 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2239 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2240 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2242 if (cmd->error != SILC_STATUS_OK) {
2243 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2244 "%s", silc_get_status_message(cmd->error));
2245 COMMAND_REPLY_ERROR(cmd->error);
2249 /* Notify application */
2250 COMMAND_REPLY((SILC_ARGS));
2253 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2254 silc_client_command_reply_free(cmd);
2257 SILC_CLIENT_CMD_REPLY_FUNC(close)
2259 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2260 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2262 if (cmd->error != SILC_STATUS_OK) {
2263 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2264 "%s", silc_get_status_message(cmd->error));
2265 COMMAND_REPLY_ERROR(cmd->error);
2269 /* Notify application */
2270 COMMAND_REPLY((SILC_ARGS));
2273 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2274 silc_client_command_reply_free(cmd);
2277 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2279 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2280 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2282 if (cmd->error != SILC_STATUS_OK) {
2283 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2284 "%s", silc_get_status_message(cmd->error));
2285 COMMAND_REPLY_ERROR(cmd->error);
2289 /* Notify application */
2290 COMMAND_REPLY((SILC_ARGS));
2293 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2294 silc_client_command_reply_free(cmd);