5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2004 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 * Command reply functions are "the otherside" of the command functions.
22 * Reply to a command sent by server is handled by these functions.
24 * The arguments received from server are also passed to the calling
25 * application through command_reply client operation. The arguments are
26 * exactly same and in same order as the server sent it. However, ID's are
27 * not sent to the application. Instead, corresponding ID entry is sent
28 * to the application. For example, instead of sending Client ID the
29 * corresponding SilcClientEntry is sent to the application. The case is
30 * same with for example Channel ID's. This way application has all the
31 * necessary data already in hand without redundant searching. If ID is
32 * received but ID entry does not exist, NULL is sent.
35 #include "silcincludes.h"
36 #include "silcclient.h"
37 #include "client_internal.h"
39 #define SAY cmd->client->internal->ops->say
41 /* All functions that call the COMMAND_CHECK_STATUS macro must have
42 out: and err: goto labels. out label should call the pending
43 command replies, and the err label just handle error condition. */
45 #define COMMAND_CHECK_STATUS \
47 SILC_LOG_DEBUG(("Start")); \
48 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
49 if (SILC_STATUS_IS_ERROR(cmd->status)) { \
51 COMMAND_REPLY_ERROR(cmd->status); \
54 /* List of errors */ \
55 COMMAND_REPLY_ERROR(cmd->error); \
56 if (cmd->status == SILC_STATUS_LIST_END) \
62 /* Same as COMMAND_CHECK_STATUS but doesn't call client operation */
63 #define COMMAND_CHECK_STATUS_I \
65 SILC_LOG_DEBUG(("Start")); \
66 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
67 if (SILC_STATUS_IS_ERROR(cmd->status)) \
69 if (cmd->status == SILC_STATUS_LIST_END) \
75 /* Process received command reply. */
77 void silc_client_command_reply_process(SilcClient client,
78 SilcSocketConnection sock,
79 SilcPacketContext *packet)
81 SilcBuffer buffer = packet->buffer;
82 SilcClientCommand cmd;
83 SilcClientCommandReplyContext ctx;
84 SilcCommandPayload payload;
86 SilcCommandCb reply = NULL;
88 /* Get command reply payload from packet */
89 payload = silc_command_payload_parse(buffer->data, buffer->len);
91 /* Silently ignore bad reply packet */
92 SILC_LOG_DEBUG(("Bad command reply packet"));
96 /* Allocate command reply context. This must be free'd by the
97 command reply routine receiving it. */
98 ctx = silc_calloc(1, sizeof(*ctx));
100 ctx->client = client;
102 ctx->payload = payload;
103 ctx->args = silc_command_get_args(ctx->payload);
104 ctx->packet = packet;
105 ctx->ident = silc_command_get_ident(ctx->payload);
106 silc_command_get_status(ctx->payload, &ctx->status, &ctx->error);
108 /* Check for pending commands and mark to be exeucted */
110 silc_client_command_pending_check(sock->user_data, ctx,
111 silc_command_get(ctx->payload),
112 ctx->ident, &ctx->callbacks_count);
114 /* Execute command reply */
116 command = silc_command_get(ctx->payload);
118 /* Try to find matching the command identifier */
119 silc_list_start(client->internal->commands);
120 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
121 if (cmd->cmd == command && !cmd->ident)
123 if (cmd->cmd == command && cmd->ident == ctx->ident) {
124 (*cmd->reply)((void *)ctx, NULL);
129 if (cmd == SILC_LIST_END) {
131 /* No specific identifier for command reply, call first one found */
138 /* Duplicate Command Reply Context by adding reference counter. The context
139 won't be free'd untill it hits zero. */
141 SilcClientCommandReplyContext
142 silc_client_command_reply_dup(SilcClientCommandReplyContext cmd)
145 SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
146 cmd->users - 1, cmd->users));
150 /* Free command reply context and its internals. */
152 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
155 SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
156 cmd->users + 1, cmd->users));
157 if (cmd->users < 1) {
158 silc_command_payload_free(cmd->payload);
164 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
168 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
169 SilcClientID *client_id;
170 SilcClientEntry client_entry = NULL;
172 unsigned char *id_data, *tmp;
173 char *nickname = NULL, *username = NULL;
174 char *realname = NULL;
175 SilcUInt32 idle = 0, mode = 0;
176 SilcBufferStruct channels, ch_user_modes;
177 bool has_channels = FALSE, has_user_modes = FALSE;
178 unsigned char *fingerprint;
179 SilcUInt32 fingerprint_len;
181 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
184 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
188 client_id = silc_id_payload_parse_id(id_data, len, NULL);
191 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
195 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
196 username = silc_argument_get_arg_type(cmd->args, 4, &len);
197 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
198 if (!nickname || !username || !realname) {
200 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
204 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
206 silc_buffer_set(&channels, tmp, len);
210 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
212 SILC_GET32_MSB(mode, tmp);
214 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
216 SILC_GET32_MSB(idle, tmp);
218 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
220 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
222 silc_buffer_set(&ch_user_modes, tmp, len);
223 has_user_modes = TRUE;
226 /* Check if we have this client cached already. */
227 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
229 SILC_LOG_DEBUG(("Adding new client entry"));
231 silc_client_add_client(cmd->client, conn, nickname, username, realname,
234 silc_client_update_client(cmd->client, conn, client_entry,
235 nickname, username, realname, mode);
236 silc_free(client_id);
239 if (fingerprint && !client_entry->fingerprint) {
240 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
241 client_entry->fingerprint_len = fingerprint_len;
244 /* Take Requested Attributes if set. */
245 tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
247 if (client_entry->attrs)
248 silc_attribute_payload_list_free(client_entry->attrs);
249 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
252 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
254 /* Notify application */
255 if (!cmd->callbacks_count && notify)
256 COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname,
257 has_channels ? &channels : NULL, mode, idle,
258 fingerprint, has_user_modes ? &ch_user_modes : NULL,
259 client_entry->attrs));
262 /* Received reply for WHOIS command. This maybe called several times
263 for one WHOIS command as server may reply with list of results. */
265 SILC_CLIENT_CMD_REPLY_FUNC(whois)
267 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
268 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
270 COMMAND_CHECK_STATUS;
272 /* Save WHOIS info */
273 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
275 /* Pending callbacks are not executed if this was an list entry */
276 if (cmd->status != SILC_STATUS_OK &&
277 cmd->status != SILC_STATUS_LIST_END) {
278 silc_client_command_reply_free(cmd);
283 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
286 /* If we received notify for invalid ID we'll remove the ID if we
288 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
289 SilcClientEntry client_entry;
292 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
295 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
297 client_entry = silc_client_get_client_by_id(cmd->client, conn,
300 silc_client_del_client(cmd->client, conn, client_entry);
301 silc_free(client_id);
306 silc_client_command_reply_free(cmd);
309 /* Received reply for WHOWAS command. */
311 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
313 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
314 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
315 SilcClientID *client_id;
316 SilcClientEntry client_entry = NULL;
318 unsigned char *id_data;
319 char *nickname, *username;
320 char *realname = NULL;
322 COMMAND_CHECK_STATUS;
324 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
326 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
330 client_id = silc_id_payload_parse_id(id_data, len, NULL);
332 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
336 /* Get the client entry, if exists */
337 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
338 silc_free(client_id);
340 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
341 username = silc_argument_get_arg_type(cmd->args, 4, &len);
342 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
343 if (!nickname || !username) {
344 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
348 /* Notify application. We don't save any history information to any
349 cache. Just pass the data to the application for displaying on
351 COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname));
353 /* Pending callbacks are not executed if this was an list entry */
354 if (cmd->status != SILC_STATUS_OK &&
355 cmd->status != SILC_STATUS_LIST_END) {
356 silc_client_command_reply_free(cmd);
361 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
363 silc_client_command_reply_free(cmd);
367 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
371 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
372 SilcClient client = cmd->client;
373 SilcClientID *client_id = NULL;
374 SilcServerID *server_id = NULL;
375 SilcChannelID *channel_id = NULL;
376 SilcClientEntry client_entry;
377 SilcServerEntry server_entry;
378 SilcChannelEntry channel_entry;
380 unsigned char *id_data;
381 char *name = NULL, *info = NULL;
382 SilcIDPayload idp = NULL;
385 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
388 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
391 idp = silc_id_payload_parse(id_data, len);
394 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
398 name = silc_argument_get_arg_type(cmd->args, 3, &len);
399 info = silc_argument_get_arg_type(cmd->args, 4, &len);
401 id_type = silc_id_payload_get_type(idp);
405 client_id = silc_id_payload_get_id(idp);
407 SILC_LOG_DEBUG(("Received client information"));
409 /* Check if we have this client cached already. */
410 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
412 SILC_LOG_DEBUG(("Adding new client entry"));
414 silc_client_add_client(cmd->client, conn, name, info, NULL,
415 silc_id_dup(client_id, id_type), 0);
417 silc_client_update_client(cmd->client, conn, client_entry,
418 name, info, NULL, 0);
421 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
423 /* Notify application */
425 COMMAND_REPLY((SILC_ARGS, client_entry, name, info));
429 server_id = silc_id_payload_get_id(idp);
431 SILC_LOG_DEBUG(("Received server information"));
433 /* Check if we have this server cached already. */
434 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
436 SILC_LOG_DEBUG(("Adding new server entry"));
437 server_entry = silc_client_add_server(cmd->client, conn, name, info,
438 silc_id_dup(server_id, id_type));
441 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
445 silc_client_update_server(client, conn, server_entry, name, info);
448 server_entry->resolve_cmd_ident = 0;
450 /* Notify application */
452 COMMAND_REPLY((SILC_ARGS, server_entry, name, info));
455 case SILC_ID_CHANNEL:
456 channel_id = silc_id_payload_get_id(idp);
458 SILC_LOG_DEBUG(("Received channel information"));
460 /* Check if we have this channel cached already. */
461 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
462 if (!channel_entry) {
466 /* Add new channel entry */
467 channel_entry = silc_client_add_channel(client, conn, name, 0,
472 /* Notify application */
474 COMMAND_REPLY((SILC_ARGS, channel_entry, name, info));
478 silc_id_payload_free(idp);
479 silc_free(client_id);
480 silc_free(server_id);
481 silc_free(channel_id);
484 /* Received reply for IDENTIFY command. This maybe called several times
485 for one IDENTIFY command as server may reply with list of results.
486 This is totally silent and does not print anything on screen. */
488 SILC_CLIENT_CMD_REPLY_FUNC(identify)
490 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
491 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
493 COMMAND_CHECK_STATUS;
495 /* Save IDENTIFY info */
496 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
498 /* Pending callbacks are not executed if this was an list entry */
499 if (cmd->status != SILC_STATUS_OK &&
500 cmd->status != SILC_STATUS_LIST_END) {
501 silc_client_command_reply_free(cmd);
506 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
509 /* If we received notify for invalid ID we'll remove the ID if we
511 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
512 SilcClientEntry client_entry;
515 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
518 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
520 client_entry = silc_client_get_client_by_id(cmd->client, conn,
523 silc_client_del_client(cmd->client, conn, client_entry);
524 silc_free(client_id);
529 silc_client_command_reply_free(cmd);
532 /* Received reply for command NICK. If everything went without errors
533 we just received our new Client ID. */
535 SILC_CLIENT_CMD_REPLY_FUNC(nick)
537 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
538 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
541 SilcUInt32 argc, len;
542 SilcClientID old_client_id;
544 SILC_LOG_DEBUG(("Start"));
546 if (cmd->error != SILC_STATUS_OK) {
547 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
548 "Cannot set nickname: %s",
549 silc_get_status_message(cmd->error));
550 COMMAND_REPLY_ERROR(cmd->error);
554 argc = silc_argument_get_arg_num(cmd->args);
555 if (argc < 2 || argc > 3) {
556 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
557 "Cannot set nickname: bad reply to command");
558 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
562 /* Save old Client ID */
563 old_client_id = *conn->local_id;
565 /* Take received Client ID */
566 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
567 idp = silc_id_payload_parse(tmp, len);
569 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
572 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
574 /* Take the new nickname too */
575 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
577 silc_idcache_del_by_context(conn->internal->client_cache,
580 silc_free(conn->nickname);
581 conn->nickname = strdup(tmp);
582 conn->local_entry->nickname = conn->nickname;
583 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
584 silc_idcache_add(conn->internal->client_cache, strdup(tmp),
585 conn->local_entry->id, conn->local_entry, 0, NULL);
588 /* Notify application */
589 COMMAND_REPLY((SILC_ARGS, conn->local_entry, conn->local_entry->nickname,
590 (const SilcClientID *)&old_client_id));
593 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
594 silc_client_command_reply_free(cmd);
597 /* Received reply to the LIST command. */
599 SILC_CLIENT_CMD_REPLY_FUNC(list)
601 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
602 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
603 unsigned char *tmp, *name, *topic;
604 SilcUInt32 usercount = 0, len;
605 SilcChannelID *channel_id = NULL;
606 SilcChannelEntry channel_entry;
608 COMMAND_CHECK_STATUS;
610 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
612 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
616 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
618 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
622 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
624 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
628 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
629 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
631 SILC_GET32_MSB(usercount, tmp);
633 /* Check whether the channel exists, and add it to cache if it doesn't. */
634 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
636 if (!channel_entry) {
637 /* Add new channel entry */
638 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
640 if (!channel_entry) {
641 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
647 /* Notify application */
648 COMMAND_REPLY((SILC_ARGS, channel_entry, name, topic, usercount));
650 /* Pending callbacks are not executed if this was an list entry */
651 if (cmd->status != SILC_STATUS_OK &&
652 cmd->status != SILC_STATUS_LIST_END) {
653 silc_client_command_reply_free(cmd);
658 silc_free(channel_id);
659 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
661 silc_client_command_reply_free(cmd);
664 /* Received reply to topic command. */
666 SILC_CLIENT_CMD_REPLY_FUNC(topic)
668 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
669 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
670 SilcChannelEntry channel;
671 SilcChannelID *channel_id = NULL;
674 SilcUInt32 argc, len;
676 if (cmd->error != SILC_STATUS_OK) {
677 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
678 "Cannot set topic: %s", silc_get_status_message(cmd->error));
679 COMMAND_REPLY_ERROR(cmd->error);
683 argc = silc_argument_get_arg_num(cmd->args);
684 if (argc < 1 || argc > 3) {
685 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
689 /* Take Channel ID */
690 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
695 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
699 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
703 /* Get the channel entry */
704 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
706 silc_free(channel_id);
707 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
712 silc_free(channel->topic);
713 channel->topic = silc_memdup(topic, strlen(topic));
716 /* Notify application */
717 COMMAND_REPLY((SILC_ARGS, channel, topic));
720 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
721 silc_client_command_reply_free(cmd);
724 /* Received reply to invite command. */
726 SILC_CLIENT_CMD_REPLY_FUNC(invite)
728 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
729 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
730 SilcChannelEntry channel;
731 SilcChannelID *channel_id;
734 SilcBufferStruct buf;
736 if (cmd->error != SILC_STATUS_OK) {
737 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
738 "Cannot invite: %s", silc_get_status_message(cmd->error));
739 COMMAND_REPLY_ERROR(cmd->error);
743 /* Take Channel ID */
744 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
748 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
752 /* Get the channel entry */
753 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
755 silc_free(channel_id);
756 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
760 /* Get the invite list */
761 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
763 silc_buffer_set(&buf, tmp, len);
765 /* Notify application */
766 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
769 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
770 silc_client_command_reply_free(cmd);
773 /* Received reply to the KILL command. */
775 SILC_CLIENT_CMD_REPLY_FUNC(kill)
777 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
778 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
779 SilcClientID *client_id;
780 SilcClientEntry client_entry = NULL;
782 unsigned char *id_data;
784 if (cmd->error != SILC_STATUS_OK) {
785 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
786 "Cannot kill: %s", silc_get_status_message(cmd->error));
787 COMMAND_REPLY_ERROR(cmd->error);
791 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
793 client_id = silc_id_payload_parse_id(id_data, len, NULL);
795 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
799 /* Get the client entry, if exists */
800 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
801 silc_free(client_id);
804 /* Notify application */
805 COMMAND_REPLY((SILC_ARGS, client_entry));
808 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
809 silc_client_command_reply_free(cmd);
812 /* Received reply to INFO command. We receive the server ID and some
813 information about the server user requested. */
815 SILC_CLIENT_CMD_REPLY_FUNC(info)
817 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
818 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
820 SilcServerEntry server;
821 SilcServerID *server_id = NULL;
822 char *server_name, *server_info;
825 SILC_LOG_DEBUG(("Start"));
827 if (cmd->error != SILC_STATUS_OK) {
828 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
829 silc_get_status_message(cmd->error));
830 COMMAND_REPLY_ERROR(cmd->error);
835 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
839 server_id = silc_id_payload_parse_id(tmp, len, NULL);
843 /* Get server name */
844 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
848 /* Get server info */
849 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
853 /* See whether we have this server cached. If not create it. */
854 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
856 SILC_LOG_DEBUG(("New server entry"));
857 server = silc_client_add_server(cmd->client, conn, server_name,
859 silc_id_dup(server_id, SILC_ID_SERVER));
864 /* Notify application */
865 COMMAND_REPLY((SILC_ARGS, server, server->server_name, server->server_info));
868 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
869 silc_free(server_id);
870 silc_client_command_reply_free(cmd);
873 /* Received reply to STATS command. */
875 SILC_CLIENT_CMD_REPLY_FUNC(stats)
877 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
878 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
879 unsigned char *tmp, *buf = NULL;
880 SilcUInt32 len, buf_len = 0;
882 if (cmd->error != SILC_STATUS_OK) {
883 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
884 "%s", silc_get_status_message(cmd->error));
885 COMMAND_REPLY_ERROR(cmd->error);
890 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
894 /* Get statistics structure */
895 buf = silc_argument_get_arg_type(cmd->args, 3, &buf_len);
897 /* Notify application */
898 COMMAND_REPLY((SILC_ARGS, buf, buf_len));
901 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
902 silc_client_command_reply_free(cmd);
905 /* Received reply to PING command. The reply time is shown to user. */
907 SILC_CLIENT_CMD_REPLY_FUNC(ping)
909 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
910 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
913 time_t diff, curtime;
915 if (cmd->error != SILC_STATUS_OK) {
916 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
917 "%s", silc_get_status_message(cmd->error));
918 COMMAND_REPLY_ERROR(cmd->error);
922 curtime = time(NULL);
923 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
924 cmd->packet->src_id_type);
925 if (!id || !conn->internal->ping) {
926 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
930 for (i = 0; i < conn->internal->ping_count; i++) {
931 if (!conn->internal->ping[i].dest_id)
933 if (SILC_ID_SERVER_COMPARE(conn->internal->ping[i].dest_id, id)) {
934 diff = curtime - conn->internal->ping[i].start_time;
935 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
936 "Ping reply from %s: %d second%s",
937 conn->internal->ping[i].dest_name, diff,
938 diff == 1 ? "" : "s");
940 conn->internal->ping[i].start_time = 0;
941 silc_free(conn->internal->ping[i].dest_id);
942 conn->internal->ping[i].dest_id = NULL;
943 silc_free(conn->internal->ping[i].dest_name);
944 conn->internal->ping[i].dest_name = NULL;
951 /* Notify application */
952 COMMAND_REPLY((SILC_ARGS));
955 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
956 silc_client_command_reply_free(cmd);
959 /* Received reply for JOIN command. */
961 SILC_CLIENT_CMD_REPLY_FUNC(join)
963 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
964 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
965 SilcChannelEntry channel;
967 SilcChannelID *channel_id;
968 SilcUInt32 argc, mode = 0, len, list_count;
969 char *topic, *tmp, *channel_name = NULL, *hmac;
970 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
971 SilcBufferStruct chpklist;
974 SILC_LOG_DEBUG(("Start"));
976 if (cmd->error != SILC_STATUS_OK) {
977 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
978 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
979 "Cannot join channel: %s", silc_get_status_message(cmd->error));
980 COMMAND_REPLY_ERROR(cmd->error);
984 argc = silc_argument_get_arg_num(cmd->args);
986 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
987 "Cannot join channel: Bad reply packet");
988 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
992 /* Get channel name */
993 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
995 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
996 "Cannot join channel: Bad reply packet");
997 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1002 /* Get Channel ID */
1003 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1005 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1006 "Cannot join channel: Bad reply packet");
1007 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1010 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1012 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1016 /* Get channel mode */
1017 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1019 SILC_GET32_MSB(mode, tmp);
1021 /* Get channel key */
1022 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1024 keyp = silc_buffer_alloc(len);
1025 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1026 silc_buffer_put(keyp, tmp, len);
1030 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1032 /* Check whether we have this channel entry already. */
1033 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1035 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
1036 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
1038 /* Create new channel entry */
1039 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1043 conn->current_channel = channel;
1044 channel->mode = mode;
1047 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1049 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1050 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1051 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1052 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1057 /* Get the list count */
1058 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1061 SILC_GET32_MSB(list_count, tmp);
1063 /* Get Client ID list */
1064 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1068 client_id_list = silc_buffer_alloc(len);
1069 silc_buffer_pull_tail(client_id_list, len);
1070 silc_buffer_put(client_id_list, tmp, len);
1072 /* Get client mode list */
1073 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1077 client_mode_list = silc_buffer_alloc(len);
1078 silc_buffer_pull_tail(client_mode_list, len);
1079 silc_buffer_put(client_mode_list, tmp, len);
1081 /* Add clients we received in the reply to the channel */
1082 for (i = 0; i < list_count; i++) {
1085 SilcClientID *client_id;
1086 SilcClientEntry client_entry;
1089 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1091 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1096 SILC_GET32_MSB(mode, client_mode_list->data);
1098 /* Check if we have this client cached already. */
1099 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1100 if (!client_entry) {
1101 /* No, we don't have it, add entry for it. */
1103 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1104 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1107 /* Join client to the channel */
1108 if (!silc_client_on_channel(channel, client_entry)) {
1109 chu = silc_calloc(1, sizeof(*chu));
1110 chu->client = client_entry;
1111 chu->channel = channel;
1113 silc_hash_table_add(channel->user_list, client_entry, chu);
1114 silc_hash_table_add(client_entry->channels, channel, chu);
1117 silc_free(client_id);
1118 silc_buffer_pull(client_id_list, idp_len);
1119 silc_buffer_pull(client_mode_list, 4);
1121 silc_buffer_push(client_id_list, client_id_list->data -
1122 client_id_list->head);
1123 silc_buffer_push(client_mode_list, client_mode_list->data -
1124 client_mode_list->head);
1126 /* Save channel key */
1128 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1130 /* Get founder key */
1131 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
1133 if (channel->founder_key)
1134 silc_pkcs_public_key_free(channel->founder_key);
1135 channel->founder_key = NULL;
1136 silc_pkcs_public_key_payload_decode(tmp, len, &channel->founder_key);
1139 /* Get user limit */
1140 tmp = silc_argument_get_arg_type(cmd->args, 17, &len);
1141 if (tmp && len == 4)
1142 SILC_GET32_MSB(channel->user_limit, tmp);
1143 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1144 channel->user_limit = 0;
1146 /* Get channel public key list */
1147 tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
1149 silc_buffer_set(&chpklist, tmp, len);
1152 silc_free(channel->topic);
1153 channel->topic = silc_memdup(topic, strlen(topic));
1156 /* Notify application */
1157 COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0,
1158 keyp ? keyp->head : NULL, NULL,
1159 NULL, topic, hmac, list_count, client_id_list,
1160 client_mode_list, channel->founder_key,
1161 tmp ? &chpklist : NULL, channel->user_limit));
1164 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1165 silc_client_command_reply_free(cmd);
1166 silc_buffer_free(keyp);
1167 silc_buffer_free(client_id_list);
1168 silc_buffer_free(client_mode_list);
1171 /* Received reply for MOTD command */
1173 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1175 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1176 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1178 char *motd = NULL, *cp, line[256];
1180 if (cmd->error != SILC_STATUS_OK) {
1181 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1182 "%s", silc_get_status_message(cmd->error));
1183 COMMAND_REPLY_ERROR(cmd->error);
1187 argc = silc_argument_get_arg_num(cmd->args);
1189 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1194 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1196 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1203 if (cp[i++] == '\n') {
1204 memset(line, 0, sizeof(line));
1205 silc_strncat(line, sizeof(line), cp, i - 1);
1211 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1220 /* Notify application */
1221 COMMAND_REPLY((SILC_ARGS, motd));
1224 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1225 silc_client_command_reply_free(cmd);
1228 /* Received reply tot he UMODE command. Save the current user mode */
1230 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1232 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1233 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1237 if (cmd->error != SILC_STATUS_OK) {
1238 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1239 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1240 COMMAND_REPLY_ERROR(cmd->error);
1244 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1246 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1250 SILC_GET32_MSB(mode, tmp);
1251 conn->local_entry->mode = mode;
1253 /* Notify application */
1254 COMMAND_REPLY((SILC_ARGS, mode));
1257 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1258 silc_client_command_reply_free(cmd);
1261 /* Received reply for CMODE command. */
1263 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1265 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1266 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1269 SilcChannelID *channel_id;
1270 SilcChannelEntry channel;
1272 SilcPublicKey public_key = NULL;
1273 SilcBufferStruct channel_pubkeys;
1275 if (cmd->error != SILC_STATUS_OK) {
1276 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1277 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1278 COMMAND_REPLY_ERROR(cmd->error);
1282 /* Take Channel ID */
1283 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1286 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1290 /* Get the channel entry */
1291 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1293 silc_free(channel_id);
1294 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1298 /* Get channel mode */
1299 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1301 silc_free(channel_id);
1302 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1307 SILC_GET32_MSB(mode, tmp);
1308 channel->mode = mode;
1310 /* Get founder public key */
1311 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
1313 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1317 /* Get user limit */
1318 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
1319 if (tmp && len == 4)
1320 SILC_GET32_MSB(channel->user_limit, tmp);
1321 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1322 channel->user_limit = 0;
1324 /* Get channel public key(s) */
1325 tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
1327 silc_buffer_set(&channel_pubkeys, tmp, len);
1329 /* Notify application */
1330 COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
1331 tmp ? &channel_pubkeys : NULL, channel->user_limit));
1333 silc_free(channel_id);
1337 silc_pkcs_public_key_free(public_key);
1338 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1339 silc_client_command_reply_free(cmd);
1342 /* Received reply for CUMODE command */
1344 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1346 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1347 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1348 SilcClientID *client_id;
1349 SilcChannelID *channel_id;
1350 SilcClientEntry client_entry;
1351 SilcChannelEntry channel;
1352 SilcChannelUser chu;
1353 unsigned char *modev, *tmp, *id;
1354 SilcUInt32 len, mode;
1356 if (cmd->error != SILC_STATUS_OK) {
1357 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1358 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1359 COMMAND_REPLY_ERROR(cmd->error);
1363 /* Get channel mode */
1364 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1366 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1370 /* Take Channel ID */
1371 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1374 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1378 /* Get the channel entry */
1379 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1381 silc_free(channel_id);
1382 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1387 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1389 silc_free(channel_id);
1390 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1393 client_id = silc_id_payload_parse_id(id, len, NULL);
1395 silc_free(channel_id);
1396 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1400 /* Get client entry */
1401 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1402 if (!client_entry) {
1403 silc_free(channel_id);
1404 silc_free(client_id);
1405 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1410 SILC_GET32_MSB(mode, modev);
1411 chu = silc_client_on_channel(channel, client_entry);
1415 /* Notify application */
1416 COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry));
1417 silc_free(client_id);
1418 silc_free(channel_id);
1421 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1422 silc_client_command_reply_free(cmd);
1425 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1427 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1428 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1429 SilcClientID *client_id = NULL;
1430 SilcChannelID *channel_id = NULL;
1431 SilcClientEntry client_entry = NULL;
1432 SilcChannelEntry channel = NULL;
1436 if (cmd->error != SILC_STATUS_OK) {
1437 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1438 "Cannot kick: %s", silc_get_status_message(cmd->error));
1439 COMMAND_REPLY_ERROR(cmd->error);
1443 /* Take Channel ID */
1444 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1446 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1448 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1452 /* Get the channel entry */
1453 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1455 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1461 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1463 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1465 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1469 /* Get client entry */
1470 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1471 if (!client_entry) {
1472 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1477 /* Notify application */
1478 COMMAND_REPLY((SILC_ARGS, channel, client_entry));
1481 silc_free(channel_id);
1482 silc_free(client_id);
1483 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1484 silc_client_command_reply_free(cmd);
1487 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1489 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1490 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1492 if (cmd->error != SILC_STATUS_OK) {
1493 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1494 "%s", silc_get_status_message(cmd->error));
1495 COMMAND_REPLY_ERROR(cmd->error);
1499 /* Notify application */
1500 COMMAND_REPLY((SILC_ARGS));
1503 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1504 silc_client_command_reply_free(cmd);
1507 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1509 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1510 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1512 if (cmd->error != SILC_STATUS_OK) {
1513 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1514 "%s", silc_get_status_message(cmd->error));
1515 COMMAND_REPLY_ERROR(cmd->error);
1519 /* Notify application */
1520 COMMAND_REPLY((SILC_ARGS));
1523 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1524 silc_client_command_reply_free(cmd);
1527 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1529 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1530 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1533 if (cmd->error != SILC_STATUS_OK) {
1534 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1535 "%s", silc_get_status_message(cmd->error));
1536 COMMAND_REPLY_ERROR(cmd->error);
1540 /* Notify application */
1541 COMMAND_REPLY((SILC_ARGS));
1543 /* Generate the detachment data and deliver it to the client in the
1544 detach client operation */
1545 detach = silc_client_get_detach_data(cmd->client, conn);
1547 cmd->client->internal->ops->detach(cmd->client, conn,
1548 detach->data, detach->len);
1549 silc_buffer_free(detach);
1553 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1554 silc_client_command_reply_free(cmd);
1557 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1559 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1560 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1562 if (cmd->error != SILC_STATUS_OK) {
1563 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1564 "%s", silc_get_status_message(cmd->error));
1565 COMMAND_REPLY_ERROR(cmd->error);
1569 /* Notify application */
1570 COMMAND_REPLY((SILC_ARGS));
1573 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1574 silc_client_command_reply_free(cmd);
1577 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1579 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1580 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1581 SilcChannelEntry channel;
1582 SilcChannelID *channel_id;
1585 SilcBufferStruct buf;
1587 if (cmd->error != SILC_STATUS_OK) {
1588 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1589 "%s", silc_get_status_message(cmd->error));
1590 COMMAND_REPLY_ERROR(cmd->error);
1594 /* Take Channel ID */
1595 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1599 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1603 /* Get the channel entry */
1604 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1606 silc_free(channel_id);
1607 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1611 /* Get the ban list */
1612 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1614 silc_buffer_set(&buf, tmp, len);
1616 /* Notify application */
1617 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
1620 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1621 silc_client_command_reply_free(cmd);
1624 /* Reply to LEAVE command. */
1626 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1628 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1629 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1630 SilcChannelID *channel_id;
1631 SilcChannelEntry channel = NULL;
1632 SilcChannelUser chu;
1636 if (cmd->error != SILC_STATUS_OK) {
1637 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1638 "%s", silc_get_status_message(cmd->error));
1639 COMMAND_REPLY_ERROR(cmd->error);
1643 /* From protocol version 1.1 we get the channel ID of the left channel */
1644 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1646 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1650 /* Get the channel entry */
1651 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1653 silc_free(channel_id);
1654 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1658 /* Remove us from this channel. */
1659 chu = silc_client_on_channel(channel, conn->local_entry);
1661 silc_hash_table_del(chu->client->channels, chu->channel);
1662 silc_hash_table_del(chu->channel->user_list, chu->client);
1666 silc_free(channel_id);
1669 /* Notify application */
1670 COMMAND_REPLY((SILC_ARGS, channel));
1672 /* Now delete the channel. */
1674 silc_client_del_channel(cmd->client, conn, channel);
1677 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1678 silc_client_command_reply_free(cmd);
1681 /* Channel resolving callback for USERS command reply. */
1683 static void silc_client_command_reply_users_cb(SilcClient client,
1684 SilcClientConnection conn,
1685 SilcChannelEntry *channels,
1686 SilcUInt32 channels_count,
1689 if (!channels_count) {
1690 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1691 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1693 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1694 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1695 "%s", silc_get_status_message(cmd->error));
1696 COMMAND_REPLY_ERROR(cmd->error);
1697 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1698 silc_client_command_reply_free(cmd);
1702 silc_client_command_reply_users(context, NULL);
1706 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1710 SilcGetChannelCallback get_channel,
1711 SilcCommandCb get_clients)
1713 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1714 SilcChannelEntry channel;
1715 SilcClientEntry client_entry;
1716 SilcChannelUser chu;
1717 SilcChannelID *channel_id = NULL;
1718 SilcBufferStruct client_id_list, client_mode_list;
1720 SilcUInt32 tmp_len, list_count;
1722 unsigned char **res_argv = NULL;
1723 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1724 bool wait_res = FALSE;
1726 SILC_LOG_DEBUG(("Start"));
1728 /* Get channel ID */
1729 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1731 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1734 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1736 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1740 /* Get the list count */
1741 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1743 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1746 SILC_GET32_MSB(list_count, tmp);
1748 /* Get Client ID list */
1749 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1751 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1754 silc_buffer_set(&client_id_list, tmp, tmp_len);
1756 /* Get client mode list */
1757 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1759 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1762 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1764 /* Get channel entry */
1765 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1767 /* Resolve the channel from server */
1768 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1770 silc_free(channel_id);
1774 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1776 /* Cache the received Client ID's and modes. */
1777 for (i = 0; i < list_count; i++) {
1780 SilcClientID *client_id;
1783 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1785 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1790 SILC_GET32_MSB(mode, client_mode_list.data);
1792 /* Check if we have this client cached already. */
1793 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1794 if (!client_entry || !client_entry->username || !client_entry->realname) {
1796 /* No we don't have it (or it is incomplete in information), query
1797 it from the server. Assemble argument table that will be sent
1798 for the WHOIS command later. */
1799 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1801 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1803 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1805 res_argv[res_argc] = client_id_list.data;
1806 res_argv_lens[res_argc] = idp_len;
1807 res_argv_types[res_argc] = res_argc + 4;
1811 if (!silc_client_on_channel(channel, client_entry)) {
1812 chu = silc_calloc(1, sizeof(*chu));
1813 chu->client = client_entry;
1815 chu->channel = channel;
1816 silc_hash_table_add(channel->user_list, client_entry, chu);
1817 silc_hash_table_add(client_entry->channels, channel, chu);
1821 silc_free(client_id);
1822 silc_buffer_pull(&client_id_list, idp_len);
1823 silc_buffer_pull(&client_mode_list, 4);
1826 /* Query the client information from server if the list included clients
1827 that we don't know about. */
1831 /* Send the WHOIS command to server */
1832 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1833 silc_client_command_reply_whois_i, 0,
1835 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1836 res_argc, res_argv, res_argv_lens,
1837 res_argv_types, conn->cmd_ident);
1838 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1839 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1842 /* Register pending command callback. After we've received the WHOIS
1843 command reply we will reprocess this command reply by re-calling this
1844 USERS command reply callback. */
1845 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1848 silc_buffer_free(res_cmd);
1849 silc_free(channel_id);
1850 silc_free(res_argv);
1851 silc_free(res_argv_lens);
1852 silc_free(res_argv_types);
1859 silc_buffer_push(&client_id_list, (client_id_list.data -
1860 client_id_list.head));
1861 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1862 client_mode_list.head));
1864 /* Notify application */
1866 COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list,
1867 &client_mode_list));
1870 silc_free(channel_id);
1874 /* Reply to USERS command. Received list of client ID's and theirs modes
1875 on the channel we requested. */
1877 SILC_CLIENT_CMD_REPLY_FUNC(users)
1879 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1880 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1881 SilcClientCommandReplyContext r = (SilcClientCommandReplyContext)context2;
1883 SILC_LOG_DEBUG(("Start"));
1885 if (cmd->error != SILC_STATUS_OK) {
1886 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1887 "Query failed: %s", silc_get_status_message(cmd->error));
1888 COMMAND_REPLY_ERROR(cmd->error);
1892 if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) {
1893 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1894 /* Do not resolve anymore. Server may be sending us some non-existent
1895 Client ID (a bug in server), and we want to show the users list
1897 silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE,
1898 silc_client_command_reply_users_cb,
1899 silc_client_command_reply_users);
1902 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1903 "Query failed: %s", silc_get_status_message(cmd->error));
1904 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1909 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE,
1910 silc_client_command_reply_users_cb,
1911 silc_client_command_reply_users))
1915 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1916 silc_client_command_reply_free(cmd);
1919 /* Received command reply to GETKEY command. WE've received the remote
1920 client's public key. */
1922 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1924 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1925 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1926 SilcIDPayload idp = NULL;
1927 SilcClientID *client_id = NULL;
1928 SilcClientEntry client_entry;
1929 SilcServerID *server_id = NULL;
1930 SilcServerEntry server_entry;
1934 SilcPublicKey public_key = NULL;
1936 SILC_LOG_DEBUG(("Start"));
1938 if (cmd->error != SILC_STATUS_OK) {
1939 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1940 "%s", silc_get_status_message(cmd->error));
1941 COMMAND_REPLY_ERROR(cmd->error);
1945 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1947 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1950 idp = silc_id_payload_parse(tmp, len);
1952 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1956 /* Get the public key payload */
1957 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1959 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1964 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1968 id_type = silc_id_payload_get_type(idp);
1969 if (id_type == SILC_ID_CLIENT) {
1970 /* Received client's public key */
1971 client_id = silc_id_payload_get_id(idp);
1972 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1973 if (!client_entry) {
1974 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1978 /* Save fingerprint */
1979 if (!client_entry->fingerprint) {
1980 client_entry->fingerprint = silc_calloc(20, sizeof(unsigned char));
1981 client_entry->fingerprint_len = 20;
1982 silc_hash_make(cmd->client->sha1hash, tmp + 4, len - 4,
1983 client_entry->fingerprint);
1985 if (!client_entry->public_key) {
1986 client_entry->public_key = public_key;
1990 /* Notify application */
1991 COMMAND_REPLY((SILC_ARGS, id_type, client_entry,
1992 client_entry->public_key));
1993 } else if (id_type == SILC_ID_SERVER) {
1994 /* Received server's public key */
1995 server_id = silc_id_payload_get_id(idp);
1996 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1997 if (!server_entry) {
1998 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2002 /* Notify application */
2003 COMMAND_REPLY((SILC_ARGS, id_type, server_entry, public_key));
2007 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
2009 silc_id_payload_free(idp);
2011 silc_pkcs_public_key_free(public_key);
2012 silc_free(client_id);
2013 silc_free(server_id);
2014 silc_client_command_reply_free(cmd);
2017 SILC_CLIENT_CMD_REPLY_FUNC(quit)
2019 silc_client_command_reply_free(context);
2023 /******************************************************************************
2025 Internal command reply functions
2027 ******************************************************************************/
2029 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
2031 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2032 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2034 COMMAND_CHECK_STATUS_I;
2036 /* Save WHOIS info */
2037 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
2039 /* Pending callbacks are not executed if this was an list entry */
2040 if (cmd->status != SILC_STATUS_OK &&
2041 cmd->status != SILC_STATUS_LIST_END) {
2042 silc_client_command_reply_free(cmd);
2047 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
2050 /* If we received notify for invalid ID we'll remove the ID if we
2052 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2053 SilcClientEntry client_entry;
2055 unsigned char *tmp =
2056 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2059 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2061 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2064 silc_client_del_client(cmd->client, conn, client_entry);
2065 silc_free(client_id);
2070 /* Unregister this command reply */
2071 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2072 NULL, silc_client_command_reply_whois_i,
2075 silc_client_command_reply_free(cmd);
2078 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2080 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2081 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2083 COMMAND_CHECK_STATUS_I;
2085 /* Save IDENTIFY info */
2086 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
2088 /* Pending callbacks are not executed if this was an list entry */
2089 if (cmd->status != SILC_STATUS_OK &&
2090 cmd->status != SILC_STATUS_LIST_END) {
2091 silc_client_command_reply_free(cmd);
2096 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2099 /* If we received notify for invalid ID we'll remove the ID if we
2101 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2102 SilcClientEntry client_entry;
2104 unsigned char *tmp =
2105 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2108 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2110 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2113 silc_client_del_client(cmd->client, conn, client_entry);
2114 silc_free(client_id);
2119 /* Unregister this command reply */
2120 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2121 NULL, silc_client_command_reply_identify_i,
2124 silc_client_command_reply_free(cmd);
2127 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2129 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2130 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2132 SilcServerEntry server;
2133 SilcServerID *server_id = NULL;
2134 char *server_name, *server_info;
2137 COMMAND_CHECK_STATUS_I;
2140 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2144 server_id = silc_id_payload_parse_id(tmp, len, NULL);
2148 /* Get server name */
2149 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2153 /* Get server info */
2154 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2158 /* See whether we have this server cached. If not create it. */
2159 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
2161 SILC_LOG_DEBUG(("New server entry"));
2162 silc_client_add_server(cmd->client, conn, server_name, server_info,
2163 silc_id_dup(server_id, SILC_ID_SERVER));
2167 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2168 silc_free(server_id);
2170 silc_client_command_reply_free(cmd);
2173 static void silc_client_command_reply_users_i_cb(SilcClient client,
2174 SilcClientConnection conn,
2175 SilcChannelEntry *channels,
2176 SilcUInt32 channels_count,
2179 if (!channels_count) {
2180 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2181 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2183 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2184 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2185 "%s", silc_get_status_message(cmd->error));
2186 COMMAND_REPLY_ERROR(cmd->error);
2187 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2188 silc_client_command_reply_free(cmd);
2192 silc_client_command_reply_users_i(context, NULL);
2195 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2197 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2199 COMMAND_CHECK_STATUS_I;
2201 /* Save USERS info */
2202 if (silc_client_command_reply_users_save(
2203 cmd, cmd->status, FALSE, TRUE,
2204 silc_client_command_reply_users_i_cb,
2205 silc_client_command_reply_users_i))
2209 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2212 /* Unregister this command reply */
2213 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2214 NULL, silc_client_command_reply_users_i,
2217 silc_client_command_reply_free(cmd);
2220 /* Private range commands, specific to this implementation (and compatible
2221 with SILC Server >= 0.9). */
2223 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2225 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2226 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2228 if (cmd->error != SILC_STATUS_OK) {
2229 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2230 "%s", silc_get_status_message(cmd->error));
2231 COMMAND_REPLY_ERROR(cmd->error);
2235 /* Notify application */
2236 COMMAND_REPLY((SILC_ARGS));
2239 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2240 silc_client_command_reply_free(cmd);
2243 SILC_CLIENT_CMD_REPLY_FUNC(close)
2245 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2246 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2248 if (cmd->error != SILC_STATUS_OK) {
2249 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2250 "%s", silc_get_status_message(cmd->error));
2251 COMMAND_REPLY_ERROR(cmd->error);
2255 /* Notify application */
2256 COMMAND_REPLY((SILC_ARGS));
2259 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2260 silc_client_command_reply_free(cmd);
2263 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2265 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2266 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2268 if (cmd->error != SILC_STATUS_OK) {
2269 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2270 "%s", silc_get_status_message(cmd->error));
2271 COMMAND_REPLY_ERROR(cmd->error);
2275 /* Notify application */
2276 COMMAND_REPLY((SILC_ARGS));
2279 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2280 silc_client_command_reply_free(cmd);