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 conn->current_channel = channel;
1054 channel->mode = mode;
1057 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1059 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1060 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1061 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1062 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1067 /* Get the list count */
1068 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1071 SILC_GET32_MSB(list_count, tmp);
1073 /* Get Client ID list */
1074 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1078 client_id_list = silc_buffer_alloc(len);
1079 silc_buffer_pull_tail(client_id_list, len);
1080 silc_buffer_put(client_id_list, tmp, len);
1082 /* Get client mode list */
1083 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1087 client_mode_list = silc_buffer_alloc(len);
1088 silc_buffer_pull_tail(client_mode_list, len);
1089 silc_buffer_put(client_mode_list, tmp, len);
1091 /* Add clients we received in the reply to the channel */
1092 for (i = 0; i < list_count; i++) {
1095 SilcClientID *client_id;
1096 SilcClientEntry client_entry;
1099 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1101 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1106 SILC_GET32_MSB(mode, client_mode_list->data);
1108 /* Check if we have this client cached already. */
1109 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1110 if (!client_entry) {
1111 /* No, we don't have it, add entry for it. */
1113 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1114 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1117 /* Join client to the channel */
1118 if (!silc_client_on_channel(channel, client_entry)) {
1119 chu = silc_calloc(1, sizeof(*chu));
1120 chu->client = client_entry;
1121 chu->channel = channel;
1123 silc_hash_table_add(channel->user_list, client_entry, chu);
1124 silc_hash_table_add(client_entry->channels, channel, chu);
1127 silc_free(client_id);
1128 silc_buffer_pull(client_id_list, idp_len);
1129 silc_buffer_pull(client_mode_list, 4);
1131 silc_buffer_push(client_id_list, client_id_list->data -
1132 client_id_list->head);
1133 silc_buffer_push(client_mode_list, client_mode_list->data -
1134 client_mode_list->head);
1136 /* Save channel key */
1138 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1140 /* Get founder key */
1141 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
1143 if (channel->founder_key)
1144 silc_pkcs_public_key_free(channel->founder_key);
1145 channel->founder_key = NULL;
1146 silc_pkcs_public_key_payload_decode(tmp, len, &channel->founder_key);
1149 /* Get user limit */
1150 tmp = silc_argument_get_arg_type(cmd->args, 17, &len);
1151 if (tmp && len == 4)
1152 SILC_GET32_MSB(channel->user_limit, tmp);
1153 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1154 channel->user_limit = 0;
1156 /* Get channel public key list */
1157 tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
1159 silc_buffer_set(&chpklist, tmp, len);
1162 silc_free(channel->topic);
1163 channel->topic = silc_memdup(topic, strlen(topic));
1166 /* Notify application */
1167 COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0,
1168 keyp ? keyp->head : NULL, NULL,
1169 NULL, topic, hmac, list_count, client_id_list,
1170 client_mode_list, channel->founder_key,
1171 tmp ? &chpklist : NULL, channel->user_limit));
1174 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1175 silc_client_command_reply_free(cmd);
1176 silc_buffer_free(keyp);
1177 silc_buffer_free(client_id_list);
1178 silc_buffer_free(client_mode_list);
1181 /* Received reply for MOTD command */
1183 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1185 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1186 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1188 char *motd = NULL, *cp, line[256];
1190 if (cmd->error != SILC_STATUS_OK) {
1191 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1192 "%s", silc_get_status_message(cmd->error));
1193 COMMAND_REPLY_ERROR(cmd->error);
1197 argc = silc_argument_get_arg_num(cmd->args);
1199 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1204 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1206 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1213 if (cp[i++] == '\n') {
1214 memset(line, 0, sizeof(line));
1215 silc_strncat(line, sizeof(line), cp, i - 1);
1221 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1230 /* Notify application */
1231 COMMAND_REPLY((SILC_ARGS, motd));
1234 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1235 silc_client_command_reply_free(cmd);
1238 /* Received reply tot he UMODE command. Save the current user mode */
1240 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1242 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1243 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1247 if (cmd->error != SILC_STATUS_OK) {
1248 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1249 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1250 COMMAND_REPLY_ERROR(cmd->error);
1254 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1256 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1260 SILC_GET32_MSB(mode, tmp);
1261 conn->local_entry->mode = mode;
1263 /* Notify application */
1264 COMMAND_REPLY((SILC_ARGS, mode));
1267 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1268 silc_client_command_reply_free(cmd);
1271 /* Received reply for CMODE command. */
1273 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1275 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1276 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1279 SilcChannelID *channel_id;
1280 SilcChannelEntry channel;
1282 SilcPublicKey public_key = NULL;
1283 SilcBufferStruct channel_pubkeys;
1285 if (cmd->error != SILC_STATUS_OK) {
1286 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1287 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1288 COMMAND_REPLY_ERROR(cmd->error);
1292 /* Take Channel ID */
1293 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1296 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1300 /* Get the channel entry */
1301 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1303 silc_free(channel_id);
1304 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1308 /* Get channel mode */
1309 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1311 silc_free(channel_id);
1312 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1317 SILC_GET32_MSB(mode, tmp);
1318 channel->mode = mode;
1320 /* Get founder public key */
1321 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
1323 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1327 /* Get user limit */
1328 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
1329 if (tmp && len == 4)
1330 SILC_GET32_MSB(channel->user_limit, tmp);
1331 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1332 channel->user_limit = 0;
1334 /* Get channel public key(s) */
1335 tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
1337 silc_buffer_set(&channel_pubkeys, tmp, len);
1339 /* Notify application */
1340 COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
1341 tmp ? &channel_pubkeys : NULL, channel->user_limit));
1343 silc_free(channel_id);
1347 silc_pkcs_public_key_free(public_key);
1348 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1349 silc_client_command_reply_free(cmd);
1352 /* Received reply for CUMODE command */
1354 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1356 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1357 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1358 SilcClientID *client_id;
1359 SilcChannelID *channel_id;
1360 SilcClientEntry client_entry;
1361 SilcChannelEntry channel;
1362 SilcChannelUser chu;
1363 unsigned char *modev, *tmp, *id;
1364 SilcUInt32 len, mode;
1366 if (cmd->error != SILC_STATUS_OK) {
1367 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1368 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1369 COMMAND_REPLY_ERROR(cmd->error);
1373 /* Get channel mode */
1374 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1376 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1380 /* Take Channel ID */
1381 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1384 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1388 /* Get the channel entry */
1389 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1391 silc_free(channel_id);
1392 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1397 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1399 silc_free(channel_id);
1400 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1403 client_id = silc_id_payload_parse_id(id, len, NULL);
1405 silc_free(channel_id);
1406 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1410 /* Get client entry */
1411 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1412 if (!client_entry) {
1413 silc_free(channel_id);
1414 silc_free(client_id);
1415 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1420 SILC_GET32_MSB(mode, modev);
1421 chu = silc_client_on_channel(channel, client_entry);
1425 /* Notify application */
1426 COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry));
1427 silc_free(client_id);
1428 silc_free(channel_id);
1431 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1432 silc_client_command_reply_free(cmd);
1435 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1437 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1438 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1439 SilcClientID *client_id = NULL;
1440 SilcChannelID *channel_id = NULL;
1441 SilcClientEntry client_entry = NULL;
1442 SilcChannelEntry channel = NULL;
1446 if (cmd->error != SILC_STATUS_OK) {
1447 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1448 "Cannot kick: %s", silc_get_status_message(cmd->error));
1449 COMMAND_REPLY_ERROR(cmd->error);
1453 /* Take Channel ID */
1454 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1456 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1458 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1462 /* Get the channel entry */
1463 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1465 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1471 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1473 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1475 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1479 /* Get client entry */
1480 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1481 if (!client_entry) {
1482 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1487 /* Notify application */
1488 COMMAND_REPLY((SILC_ARGS, channel, client_entry));
1491 silc_free(channel_id);
1492 silc_free(client_id);
1493 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1494 silc_client_command_reply_free(cmd);
1497 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1499 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1500 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1502 if (cmd->error != SILC_STATUS_OK) {
1503 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1504 "%s", silc_get_status_message(cmd->error));
1505 COMMAND_REPLY_ERROR(cmd->error);
1509 /* Notify application */
1510 COMMAND_REPLY((SILC_ARGS));
1513 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1514 silc_client_command_reply_free(cmd);
1517 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1519 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1520 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1522 if (cmd->error != SILC_STATUS_OK) {
1523 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1524 "%s", silc_get_status_message(cmd->error));
1525 COMMAND_REPLY_ERROR(cmd->error);
1529 /* Notify application */
1530 COMMAND_REPLY((SILC_ARGS));
1533 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1534 silc_client_command_reply_free(cmd);
1537 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1539 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1540 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1543 if (cmd->error != SILC_STATUS_OK) {
1544 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1545 "%s", silc_get_status_message(cmd->error));
1546 COMMAND_REPLY_ERROR(cmd->error);
1550 /* Notify application */
1551 COMMAND_REPLY((SILC_ARGS));
1553 /* Generate the detachment data and deliver it to the client in the
1554 detach client operation */
1555 detach = silc_client_get_detach_data(cmd->client, conn);
1557 cmd->client->internal->ops->detach(cmd->client, conn,
1558 detach->data, detach->len);
1559 silc_buffer_free(detach);
1563 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1564 silc_client_command_reply_free(cmd);
1567 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1569 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1570 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1572 if (cmd->error != SILC_STATUS_OK) {
1573 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1574 "%s", silc_get_status_message(cmd->error));
1575 COMMAND_REPLY_ERROR(cmd->error);
1579 /* Notify application */
1580 COMMAND_REPLY((SILC_ARGS));
1583 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1584 silc_client_command_reply_free(cmd);
1587 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1589 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1590 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1591 SilcChannelEntry channel;
1592 SilcChannelID *channel_id;
1595 SilcBufferStruct buf;
1597 if (cmd->error != SILC_STATUS_OK) {
1598 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1599 "%s", silc_get_status_message(cmd->error));
1600 COMMAND_REPLY_ERROR(cmd->error);
1604 /* Take Channel ID */
1605 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1609 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1613 /* Get the channel entry */
1614 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1616 silc_free(channel_id);
1617 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1621 /* Get the ban list */
1622 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1624 silc_buffer_set(&buf, tmp, len);
1626 /* Notify application */
1627 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
1630 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1631 silc_client_command_reply_free(cmd);
1634 /* Reply to LEAVE command. */
1636 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1638 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1639 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1640 SilcChannelID *channel_id;
1641 SilcChannelEntry channel = NULL;
1642 SilcChannelUser chu;
1646 if (cmd->error != SILC_STATUS_OK) {
1647 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1648 "%s", silc_get_status_message(cmd->error));
1649 COMMAND_REPLY_ERROR(cmd->error);
1653 /* From protocol version 1.1 we get the channel ID of the left channel */
1654 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1656 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1660 /* Get the channel entry */
1661 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1663 silc_free(channel_id);
1664 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1668 /* Remove us from this channel. */
1669 chu = silc_client_on_channel(channel, conn->local_entry);
1671 silc_hash_table_del(chu->client->channels, chu->channel);
1672 silc_hash_table_del(chu->channel->user_list, chu->client);
1676 silc_free(channel_id);
1679 /* Notify application */
1680 COMMAND_REPLY((SILC_ARGS, channel));
1682 /* Now delete the channel. */
1684 silc_client_del_channel(cmd->client, conn, channel);
1687 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1688 silc_client_command_reply_free(cmd);
1691 /* Channel resolving callback for USERS command reply. */
1693 static void silc_client_command_reply_users_cb(SilcClient client,
1694 SilcClientConnection conn,
1695 SilcChannelEntry *channels,
1696 SilcUInt32 channels_count,
1699 if (!channels_count) {
1700 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1701 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1703 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1704 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1705 "%s", silc_get_status_message(cmd->error));
1706 COMMAND_REPLY_ERROR(cmd->error);
1707 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1708 silc_client_command_reply_free(cmd);
1712 silc_client_command_reply_users(context, NULL);
1716 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1720 SilcGetChannelCallback get_channel,
1721 SilcCommandCb get_clients)
1723 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1724 SilcChannelEntry channel;
1725 SilcClientEntry client_entry;
1726 SilcChannelUser chu;
1727 SilcChannelID *channel_id = NULL;
1728 SilcBufferStruct client_id_list, client_mode_list;
1730 SilcUInt32 tmp_len, list_count;
1732 unsigned char **res_argv = NULL;
1733 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1734 bool wait_res = FALSE;
1736 SILC_LOG_DEBUG(("Start"));
1738 /* Get channel ID */
1739 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1741 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1744 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1746 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1750 /* Get the list count */
1751 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1753 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1756 SILC_GET32_MSB(list_count, tmp);
1758 /* Get Client ID list */
1759 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1761 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1764 silc_buffer_set(&client_id_list, tmp, tmp_len);
1766 /* Get client mode list */
1767 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1769 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1772 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1774 /* Get channel entry */
1775 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1777 /* Resolve the channel from server */
1778 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1780 silc_free(channel_id);
1784 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1786 /* Cache the received Client ID's and modes. */
1787 for (i = 0; i < list_count; i++) {
1790 SilcClientID *client_id;
1793 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1795 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1800 SILC_GET32_MSB(mode, client_mode_list.data);
1802 /* Check if we have this client cached already. */
1803 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1804 if (!client_entry || !client_entry->username || !client_entry->realname) {
1806 /* No we don't have it (or it is incomplete in information), query
1807 it from the server. Assemble argument table that will be sent
1808 for the WHOIS command later. */
1809 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1811 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1813 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1815 res_argv[res_argc] = client_id_list.data;
1816 res_argv_lens[res_argc] = idp_len;
1817 res_argv_types[res_argc] = res_argc + 4;
1821 if (!silc_client_on_channel(channel, client_entry)) {
1822 chu = silc_calloc(1, sizeof(*chu));
1823 chu->client = client_entry;
1825 chu->channel = channel;
1826 silc_hash_table_add(channel->user_list, client_entry, chu);
1827 silc_hash_table_add(client_entry->channels, channel, chu);
1831 silc_free(client_id);
1832 silc_buffer_pull(&client_id_list, idp_len);
1833 silc_buffer_pull(&client_mode_list, 4);
1836 /* Query the client information from server if the list included clients
1837 that we don't know about. */
1841 /* Send the WHOIS command to server */
1842 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1843 silc_client_command_reply_whois_i, 0,
1845 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1846 res_argc, res_argv, res_argv_lens,
1847 res_argv_types, conn->cmd_ident);
1848 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1849 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1852 /* Register pending command callback. After we've received the WHOIS
1853 command reply we will reprocess this command reply by re-calling this
1854 USERS command reply callback. */
1855 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1858 silc_buffer_free(res_cmd);
1859 silc_free(channel_id);
1860 silc_free(res_argv);
1861 silc_free(res_argv_lens);
1862 silc_free(res_argv_types);
1869 silc_buffer_push(&client_id_list, (client_id_list.data -
1870 client_id_list.head));
1871 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1872 client_mode_list.head));
1874 /* Notify application */
1876 COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list,
1877 &client_mode_list));
1880 silc_free(channel_id);
1884 /* Reply to USERS command. Received list of client ID's and theirs modes
1885 on the channel we requested. */
1887 SILC_CLIENT_CMD_REPLY_FUNC(users)
1889 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1890 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1891 SilcClientCommandReplyContext r = (SilcClientCommandReplyContext)context2;
1893 SILC_LOG_DEBUG(("Start"));
1895 if (cmd->error != SILC_STATUS_OK) {
1896 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1897 "Query failed: %s", silc_get_status_message(cmd->error));
1898 COMMAND_REPLY_ERROR(cmd->error);
1902 if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) {
1903 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1904 /* Do not resolve anymore. Server may be sending us some non-existent
1905 Client ID (a bug in server), and we want to show the users list
1907 silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE,
1908 silc_client_command_reply_users_cb,
1909 silc_client_command_reply_users);
1912 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1913 "Query failed: %s", silc_get_status_message(cmd->error));
1914 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1919 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE,
1920 silc_client_command_reply_users_cb,
1921 silc_client_command_reply_users))
1925 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1926 silc_client_command_reply_free(cmd);
1929 /* Received command reply to GETKEY command. WE've received the remote
1930 client's public key. */
1932 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1934 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1935 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1936 SilcIDPayload idp = NULL;
1937 SilcClientID *client_id = NULL;
1938 SilcClientEntry client_entry;
1939 SilcServerID *server_id = NULL;
1940 SilcServerEntry server_entry;
1944 SilcPublicKey public_key = NULL;
1946 SILC_LOG_DEBUG(("Start"));
1948 if (cmd->error != SILC_STATUS_OK) {
1949 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1950 "%s", silc_get_status_message(cmd->error));
1951 COMMAND_REPLY_ERROR(cmd->error);
1955 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1957 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1960 idp = silc_id_payload_parse(tmp, len);
1962 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1966 /* Get the public key payload */
1967 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1969 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1974 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1978 id_type = silc_id_payload_get_type(idp);
1979 if (id_type == SILC_ID_CLIENT) {
1980 /* Received client's public key */
1981 client_id = silc_id_payload_get_id(idp);
1982 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1983 if (!client_entry) {
1984 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1988 /* Save fingerprint */
1989 if (!client_entry->fingerprint) {
1990 client_entry->fingerprint = silc_calloc(20, sizeof(unsigned char));
1991 client_entry->fingerprint_len = 20;
1992 silc_hash_make(cmd->client->sha1hash, tmp + 4, len - 4,
1993 client_entry->fingerprint);
1995 if (!client_entry->public_key) {
1996 client_entry->public_key = public_key;
2000 /* Notify application */
2001 COMMAND_REPLY((SILC_ARGS, id_type, client_entry,
2002 client_entry->public_key));
2003 } else if (id_type == SILC_ID_SERVER) {
2004 /* Received server's public key */
2005 server_id = silc_id_payload_get_id(idp);
2006 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
2007 if (!server_entry) {
2008 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2012 /* Notify application */
2013 COMMAND_REPLY((SILC_ARGS, id_type, server_entry, public_key));
2017 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
2019 silc_id_payload_free(idp);
2021 silc_pkcs_public_key_free(public_key);
2022 silc_free(client_id);
2023 silc_free(server_id);
2024 silc_client_command_reply_free(cmd);
2027 SILC_CLIENT_CMD_REPLY_FUNC(quit)
2029 silc_client_command_reply_free(context);
2033 /******************************************************************************
2035 Internal command reply functions
2037 ******************************************************************************/
2039 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
2041 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2042 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2044 COMMAND_CHECK_STATUS_I;
2046 /* Save WHOIS info */
2047 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
2049 /* Pending callbacks are not executed if this was an list entry */
2050 if (cmd->status != SILC_STATUS_OK &&
2051 cmd->status != SILC_STATUS_LIST_END) {
2052 silc_client_command_reply_free(cmd);
2057 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
2060 /* If we received notify for invalid ID we'll remove the ID if we
2062 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2063 SilcClientEntry client_entry;
2065 unsigned char *tmp =
2066 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2069 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2071 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2074 silc_client_del_client(cmd->client, conn, client_entry);
2075 silc_free(client_id);
2080 /* Unregister this command reply */
2081 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2082 NULL, silc_client_command_reply_whois_i,
2085 silc_client_command_reply_free(cmd);
2088 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2090 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2091 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2093 COMMAND_CHECK_STATUS_I;
2095 /* Save IDENTIFY info */
2096 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
2098 /* Pending callbacks are not executed if this was an list entry */
2099 if (cmd->status != SILC_STATUS_OK &&
2100 cmd->status != SILC_STATUS_LIST_END) {
2101 silc_client_command_reply_free(cmd);
2106 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2109 /* If we received notify for invalid ID we'll remove the ID if we
2111 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2112 SilcClientEntry client_entry;
2114 unsigned char *tmp =
2115 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2118 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2120 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2123 silc_client_del_client(cmd->client, conn, client_entry);
2124 silc_free(client_id);
2129 /* Unregister this command reply */
2130 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2131 NULL, silc_client_command_reply_identify_i,
2134 silc_client_command_reply_free(cmd);
2137 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2139 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2140 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2142 SilcServerEntry server;
2143 SilcServerID *server_id = NULL;
2144 char *server_name, *server_info;
2147 COMMAND_CHECK_STATUS_I;
2150 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2154 server_id = silc_id_payload_parse_id(tmp, len, NULL);
2158 /* Get server name */
2159 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2163 /* Get server info */
2164 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2168 /* See whether we have this server cached. If not create it. */
2169 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
2171 SILC_LOG_DEBUG(("New server entry"));
2172 silc_client_add_server(cmd->client, conn, server_name, server_info,
2173 silc_id_dup(server_id, SILC_ID_SERVER));
2177 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2178 silc_free(server_id);
2180 silc_client_command_reply_free(cmd);
2183 static void silc_client_command_reply_users_i_cb(SilcClient client,
2184 SilcClientConnection conn,
2185 SilcChannelEntry *channels,
2186 SilcUInt32 channels_count,
2189 if (!channels_count) {
2190 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2191 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2193 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2194 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2195 "%s", silc_get_status_message(cmd->error));
2196 COMMAND_REPLY_ERROR(cmd->error);
2197 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2198 silc_client_command_reply_free(cmd);
2202 silc_client_command_reply_users_i(context, NULL);
2205 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2207 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2209 COMMAND_CHECK_STATUS_I;
2211 /* Save USERS info */
2212 if (silc_client_command_reply_users_save(
2213 cmd, cmd->status, FALSE, TRUE,
2214 silc_client_command_reply_users_i_cb,
2215 silc_client_command_reply_users_i))
2219 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2222 /* Unregister this command reply */
2223 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2224 NULL, silc_client_command_reply_users_i,
2227 silc_client_command_reply_free(cmd);
2230 /* Private range commands, specific to this implementation (and compatible
2231 with SILC Server >= 0.9). */
2233 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2235 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2236 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2238 if (cmd->error != SILC_STATUS_OK) {
2239 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2240 "%s", silc_get_status_message(cmd->error));
2241 COMMAND_REPLY_ERROR(cmd->error);
2245 /* Notify application */
2246 COMMAND_REPLY((SILC_ARGS));
2249 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2250 silc_client_command_reply_free(cmd);
2253 SILC_CLIENT_CMD_REPLY_FUNC(close)
2255 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2256 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2258 if (cmd->error != SILC_STATUS_OK) {
2259 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2260 "%s", silc_get_status_message(cmd->error));
2261 COMMAND_REPLY_ERROR(cmd->error);
2265 /* Notify application */
2266 COMMAND_REPLY((SILC_ARGS));
2269 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2270 silc_client_command_reply_free(cmd);
2273 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2275 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2276 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2278 if (cmd->error != SILC_STATUS_OK) {
2279 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2280 "%s", silc_get_status_message(cmd->error));
2281 COMMAND_REPLY_ERROR(cmd->error);
2285 /* Notify application */
2286 COMMAND_REPLY((SILC_ARGS));
2289 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2290 silc_client_command_reply_free(cmd);