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 */
134 silc_client_command_reply_free(ctx);
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) {
159 silc_free(cmd->callbacks);
160 silc_command_payload_free(cmd->payload);
166 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
170 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
171 SilcClientID *client_id;
172 SilcClientEntry client_entry = NULL;
174 unsigned char *id_data, *tmp;
175 char *nickname = NULL, *username = NULL;
176 char *realname = NULL;
177 SilcUInt32 idle = 0, mode = 0;
178 SilcBufferStruct channels, ch_user_modes;
179 bool has_channels = FALSE, has_user_modes = FALSE;
180 unsigned char *fingerprint;
181 SilcUInt32 fingerprint_len;
183 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
186 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
190 client_id = silc_id_payload_parse_id(id_data, len, NULL);
193 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
197 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
198 username = silc_argument_get_arg_type(cmd->args, 4, &len);
199 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
200 if (!nickname || !username || !realname) {
202 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
206 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
208 silc_buffer_set(&channels, tmp, len);
212 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
214 SILC_GET32_MSB(mode, tmp);
216 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
218 SILC_GET32_MSB(idle, tmp);
220 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
222 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
224 silc_buffer_set(&ch_user_modes, tmp, len);
225 has_user_modes = TRUE;
228 /* Check if we have this client cached already. */
229 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
231 SILC_LOG_DEBUG(("Adding new client entry"));
233 silc_client_add_client(cmd->client, conn, nickname, username, realname,
237 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
241 silc_client_update_client(cmd->client, conn, client_entry,
242 nickname, username, realname, mode);
243 silc_free(client_id);
246 if (fingerprint && !client_entry->fingerprint) {
247 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
248 client_entry->fingerprint_len = fingerprint_len;
251 /* Take Requested Attributes if set. */
252 tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
254 if (client_entry->attrs)
255 silc_attribute_payload_list_free(client_entry->attrs);
256 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
259 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
261 /* Notify application */
262 if (!cmd->callbacks_count && notify)
263 COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname,
264 has_channels ? &channels : NULL, mode, idle,
265 fingerprint, has_user_modes ? &ch_user_modes : NULL,
266 client_entry->attrs));
269 /* Received reply for WHOIS command. This maybe called several times
270 for one WHOIS command as server may reply with list of results. */
272 SILC_CLIENT_CMD_REPLY_FUNC(whois)
274 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
275 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
277 COMMAND_CHECK_STATUS;
279 /* Save WHOIS info */
280 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
282 /* Pending callbacks are not executed if this was an list entry */
283 if (cmd->status != SILC_STATUS_OK &&
284 cmd->status != SILC_STATUS_LIST_END) {
285 silc_client_command_reply_free(cmd);
290 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
293 /* If we received notify for invalid ID we'll remove the ID if we
295 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
296 SilcClientEntry client_entry;
299 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
302 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
304 client_entry = silc_client_get_client_by_id(cmd->client, conn,
307 silc_client_del_client(cmd->client, conn, client_entry);
308 silc_free(client_id);
313 silc_client_command_reply_free(cmd);
316 /* Received reply for WHOWAS command. */
318 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
320 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
321 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
322 SilcClientID *client_id;
323 SilcClientEntry client_entry = NULL;
325 unsigned char *id_data;
326 char *nickname, *username;
327 char *realname = NULL;
329 COMMAND_CHECK_STATUS;
331 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
333 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
337 client_id = silc_id_payload_parse_id(id_data, len, NULL);
339 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
343 /* Get the client entry, if exists */
344 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
345 silc_free(client_id);
347 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
348 username = silc_argument_get_arg_type(cmd->args, 4, &len);
349 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
350 if (!nickname || !username) {
351 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
355 /* Notify application. We don't save any history information to any
356 cache. Just pass the data to the application for displaying on
358 COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname));
360 /* Pending callbacks are not executed if this was an list entry */
361 if (cmd->status != SILC_STATUS_OK &&
362 cmd->status != SILC_STATUS_LIST_END) {
363 silc_client_command_reply_free(cmd);
368 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
370 silc_client_command_reply_free(cmd);
374 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
378 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
379 SilcClient client = cmd->client;
380 SilcClientID *client_id = NULL;
381 SilcServerID *server_id = NULL;
382 SilcChannelID *channel_id = NULL;
383 SilcClientEntry client_entry;
384 SilcServerEntry server_entry;
385 SilcChannelEntry channel_entry;
387 unsigned char *id_data;
388 char *name = NULL, *info = NULL;
389 SilcIDPayload idp = NULL;
392 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
395 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
398 idp = silc_id_payload_parse(id_data, len);
401 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
405 name = silc_argument_get_arg_type(cmd->args, 3, &len);
406 info = silc_argument_get_arg_type(cmd->args, 4, &len);
408 id_type = silc_id_payload_get_type(idp);
412 client_id = silc_id_payload_get_id(idp);
414 SILC_LOG_DEBUG(("Received client information"));
416 /* Check if we have this client cached already. */
417 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
419 SILC_LOG_DEBUG(("Adding new client entry"));
421 silc_client_add_client(cmd->client, conn, name, info, NULL,
422 silc_id_dup(client_id, id_type), 0);
425 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
429 silc_client_update_client(cmd->client, conn, client_entry,
430 name, info, NULL, 0);
433 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
435 /* Notify application */
437 COMMAND_REPLY((SILC_ARGS, client_entry, name, info));
441 server_id = silc_id_payload_get_id(idp);
443 SILC_LOG_DEBUG(("Received server information"));
445 /* Check if we have this server cached already. */
446 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
448 SILC_LOG_DEBUG(("Adding new server entry"));
449 server_entry = silc_client_add_server(cmd->client, conn, name, info,
450 silc_id_dup(server_id, id_type));
453 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
457 silc_client_update_server(client, conn, server_entry, name, info);
460 server_entry->resolve_cmd_ident = 0;
462 /* Notify application */
464 COMMAND_REPLY((SILC_ARGS, server_entry, name, info));
467 case SILC_ID_CHANNEL:
468 channel_id = silc_id_payload_get_id(idp);
470 SILC_LOG_DEBUG(("Received channel information"));
472 /* Check if we have this channel cached already. */
473 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
474 if (!channel_entry) {
478 /* Add new channel entry */
479 channel_entry = silc_client_add_channel(client, conn, name, 0,
481 if (!channel_entry) {
483 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
489 /* Notify application */
491 COMMAND_REPLY((SILC_ARGS, channel_entry, name, info));
495 silc_id_payload_free(idp);
496 silc_free(client_id);
497 silc_free(server_id);
498 silc_free(channel_id);
501 /* Received reply for IDENTIFY command. This maybe called several times
502 for one IDENTIFY command as server may reply with list of results.
503 This is totally silent and does not print anything on screen. */
505 SILC_CLIENT_CMD_REPLY_FUNC(identify)
507 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
508 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
510 COMMAND_CHECK_STATUS;
512 /* Save IDENTIFY info */
513 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
515 /* Pending callbacks are not executed if this was an list entry */
516 if (cmd->status != SILC_STATUS_OK &&
517 cmd->status != SILC_STATUS_LIST_END) {
518 silc_client_command_reply_free(cmd);
523 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
526 /* If we received notify for invalid ID we'll remove the ID if we
528 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
529 SilcClientEntry client_entry;
532 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
535 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
537 client_entry = silc_client_get_client_by_id(cmd->client, conn,
540 silc_client_del_client(cmd->client, conn, client_entry);
541 silc_free(client_id);
546 silc_client_command_reply_free(cmd);
549 /* Received reply for command NICK. If everything went without errors
550 we just received our new Client ID. */
552 SILC_CLIENT_CMD_REPLY_FUNC(nick)
554 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
555 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
558 SilcUInt32 argc, len;
559 SilcClientID old_client_id;
561 SILC_LOG_DEBUG(("Start"));
563 if (cmd->error != SILC_STATUS_OK) {
564 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
565 "Cannot set nickname: %s",
566 silc_get_status_message(cmd->error));
567 COMMAND_REPLY_ERROR(cmd->error);
571 argc = silc_argument_get_arg_num(cmd->args);
572 if (argc < 2 || argc > 3) {
573 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
574 "Cannot set nickname: bad reply to command");
575 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
579 /* Save old Client ID */
580 old_client_id = *conn->local_id;
582 /* Take received Client ID */
583 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
584 idp = silc_id_payload_parse(tmp, len);
586 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
589 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
591 /* Take the new nickname too */
592 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
594 silc_idcache_del_by_context(conn->internal->client_cache,
597 silc_free(conn->nickname);
598 conn->nickname = strdup(tmp);
599 conn->local_entry->nickname = conn->nickname;
601 /* Normalize nickname */
602 tmp = silc_identifier_check(conn->nickname, strlen(conn->nickname),
603 SILC_STRING_UTF8, 128, NULL);
605 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_NICKNAME);
609 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
611 silc_idcache_add(conn->internal->client_cache, tmp,
612 conn->local_entry->id, conn->local_entry, 0, NULL);
615 /* Notify application */
616 COMMAND_REPLY((SILC_ARGS, conn->local_entry, conn->local_entry->nickname,
617 (const SilcClientID *)&old_client_id));
620 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
621 silc_client_command_reply_free(cmd);
624 /* Received reply to the LIST command. */
626 SILC_CLIENT_CMD_REPLY_FUNC(list)
628 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
629 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
630 unsigned char *tmp, *name, *topic;
631 SilcUInt32 usercount = 0, len;
632 SilcChannelID *channel_id = NULL;
633 SilcChannelEntry channel_entry;
635 COMMAND_CHECK_STATUS;
637 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
639 /* There were no channels in the network. */
640 COMMAND_REPLY((SILC_ARGS, NULL, NULL, 0));
644 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
646 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
650 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
652 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
656 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
657 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
659 SILC_GET32_MSB(usercount, tmp);
661 /* Check whether the channel exists, and add it to cache if it doesn't. */
662 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
664 if (!channel_entry) {
665 /* Add new channel entry */
666 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
668 if (!channel_entry) {
669 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
675 /* Notify application */
676 COMMAND_REPLY((SILC_ARGS, channel_entry, name, topic, usercount));
678 /* Pending callbacks are not executed if this was an list entry */
679 if (cmd->status != SILC_STATUS_OK &&
680 cmd->status != SILC_STATUS_LIST_END) {
681 silc_client_command_reply_free(cmd);
686 silc_free(channel_id);
687 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
689 silc_client_command_reply_free(cmd);
692 /* Received reply to topic command. */
694 SILC_CLIENT_CMD_REPLY_FUNC(topic)
696 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
697 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
698 SilcChannelEntry channel;
699 SilcChannelID *channel_id = NULL;
702 SilcUInt32 argc, len;
704 if (cmd->error != SILC_STATUS_OK) {
705 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
706 "Cannot set topic: %s", silc_get_status_message(cmd->error));
707 COMMAND_REPLY_ERROR(cmd->error);
711 argc = silc_argument_get_arg_num(cmd->args);
712 if (argc < 1 || argc > 3) {
713 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
717 /* Take Channel ID */
718 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
723 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
727 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
731 /* Get the channel entry */
732 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
734 silc_free(channel_id);
735 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
740 silc_free(channel->topic);
741 channel->topic = silc_memdup(topic, strlen(topic));
744 /* Notify application */
745 COMMAND_REPLY((SILC_ARGS, channel, topic));
748 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
749 silc_client_command_reply_free(cmd);
752 /* Received reply to invite command. */
754 SILC_CLIENT_CMD_REPLY_FUNC(invite)
756 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
757 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
758 SilcChannelEntry channel;
759 SilcChannelID *channel_id;
762 SilcBufferStruct buf;
764 if (cmd->error != SILC_STATUS_OK) {
765 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
766 "Cannot invite: %s", silc_get_status_message(cmd->error));
767 COMMAND_REPLY_ERROR(cmd->error);
771 /* Take Channel ID */
772 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
776 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
780 /* Get the channel entry */
781 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
783 silc_free(channel_id);
784 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
788 /* Get the invite list */
789 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
791 silc_buffer_set(&buf, tmp, len);
793 /* Notify application */
794 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
797 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
798 silc_client_command_reply_free(cmd);
801 /* Received reply to the KILL command. */
803 SILC_CLIENT_CMD_REPLY_FUNC(kill)
805 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
806 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
807 SilcClientID *client_id;
808 SilcClientEntry client_entry = NULL;
810 unsigned char *id_data;
812 if (cmd->error != SILC_STATUS_OK) {
813 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
814 "Cannot kill: %s", silc_get_status_message(cmd->error));
815 COMMAND_REPLY_ERROR(cmd->error);
819 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
821 client_id = silc_id_payload_parse_id(id_data, len, NULL);
823 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
827 /* Get the client entry, if exists */
828 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
829 silc_free(client_id);
832 /* Notify application */
833 COMMAND_REPLY((SILC_ARGS, client_entry));
836 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
837 silc_client_command_reply_free(cmd);
840 /* Received reply to INFO command. We receive the server ID and some
841 information about the server user requested. */
843 SILC_CLIENT_CMD_REPLY_FUNC(info)
845 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
846 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
848 SilcServerEntry server;
849 SilcServerID *server_id = NULL;
850 char *server_name, *server_info;
853 SILC_LOG_DEBUG(("Start"));
855 if (cmd->error != SILC_STATUS_OK) {
856 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
857 silc_get_status_message(cmd->error));
858 COMMAND_REPLY_ERROR(cmd->error);
863 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
867 server_id = silc_id_payload_parse_id(tmp, len, NULL);
871 /* Get server name */
872 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
876 /* Get server info */
877 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
881 /* See whether we have this server cached. If not create it. */
882 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
884 SILC_LOG_DEBUG(("New server entry"));
885 server = silc_client_add_server(cmd->client, conn, server_name,
887 silc_id_dup(server_id, SILC_ID_SERVER));
892 /* Notify application */
893 COMMAND_REPLY((SILC_ARGS, server, server->server_name, server->server_info));
896 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
897 silc_free(server_id);
898 silc_client_command_reply_free(cmd);
901 /* Received reply to STATS command. */
903 SILC_CLIENT_CMD_REPLY_FUNC(stats)
905 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
906 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
907 unsigned char *tmp, *buf = NULL;
908 SilcUInt32 len, buf_len = 0;
910 if (cmd->error != SILC_STATUS_OK) {
911 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
912 "%s", silc_get_status_message(cmd->error));
913 COMMAND_REPLY_ERROR(cmd->error);
918 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
922 /* Get statistics structure */
923 buf = silc_argument_get_arg_type(cmd->args, 3, &buf_len);
925 /* Notify application */
926 COMMAND_REPLY((SILC_ARGS, buf, buf_len));
929 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
930 silc_client_command_reply_free(cmd);
933 /* Received reply to PING command. The reply time is shown to user. */
935 SILC_CLIENT_CMD_REPLY_FUNC(ping)
937 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
938 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
941 time_t diff, curtime;
943 if (cmd->error != SILC_STATUS_OK) {
944 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
945 "%s", silc_get_status_message(cmd->error));
946 COMMAND_REPLY_ERROR(cmd->error);
950 curtime = time(NULL);
951 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
952 cmd->packet->src_id_type);
953 if (!id || !conn->internal->ping) {
954 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
958 for (i = 0; i < conn->internal->ping_count; i++) {
959 if (!conn->internal->ping[i].dest_id)
961 if (SILC_ID_SERVER_COMPARE(conn->internal->ping[i].dest_id, id)) {
962 diff = curtime - conn->internal->ping[i].start_time;
963 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
964 "Ping reply from %s: %d second%s",
965 conn->internal->ping[i].dest_name, diff,
966 diff == 1 ? "" : "s");
968 conn->internal->ping[i].start_time = 0;
969 silc_free(conn->internal->ping[i].dest_id);
970 conn->internal->ping[i].dest_id = NULL;
971 silc_free(conn->internal->ping[i].dest_name);
972 conn->internal->ping[i].dest_name = NULL;
977 /* Notify application */
978 COMMAND_REPLY((SILC_ARGS));
983 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
984 silc_client_command_reply_free(cmd);
987 /* Received reply for JOIN command. */
989 SILC_CLIENT_CMD_REPLY_FUNC(join)
991 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
992 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
993 SilcChannelEntry channel;
995 SilcChannelID *channel_id;
996 SilcUInt32 argc, mode = 0, len, list_count;
997 char *topic, *tmp, *channel_name = NULL, *hmac;
998 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
999 SilcBufferStruct chpklist;
1002 SILC_LOG_DEBUG(("Start"));
1004 if (cmd->error != SILC_STATUS_OK) {
1005 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
1006 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1007 "Cannot join channel: %s", silc_get_status_message(cmd->error));
1008 COMMAND_REPLY_ERROR(cmd->error);
1012 argc = silc_argument_get_arg_num(cmd->args);
1014 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1015 "Cannot join channel: Bad reply packet");
1016 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1020 /* Get channel name */
1021 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1023 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1024 "Cannot join channel: Bad reply packet");
1025 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1030 /* Get Channel ID */
1031 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1033 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1034 "Cannot join channel: Bad reply packet");
1035 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1038 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1040 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1044 /* Get channel mode */
1045 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1047 SILC_GET32_MSB(mode, tmp);
1049 /* Get channel key */
1050 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1052 keyp = silc_buffer_alloc(len);
1053 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1054 silc_buffer_put(keyp, tmp, len);
1058 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1060 /* Check whether we have this channel entry already. */
1061 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1063 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
1064 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
1066 /* Create new channel entry */
1067 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1071 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_CHANNEL);
1075 conn->current_channel = channel;
1076 channel->mode = mode;
1079 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1081 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1082 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1083 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1084 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1089 /* Get the list count */
1090 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1093 SILC_GET32_MSB(list_count, tmp);
1095 /* Get Client ID list */
1096 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1100 client_id_list = silc_buffer_alloc(len);
1101 silc_buffer_pull_tail(client_id_list, len);
1102 silc_buffer_put(client_id_list, tmp, len);
1104 /* Get client mode list */
1105 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1109 client_mode_list = silc_buffer_alloc(len);
1110 silc_buffer_pull_tail(client_mode_list, len);
1111 silc_buffer_put(client_mode_list, tmp, len);
1113 /* Add clients we received in the reply to the channel */
1114 for (i = 0; i < list_count; i++) {
1117 SilcClientID *client_id;
1118 SilcClientEntry client_entry;
1121 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1123 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1128 SILC_GET32_MSB(mode, client_mode_list->data);
1130 /* Check if we have this client cached already. */
1131 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1132 if (!client_entry) {
1133 /* No, we don't have it, add entry for it. */
1135 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1136 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1141 /* Join client to the channel */
1142 if (!silc_client_on_channel(channel, client_entry)) {
1143 chu = silc_calloc(1, sizeof(*chu));
1144 chu->client = client_entry;
1145 chu->channel = channel;
1147 silc_hash_table_add(channel->user_list, client_entry, chu);
1148 silc_hash_table_add(client_entry->channels, channel, chu);
1151 silc_free(client_id);
1152 silc_buffer_pull(client_id_list, idp_len);
1153 silc_buffer_pull(client_mode_list, 4);
1155 silc_buffer_push(client_id_list, client_id_list->data -
1156 client_id_list->head);
1157 silc_buffer_push(client_mode_list, client_mode_list->data -
1158 client_mode_list->head);
1160 /* Save channel key */
1162 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1164 /* Get founder key */
1165 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
1167 if (channel->founder_key)
1168 silc_pkcs_public_key_free(channel->founder_key);
1169 channel->founder_key = NULL;
1170 silc_pkcs_public_key_payload_decode(tmp, len, &channel->founder_key);
1173 /* Get user limit */
1174 tmp = silc_argument_get_arg_type(cmd->args, 17, &len);
1175 if (tmp && len == 4)
1176 SILC_GET32_MSB(channel->user_limit, tmp);
1177 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1178 channel->user_limit = 0;
1180 /* Get channel public key list */
1181 tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
1183 silc_buffer_set(&chpklist, tmp, len);
1186 silc_free(channel->topic);
1187 channel->topic = silc_memdup(topic, strlen(topic));
1190 /* Notify application */
1191 COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0,
1192 keyp ? keyp->head : NULL, NULL,
1193 NULL, topic, hmac, list_count, client_id_list,
1194 client_mode_list, channel->founder_key,
1195 tmp ? &chpklist : NULL, channel->user_limit));
1198 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1199 silc_client_command_reply_free(cmd);
1200 silc_buffer_free(keyp);
1201 silc_buffer_free(client_id_list);
1202 silc_buffer_free(client_mode_list);
1205 /* Received reply for MOTD command */
1207 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1209 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1210 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1212 char *motd = NULL, *cp, line[256];
1214 if (cmd->error != SILC_STATUS_OK) {
1215 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1216 "%s", silc_get_status_message(cmd->error));
1217 COMMAND_REPLY_ERROR(cmd->error);
1221 argc = silc_argument_get_arg_num(cmd->args);
1223 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1228 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1230 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1237 if (cp[i++] == '\n') {
1238 memset(line, 0, sizeof(line));
1239 silc_strncat(line, sizeof(line), cp, i - 1);
1245 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1254 /* Notify application */
1255 COMMAND_REPLY((SILC_ARGS, motd));
1258 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1259 silc_client_command_reply_free(cmd);
1262 /* Received reply tot he UMODE command. Save the current user mode */
1264 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1266 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1267 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1271 if (cmd->error != SILC_STATUS_OK) {
1272 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1273 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1274 COMMAND_REPLY_ERROR(cmd->error);
1278 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1280 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1284 SILC_GET32_MSB(mode, tmp);
1285 conn->local_entry->mode = mode;
1287 /* Notify application */
1288 COMMAND_REPLY((SILC_ARGS, mode));
1291 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1292 silc_client_command_reply_free(cmd);
1295 /* Received reply for CMODE command. */
1297 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1299 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1300 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1303 SilcChannelID *channel_id;
1304 SilcChannelEntry channel;
1306 SilcPublicKey public_key = NULL;
1307 SilcBufferStruct channel_pubkeys;
1309 if (cmd->error != SILC_STATUS_OK) {
1310 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1311 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1312 COMMAND_REPLY_ERROR(cmd->error);
1316 /* Take Channel ID */
1317 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1320 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1324 /* Get the channel entry */
1325 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1327 silc_free(channel_id);
1328 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1332 /* Get channel mode */
1333 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1335 silc_free(channel_id);
1336 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1341 SILC_GET32_MSB(mode, tmp);
1342 channel->mode = mode;
1344 /* Get founder public key */
1345 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
1347 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1351 /* Get user limit */
1352 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
1353 if (tmp && len == 4)
1354 SILC_GET32_MSB(channel->user_limit, tmp);
1355 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1356 channel->user_limit = 0;
1358 /* Get channel public key(s) */
1359 tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
1361 silc_buffer_set(&channel_pubkeys, tmp, len);
1363 /* Notify application */
1364 COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
1365 tmp ? &channel_pubkeys : NULL, channel->user_limit));
1367 silc_free(channel_id);
1371 silc_pkcs_public_key_free(public_key);
1372 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1373 silc_client_command_reply_free(cmd);
1376 /* Received reply for CUMODE command */
1378 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1380 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1381 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1382 SilcClientID *client_id;
1383 SilcChannelID *channel_id;
1384 SilcClientEntry client_entry;
1385 SilcChannelEntry channel;
1386 SilcChannelUser chu;
1387 unsigned char *modev, *tmp, *id;
1388 SilcUInt32 len, mode;
1390 if (cmd->error != SILC_STATUS_OK) {
1391 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1392 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1393 COMMAND_REPLY_ERROR(cmd->error);
1397 /* Get channel mode */
1398 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1400 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1404 /* Take Channel ID */
1405 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1408 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1412 /* Get the channel entry */
1413 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1415 silc_free(channel_id);
1416 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1421 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1423 silc_free(channel_id);
1424 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1427 client_id = silc_id_payload_parse_id(id, len, NULL);
1429 silc_free(channel_id);
1430 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1434 /* Get client entry */
1435 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1436 if (!client_entry) {
1437 silc_free(channel_id);
1438 silc_free(client_id);
1439 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1444 SILC_GET32_MSB(mode, modev);
1445 chu = silc_client_on_channel(channel, client_entry);
1449 /* Notify application */
1450 COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry));
1451 silc_free(client_id);
1452 silc_free(channel_id);
1455 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1456 silc_client_command_reply_free(cmd);
1459 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1461 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1462 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1463 SilcClientID *client_id = NULL;
1464 SilcChannelID *channel_id = NULL;
1465 SilcClientEntry client_entry = NULL;
1466 SilcChannelEntry channel = NULL;
1470 if (cmd->error != SILC_STATUS_OK) {
1471 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1472 "Cannot kick: %s", silc_get_status_message(cmd->error));
1473 COMMAND_REPLY_ERROR(cmd->error);
1477 /* Take Channel ID */
1478 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1480 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1482 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1486 /* Get the channel entry */
1487 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1489 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1495 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1497 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1499 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1503 /* Get client entry */
1504 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1505 if (!client_entry) {
1506 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1511 /* Notify application */
1512 COMMAND_REPLY((SILC_ARGS, channel, client_entry));
1515 silc_free(channel_id);
1516 silc_free(client_id);
1517 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1518 silc_client_command_reply_free(cmd);
1521 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1523 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1524 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1526 if (cmd->error != SILC_STATUS_OK) {
1527 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1528 "%s", silc_get_status_message(cmd->error));
1529 COMMAND_REPLY_ERROR(cmd->error);
1533 /* Notify application */
1534 COMMAND_REPLY((SILC_ARGS));
1537 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1538 silc_client_command_reply_free(cmd);
1541 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1543 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1544 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1546 if (cmd->error != SILC_STATUS_OK) {
1547 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1548 "%s", silc_get_status_message(cmd->error));
1549 COMMAND_REPLY_ERROR(cmd->error);
1553 /* Notify application */
1554 COMMAND_REPLY((SILC_ARGS));
1557 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1558 silc_client_command_reply_free(cmd);
1561 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1563 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1564 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1567 if (cmd->error != SILC_STATUS_OK) {
1568 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1569 "%s", silc_get_status_message(cmd->error));
1570 COMMAND_REPLY_ERROR(cmd->error);
1574 /* Notify application */
1575 COMMAND_REPLY((SILC_ARGS));
1577 /* Generate the detachment data and deliver it to the client in the
1578 detach client operation */
1579 detach = silc_client_get_detach_data(cmd->client, conn);
1581 cmd->client->internal->ops->detach(cmd->client, conn,
1582 detach->data, detach->len);
1583 silc_buffer_free(detach);
1587 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1588 silc_client_command_reply_free(cmd);
1591 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1593 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1594 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1596 if (cmd->error != SILC_STATUS_OK) {
1597 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1598 "%s", silc_get_status_message(cmd->error));
1599 COMMAND_REPLY_ERROR(cmd->error);
1603 /* Notify application */
1604 COMMAND_REPLY((SILC_ARGS));
1607 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1608 silc_client_command_reply_free(cmd);
1611 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1613 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1614 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1615 SilcChannelEntry channel;
1616 SilcChannelID *channel_id;
1619 SilcBufferStruct buf;
1621 if (cmd->error != SILC_STATUS_OK) {
1622 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1623 "%s", silc_get_status_message(cmd->error));
1624 COMMAND_REPLY_ERROR(cmd->error);
1628 /* Take Channel ID */
1629 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1633 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1637 /* Get the channel entry */
1638 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1640 silc_free(channel_id);
1641 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1645 /* Get the ban list */
1646 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1648 silc_buffer_set(&buf, tmp, len);
1650 /* Notify application */
1651 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
1654 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1655 silc_client_command_reply_free(cmd);
1658 /* Reply to LEAVE command. */
1660 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1662 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1663 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1664 SilcChannelID *channel_id;
1665 SilcChannelEntry channel = NULL;
1666 SilcChannelUser chu;
1670 if (cmd->error != SILC_STATUS_OK) {
1671 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1672 "%s", silc_get_status_message(cmd->error));
1673 COMMAND_REPLY_ERROR(cmd->error);
1677 /* From protocol version 1.1 we get the channel ID of the left channel */
1678 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1680 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1684 /* Get the channel entry */
1685 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1687 silc_free(channel_id);
1688 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1692 /* Remove us from this channel. */
1693 chu = silc_client_on_channel(channel, conn->local_entry);
1695 silc_hash_table_del(chu->client->channels, chu->channel);
1696 silc_hash_table_del(chu->channel->user_list, chu->client);
1700 silc_free(channel_id);
1703 /* Notify application */
1704 COMMAND_REPLY((SILC_ARGS, channel));
1706 /* Now delete the channel. */
1708 silc_client_del_channel(cmd->client, conn, channel);
1711 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1712 silc_client_command_reply_free(cmd);
1715 /* Channel resolving callback for USERS command reply. */
1717 static void silc_client_command_reply_users_cb(SilcClient client,
1718 SilcClientConnection conn,
1719 SilcChannelEntry *channels,
1720 SilcUInt32 channels_count,
1723 if (!channels_count) {
1724 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1725 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1727 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1728 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1729 "%s", silc_get_status_message(cmd->error));
1730 COMMAND_REPLY_ERROR(cmd->error);
1731 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1732 silc_client_command_reply_free(cmd);
1736 silc_client_command_reply_users(context, NULL);
1740 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1744 SilcGetChannelCallback get_channel,
1745 SilcCommandCb get_clients)
1747 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1748 SilcChannelEntry channel;
1749 SilcClientEntry client_entry;
1750 SilcChannelUser chu;
1751 SilcChannelID *channel_id = NULL;
1752 SilcBufferStruct client_id_list, client_mode_list;
1754 SilcUInt32 tmp_len, list_count;
1756 unsigned char **res_argv = NULL;
1757 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1758 bool wait_res = FALSE;
1760 SILC_LOG_DEBUG(("Start"));
1762 /* Get channel ID */
1763 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1765 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1768 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1770 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1774 /* Get the list count */
1775 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1777 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1780 SILC_GET32_MSB(list_count, tmp);
1782 /* Get Client ID list */
1783 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1785 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1788 silc_buffer_set(&client_id_list, tmp, tmp_len);
1790 /* Get client mode list */
1791 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1793 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1796 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1798 /* Get channel entry */
1799 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1801 /* Resolve the channel from server */
1802 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1804 silc_free(channel_id);
1808 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1810 /* Cache the received Client ID's and modes. */
1811 for (i = 0; i < list_count; i++) {
1814 SilcClientID *client_id;
1817 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1819 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1824 SILC_GET32_MSB(mode, client_mode_list.data);
1826 /* Check if we have this client cached already. */
1827 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1828 if (!client_entry || !client_entry->username || !client_entry->realname) {
1830 /* No we don't have it (or it is incomplete in information), query
1831 it from the server. Assemble argument table that will be sent
1832 for the WHOIS command later. */
1833 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1835 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1837 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1839 res_argv[res_argc] = client_id_list.data;
1840 res_argv_lens[res_argc] = idp_len;
1841 res_argv_types[res_argc] = res_argc + 4;
1845 if (!silc_client_on_channel(channel, client_entry)) {
1846 chu = silc_calloc(1, sizeof(*chu));
1847 chu->client = client_entry;
1849 chu->channel = channel;
1850 silc_hash_table_add(channel->user_list, client_entry, chu);
1851 silc_hash_table_add(client_entry->channels, channel, chu);
1855 silc_free(client_id);
1856 silc_buffer_pull(&client_id_list, idp_len);
1857 silc_buffer_pull(&client_mode_list, 4);
1860 /* Query the client information from server if the list included clients
1861 that we don't know about. */
1865 /* Send the WHOIS command to server */
1866 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1867 silc_client_command_reply_whois_i, 0,
1869 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1870 res_argc, res_argv, res_argv_lens,
1871 res_argv_types, conn->cmd_ident);
1872 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1873 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1876 /* Register pending command callback. After we've received the WHOIS
1877 command reply we will reprocess this command reply by re-calling this
1878 USERS command reply callback. */
1879 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1882 silc_buffer_free(res_cmd);
1883 silc_free(channel_id);
1884 silc_free(res_argv);
1885 silc_free(res_argv_lens);
1886 silc_free(res_argv_types);
1893 silc_buffer_push(&client_id_list, (client_id_list.data -
1894 client_id_list.head));
1895 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1896 client_mode_list.head));
1898 /* Notify application */
1900 COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list,
1901 &client_mode_list));
1904 silc_free(channel_id);
1908 /* Reply to USERS command. Received list of client ID's and theirs modes
1909 on the channel we requested. */
1911 SILC_CLIENT_CMD_REPLY_FUNC(users)
1913 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1914 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1915 SilcClientCommandReplyContext r = (SilcClientCommandReplyContext)context2;
1917 SILC_LOG_DEBUG(("Start"));
1919 if (cmd->error != SILC_STATUS_OK) {
1920 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1921 "Query failed: %s", silc_get_status_message(cmd->error));
1922 COMMAND_REPLY_ERROR(cmd->error);
1926 if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) {
1927 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1928 /* Do not resolve anymore. Server may be sending us some non-existent
1929 Client ID (a bug in server), and we want to show the users list
1931 silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE,
1932 silc_client_command_reply_users_cb,
1933 silc_client_command_reply_users);
1936 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1937 "Query failed: %s", silc_get_status_message(cmd->error));
1938 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1943 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE,
1944 silc_client_command_reply_users_cb,
1945 silc_client_command_reply_users))
1949 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1950 silc_client_command_reply_free(cmd);
1953 /* Received command reply to GETKEY command. WE've received the remote
1954 client's public key. */
1956 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1958 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1959 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1960 SilcIDPayload idp = NULL;
1961 SilcClientID *client_id = NULL;
1962 SilcClientEntry client_entry;
1963 SilcServerID *server_id = NULL;
1964 SilcServerEntry server_entry;
1968 SilcPublicKey public_key = NULL;
1970 SILC_LOG_DEBUG(("Start"));
1972 if (cmd->error != SILC_STATUS_OK) {
1973 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1974 "%s", silc_get_status_message(cmd->error));
1975 COMMAND_REPLY_ERROR(cmd->error);
1979 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1981 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1984 idp = silc_id_payload_parse(tmp, len);
1986 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1990 /* Get the public key payload */
1991 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1993 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1998 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2002 id_type = silc_id_payload_get_type(idp);
2003 if (id_type == SILC_ID_CLIENT) {
2004 /* Received client's public key */
2005 client_id = silc_id_payload_get_id(idp);
2006 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
2007 if (!client_entry) {
2008 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2012 /* Save fingerprint */
2013 if (!client_entry->fingerprint) {
2014 client_entry->fingerprint = silc_calloc(20, sizeof(unsigned char));
2015 client_entry->fingerprint_len = 20;
2016 silc_hash_make(cmd->client->sha1hash, tmp + 4, len - 4,
2017 client_entry->fingerprint);
2019 if (!client_entry->public_key) {
2020 client_entry->public_key = public_key;
2024 /* Notify application */
2025 COMMAND_REPLY((SILC_ARGS, id_type, client_entry,
2026 client_entry->public_key));
2027 } else if (id_type == SILC_ID_SERVER) {
2028 /* Received server's public key */
2029 server_id = silc_id_payload_get_id(idp);
2030 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
2031 if (!server_entry) {
2032 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2036 /* Notify application */
2037 COMMAND_REPLY((SILC_ARGS, id_type, server_entry, public_key));
2041 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
2043 silc_id_payload_free(idp);
2045 silc_pkcs_public_key_free(public_key);
2046 silc_free(client_id);
2047 silc_free(server_id);
2048 silc_client_command_reply_free(cmd);
2051 /* Reply to SERVICE command. */
2052 /* XXX incomplete */
2054 SILC_CLIENT_CMD_REPLY_FUNC(service)
2056 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2058 unsigned char *service_list, *name;
2060 COMMAND_CHECK_STATUS;
2062 /* Get service list */
2063 service_list = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
2065 /* Get requested service name */
2066 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
2068 /* Notify application */
2069 COMMAND_REPLY((SILC_ARGS, service_list, name));
2072 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SERVICE);
2074 silc_client_command_reply_free(cmd);
2077 SILC_CLIENT_CMD_REPLY_FUNC(quit)
2079 silc_client_command_reply_free(context);
2083 /******************************************************************************
2085 Internal command reply functions
2087 ******************************************************************************/
2089 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
2091 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2092 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2094 COMMAND_CHECK_STATUS_I;
2096 /* Save WHOIS info */
2097 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
2099 /* Pending callbacks are not executed if this was an list entry */
2100 if (cmd->status != SILC_STATUS_OK &&
2101 cmd->status != SILC_STATUS_LIST_END) {
2102 silc_client_command_reply_free(cmd);
2107 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
2110 /* If we received notify for invalid ID we'll remove the ID if we
2112 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2113 SilcClientEntry client_entry;
2115 unsigned char *tmp =
2116 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2119 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2121 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2124 silc_client_del_client(cmd->client, conn, client_entry);
2125 silc_free(client_id);
2130 /* Unregister this command reply */
2131 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2132 NULL, silc_client_command_reply_whois_i,
2135 silc_client_command_reply_free(cmd);
2138 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2140 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2141 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2143 COMMAND_CHECK_STATUS_I;
2145 /* Save IDENTIFY info */
2146 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
2148 /* Pending callbacks are not executed if this was an list entry */
2149 if (cmd->status != SILC_STATUS_OK &&
2150 cmd->status != SILC_STATUS_LIST_END) {
2151 silc_client_command_reply_free(cmd);
2156 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2159 /* If we received notify for invalid ID we'll remove the ID if we
2161 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2162 SilcClientEntry client_entry;
2164 unsigned char *tmp =
2165 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2168 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2170 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2173 silc_client_del_client(cmd->client, conn, client_entry);
2174 silc_free(client_id);
2179 /* Unregister this command reply */
2180 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2181 NULL, silc_client_command_reply_identify_i,
2184 silc_client_command_reply_free(cmd);
2187 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2189 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2190 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2192 SilcServerEntry server;
2193 SilcServerID *server_id = NULL;
2194 char *server_name, *server_info;
2197 COMMAND_CHECK_STATUS_I;
2200 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2204 server_id = silc_id_payload_parse_id(tmp, len, NULL);
2208 /* Get server name */
2209 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2213 /* Get server info */
2214 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2218 /* See whether we have this server cached. If not create it. */
2219 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
2221 SILC_LOG_DEBUG(("New server entry"));
2222 silc_client_add_server(cmd->client, conn, server_name, server_info,
2223 silc_id_dup(server_id, SILC_ID_SERVER));
2227 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2228 silc_free(server_id);
2230 silc_client_command_reply_free(cmd);
2233 static void silc_client_command_reply_users_i_cb(SilcClient client,
2234 SilcClientConnection conn,
2235 SilcChannelEntry *channels,
2236 SilcUInt32 channels_count,
2239 if (!channels_count) {
2240 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2241 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2243 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2244 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2245 "%s", silc_get_status_message(cmd->error));
2246 COMMAND_REPLY_ERROR(cmd->error);
2247 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2248 silc_client_command_reply_free(cmd);
2252 silc_client_command_reply_users_i(context, NULL);
2255 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2257 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2259 COMMAND_CHECK_STATUS_I;
2261 /* Save USERS info */
2262 if (silc_client_command_reply_users_save(
2263 cmd, cmd->status, FALSE, TRUE,
2264 silc_client_command_reply_users_i_cb,
2265 silc_client_command_reply_users_i))
2269 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2272 /* Unregister this command reply */
2273 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2274 NULL, silc_client_command_reply_users_i,
2277 silc_client_command_reply_free(cmd);
2280 /* Private range commands, specific to this implementation (and compatible
2281 with SILC Server >= 0.9). */
2283 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2285 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2286 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2288 if (cmd->error != SILC_STATUS_OK) {
2289 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2290 "%s", silc_get_status_message(cmd->error));
2291 COMMAND_REPLY_ERROR(cmd->error);
2295 /* Notify application */
2296 COMMAND_REPLY((SILC_ARGS));
2299 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2300 silc_client_command_reply_free(cmd);
2303 SILC_CLIENT_CMD_REPLY_FUNC(close)
2305 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2306 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2308 if (cmd->error != SILC_STATUS_OK) {
2309 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2310 "%s", silc_get_status_message(cmd->error));
2311 COMMAND_REPLY_ERROR(cmd->error);
2315 /* Notify application */
2316 COMMAND_REPLY((SILC_ARGS));
2319 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2320 silc_client_command_reply_free(cmd);
2323 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2325 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2326 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2328 if (cmd->error != SILC_STATUS_OK) {
2329 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2330 "%s", silc_get_status_message(cmd->error));
2331 COMMAND_REPLY_ERROR(cmd->error);
2335 /* Notify application */
2336 COMMAND_REPLY((SILC_ARGS));
2339 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2340 silc_client_command_reply_free(cmd);