5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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
44 #define COMMAND_CHECK_STATUS \
46 SILC_LOG_DEBUG(("Start")); \
47 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
48 COMMAND_REPLY_ERROR; \
53 /* Process received command reply. */
55 void silc_client_command_reply_process(SilcClient client,
56 SilcSocketConnection sock,
57 SilcPacketContext *packet)
59 SilcBuffer buffer = packet->buffer;
60 SilcClientCommand cmd;
61 SilcClientCommandReplyContext ctx;
62 SilcCommandPayload payload;
64 SilcCommandCb reply = NULL;
66 /* Get command reply payload from packet */
67 payload = silc_command_payload_parse(buffer->data, buffer->len);
69 /* Silently ignore bad reply packet */
70 SILC_LOG_DEBUG(("Bad command reply packet"));
74 /* Allocate command reply context. This must be free'd by the
75 command reply routine receiving it. */
76 ctx = silc_calloc(1, sizeof(*ctx));
79 ctx->payload = payload;
80 ctx->args = silc_command_get_args(ctx->payload);
82 ctx->ident = silc_command_get_ident(ctx->payload);
83 silc_command_get_status(ctx->payload, &ctx->status, &ctx->error);
85 /* Check for pending commands and mark to be exeucted */
87 silc_client_command_pending_check(sock->user_data, ctx,
88 silc_command_get(ctx->payload),
89 ctx->ident, &ctx->callbacks_count);
91 /* Execute command reply */
93 command = silc_command_get(ctx->payload);
95 /* Try to find matching the command identifier */
96 silc_list_start(client->internal->commands);
97 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
98 if (cmd->cmd == command && !cmd->ident)
100 if (cmd->cmd == command && cmd->ident == ctx->ident) {
101 (*cmd->reply)((void *)ctx, NULL);
106 if (cmd == SILC_LIST_END) {
108 /* No specific identifier for command reply, call first one found */
115 /* Free command reply context and its internals. */
117 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
120 silc_command_payload_free(cmd->payload);
126 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
130 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
131 SilcClientID *client_id;
132 SilcClientEntry client_entry = NULL;
134 unsigned char *id_data, *tmp;
135 char *nickname = NULL, *username = NULL;
136 char *realname = NULL;
137 SilcUInt32 idle = 0, mode = 0;
138 SilcBufferStruct channels, ch_user_modes;
139 bool has_channels = FALSE, has_user_modes = FALSE;
140 unsigned char *fingerprint;
141 SilcUInt32 fingerprint_len;
143 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
150 client_id = silc_id_payload_parse_id(id_data, len, NULL);
157 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
158 username = silc_argument_get_arg_type(cmd->args, 4, &len);
159 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
160 if (!nickname || !username || !realname) {
166 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
168 silc_buffer_set(&channels, tmp, len);
172 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
174 SILC_GET32_MSB(mode, tmp);
176 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
178 SILC_GET32_MSB(idle, tmp);
180 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
182 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
184 silc_buffer_set(&ch_user_modes, tmp, len);
185 has_user_modes = TRUE;
188 /* Check if we have this client cached already. */
189 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
191 SILC_LOG_DEBUG(("Adding new client entry"));
193 silc_client_add_client(cmd->client, conn, nickname, username, realname,
196 silc_client_update_client(cmd->client, conn, client_entry,
197 nickname, username, realname, mode);
198 silc_free(client_id);
201 if (fingerprint && !client_entry->fingerprint) {
202 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
203 client_entry->fingerprint_len = fingerprint_len;
206 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
207 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
209 /* Notify application */
210 if (!cmd->callbacks_count && notify)
211 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
212 has_channels ? &channels : NULL, mode, idle,
213 fingerprint, has_user_modes ? &ch_user_modes : NULL));
216 /* Received reply for WHOIS command. This maybe called several times
217 for one WHOIS command as server may reply with list of results. */
219 SILC_CLIENT_CMD_REPLY_FUNC(whois)
221 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
222 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
224 COMMAND_CHECK_STATUS;
226 /* Save WHOIS info */
227 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
229 /* Pending callbacks are not executed if this was an list entry */
230 if (cmd->status != SILC_STATUS_OK &&
231 cmd->status != SILC_STATUS_LIST_END) {
232 silc_client_command_reply_free(cmd);
237 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
239 /* If we received notify for invalid ID we'll remove the ID if we
241 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
242 SilcClientEntry client_entry;
245 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
248 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
250 client_entry = silc_client_get_client_by_id(cmd->client, conn,
253 silc_client_del_client(cmd->client, conn, client_entry);
254 silc_free(client_id);
259 silc_client_command_reply_free(cmd);
262 /* Received reply for WHOWAS command. */
264 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
266 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
267 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
268 SilcClientID *client_id;
269 SilcClientEntry client_entry = NULL;
271 unsigned char *id_data;
272 char *nickname, *username;
273 char *realname = NULL;
275 COMMAND_CHECK_STATUS;
277 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
283 client_id = silc_id_payload_parse_id(id_data, len, NULL);
289 /* Get the client entry, if exists */
290 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
291 silc_free(client_id);
293 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
294 username = silc_argument_get_arg_type(cmd->args, 4, &len);
295 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
296 if (!nickname || !username) {
301 /* Notify application. We don't save any history information to any
302 cache. Just pass the data to the application for displaying on
304 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
306 /* Pending callbacks are not executed if this was an list entry */
307 if (cmd->status != SILC_STATUS_OK &&
308 cmd->status != SILC_STATUS_LIST_END) {
309 silc_client_command_reply_free(cmd);
314 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
315 silc_client_command_reply_free(cmd);
319 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
323 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
324 SilcClient client = cmd->client;
325 SilcClientID *client_id = NULL;
326 SilcServerID *server_id = NULL;
327 SilcChannelID *channel_id = NULL;
328 SilcClientEntry client_entry;
329 SilcServerEntry server_entry;
330 SilcChannelEntry channel_entry;
332 unsigned char *id_data;
333 char *name = NULL, *info = NULL;
334 SilcIDPayload idp = NULL;
337 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
343 idp = silc_id_payload_parse(id_data, len);
350 name = silc_argument_get_arg_type(cmd->args, 3, &len);
351 info = silc_argument_get_arg_type(cmd->args, 4, &len);
353 id_type = silc_id_payload_get_type(idp);
357 client_id = silc_id_payload_get_id(idp);
359 SILC_LOG_DEBUG(("Received client information"));
361 /* Check if we have this client cached already. */
362 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
364 SILC_LOG_DEBUG(("Adding new client entry"));
366 silc_client_add_client(cmd->client, conn, name, info, NULL,
367 silc_id_dup(client_id, id_type), 0);
369 silc_client_update_client(cmd->client, conn, client_entry,
370 name, info, NULL, 0);
373 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
374 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
376 /* Notify application */
378 COMMAND_REPLY((ARGS, client_entry, name, info));
382 server_id = silc_id_payload_get_id(idp);
384 SILC_LOG_DEBUG(("Received server information"));
386 /* Check if we have this server cached already. */
387 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
389 SILC_LOG_DEBUG(("Adding new server entry"));
390 server_entry = silc_client_add_server(cmd->client, conn, name, info,
391 silc_id_dup(server_id, id_type));
399 /* Notify application */
401 COMMAND_REPLY((ARGS, server_entry, name, info));
404 case SILC_ID_CHANNEL:
405 channel_id = silc_id_payload_get_id(idp);
407 SILC_LOG_DEBUG(("Received channel information"));
409 /* Check if we have this channel cached already. */
410 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
411 if (!channel_entry) {
415 /* Add new channel entry */
416 channel_entry = silc_client_add_channel(client, conn, name, 0,
421 /* Notify application */
423 COMMAND_REPLY((ARGS, channel_entry, name, info));
427 silc_id_payload_free(idp);
428 silc_free(client_id);
429 silc_free(server_id);
430 silc_free(channel_id);
433 /* Received reply for IDENTIFY command. This maybe called several times
434 for one IDENTIFY command as server may reply with list of results.
435 This is totally silent and does not print anything on screen. */
437 SILC_CLIENT_CMD_REPLY_FUNC(identify)
439 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
440 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
442 COMMAND_CHECK_STATUS;
444 /* Save IDENTIFY info */
445 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
447 /* Pending callbacks are not executed if this was an list entry */
448 if (cmd->status != SILC_STATUS_OK &&
449 cmd->status != SILC_STATUS_LIST_END) {
450 silc_client_command_reply_free(cmd);
455 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
457 /* If we received notify for invalid ID we'll remove the ID if we
459 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
460 SilcClientEntry client_entry;
463 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
466 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
468 client_entry = silc_client_get_client_by_id(cmd->client, conn,
471 silc_client_del_client(cmd->client, conn, client_entry);
472 silc_free(client_id);
477 silc_client_command_reply_free(cmd);
480 /* Received reply for command NICK. If everything went without errors
481 we just received our new Client ID. */
483 SILC_CLIENT_CMD_REPLY_FUNC(nick)
485 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
486 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
489 SilcUInt32 argc, len;
491 SILC_LOG_DEBUG(("Start"));
493 if (cmd->error != SILC_STATUS_OK) {
494 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
495 "Cannot set nickname: %s",
496 silc_get_status_message(cmd->error));
501 argc = silc_argument_get_arg_num(cmd->args);
502 if (argc < 2 || argc > 3) {
503 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
504 "Cannot set nickname: bad reply to command");
509 /* Take received Client ID */
510 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
511 idp = silc_id_payload_parse(tmp, len);
516 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
518 /* Take the new nickname too */
519 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
521 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
523 silc_free(conn->nickname);
524 conn->nickname = strdup(tmp);
525 conn->local_entry->nickname = conn->nickname;
526 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
527 silc_idcache_add(conn->client_cache, strdup(tmp),
528 conn->local_entry->id, conn->local_entry, 0, NULL);
531 /* Notify application */
532 COMMAND_REPLY((ARGS, conn->local_entry, conn->local_entry->nickname));
535 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
536 silc_client_command_reply_free(cmd);
539 /* Received reply to the LIST command. */
541 SILC_CLIENT_CMD_REPLY_FUNC(list)
543 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
544 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
545 unsigned char *tmp, *name, *topic;
546 SilcUInt32 usercount = 0, len;
547 SilcChannelID *channel_id = NULL;
548 SilcChannelEntry channel_entry;
550 COMMAND_CHECK_STATUS;
552 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
558 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
564 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
570 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
571 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
573 SILC_GET32_MSB(usercount, tmp);
575 /* Check whether the channel exists, and add it to cache if it doesn't. */
576 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
578 if (!channel_entry) {
579 /* Add new channel entry */
580 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
582 if (!channel_entry) {
589 /* Notify application */
590 COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount));
592 /* Pending callbacks are not executed if this was an list entry */
593 if (cmd->status != SILC_STATUS_OK &&
594 cmd->status != SILC_STATUS_LIST_END) {
595 silc_client_command_reply_free(cmd);
600 silc_free(channel_id);
601 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
602 silc_client_command_reply_free(cmd);
605 /* Received reply to topic command. */
607 SILC_CLIENT_CMD_REPLY_FUNC(topic)
609 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
610 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
611 SilcChannelEntry channel;
612 SilcChannelID *channel_id = NULL;
615 SilcUInt32 argc, len;
617 if (cmd->error != SILC_STATUS_OK) {
618 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
619 "%s", silc_get_status_message(cmd->error));
624 argc = silc_argument_get_arg_num(cmd->args);
625 if (argc < 1 || argc > 3) {
630 /* Take Channel ID */
631 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
636 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
640 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
644 /* Get the channel entry */
645 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
647 silc_free(channel_id);
652 /* Notify application */
653 COMMAND_REPLY((ARGS, channel, topic));
656 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
657 silc_client_command_reply_free(cmd);
660 /* Received reply to invite command. */
662 SILC_CLIENT_CMD_REPLY_FUNC(invite)
664 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
665 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
666 SilcChannelEntry channel;
667 SilcChannelID *channel_id;
671 if (cmd->error != SILC_STATUS_OK) {
672 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
673 "%s", silc_get_status_message(cmd->error));
678 /* Take Channel ID */
679 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
683 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
687 /* Get the channel entry */
688 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
690 silc_free(channel_id);
695 /* Get the invite list */
696 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
698 /* Notify application */
699 COMMAND_REPLY((ARGS, channel, tmp));
702 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
703 silc_client_command_reply_free(cmd);
706 /* Received reply to the KILL command. */
708 SILC_CLIENT_CMD_REPLY_FUNC(kill)
710 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
711 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
713 if (cmd->error != SILC_STATUS_OK) {
714 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
715 "%s", silc_get_status_message(cmd->error));
720 /* Notify application */
721 COMMAND_REPLY((ARGS));
724 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
725 silc_client_command_reply_free(cmd);
728 /* Received reply to INFO command. We receive the server ID and some
729 information about the server user requested. */
731 SILC_CLIENT_CMD_REPLY_FUNC(info)
733 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
734 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
736 SilcServerEntry server;
737 SilcServerID *server_id = NULL;
738 char *server_name, *server_info;
741 SILC_LOG_DEBUG(("Start"));
743 if (cmd->error != SILC_STATUS_OK) {
744 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
745 silc_get_status_message(cmd->error));
751 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
755 server_id = silc_id_payload_parse_id(tmp, len, NULL);
759 /* Get server name */
760 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
764 /* Get server info */
765 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
769 /* See whether we have this server cached. If not create it. */
770 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
772 SILC_LOG_DEBUG(("New server entry"));
773 server = silc_client_add_server(cmd->client, conn, server_name,
775 silc_id_dup(server_id, SILC_ID_SERVER));
780 /* Notify application */
781 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
784 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
785 silc_free(server_id);
786 silc_client_command_reply_free(cmd);
789 /* Received reply to PING command. The reply time is shown to user. */
791 SILC_CLIENT_CMD_REPLY_FUNC(ping)
793 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
794 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
797 time_t diff, curtime;
799 if (cmd->error != SILC_STATUS_OK) {
800 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
801 "%s", silc_get_status_message(cmd->error));
806 curtime = time(NULL);
807 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
808 cmd->packet->src_id_type);
809 if (!id || !conn->ping) {
814 for (i = 0; i < conn->ping_count; i++) {
815 if (!conn->ping[i].dest_id)
817 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
818 diff = curtime - conn->ping[i].start_time;
819 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
820 "Ping reply from %s: %d second%s",
821 conn->ping[i].dest_name, diff,
822 diff == 1 ? "" : "s");
824 conn->ping[i].start_time = 0;
825 silc_free(conn->ping[i].dest_id);
826 conn->ping[i].dest_id = NULL;
827 silc_free(conn->ping[i].dest_name);
828 conn->ping[i].dest_name = NULL;
835 /* Notify application */
836 COMMAND_REPLY((ARGS));
839 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
840 silc_client_command_reply_free(cmd);
843 /* Received reply for JOIN command. */
845 SILC_CLIENT_CMD_REPLY_FUNC(join)
847 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
848 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
849 SilcChannelEntry channel;
851 SilcChannelID *channel_id;
852 SilcUInt32 argc, mode = 0, len, list_count;
853 char *topic, *tmp, *channel_name = NULL, *hmac;
854 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
857 SILC_LOG_DEBUG(("Start"));
859 if (cmd->error != SILC_STATUS_OK) {
860 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
861 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
862 "%s", silc_get_status_message(cmd->error));
867 argc = silc_argument_get_arg_num(cmd->args);
868 if (argc < 7 || argc > 14) {
869 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
870 "Cannot join channel: Bad reply packet");
875 /* Get channel name */
876 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
878 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
879 "Cannot join channel: Bad reply packet");
886 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
888 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
889 "Cannot join channel: Bad reply packet");
893 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
899 /* Get channel mode */
900 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
902 SILC_GET32_MSB(mode, tmp);
904 /* Get channel key */
905 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
907 keyp = silc_buffer_alloc(len);
908 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
909 silc_buffer_put(keyp, tmp, len);
913 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
915 /* Check whether we have this channel entry already. */
916 channel = silc_client_get_channel(cmd->client, conn, channel_name);
918 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
919 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
921 /* Create new channel entry */
922 channel = silc_client_add_channel(cmd->client, conn, channel_name,
926 conn->current_channel = channel;
929 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
931 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
932 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
933 "Cannot join channel: Unsupported HMAC `%s'", hmac);
939 /* Get the list count */
940 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
943 SILC_GET32_MSB(list_count, tmp);
945 /* Get Client ID list */
946 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
950 client_id_list = silc_buffer_alloc(len);
951 silc_buffer_pull_tail(client_id_list, len);
952 silc_buffer_put(client_id_list, tmp, len);
954 /* Get client mode list */
955 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
959 client_mode_list = silc_buffer_alloc(len);
960 silc_buffer_pull_tail(client_mode_list, len);
961 silc_buffer_put(client_mode_list, tmp, len);
963 /* Add clients we received in the reply to the channel */
964 for (i = 0; i < list_count; i++) {
967 SilcClientID *client_id;
968 SilcClientEntry client_entry;
971 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
973 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
978 SILC_GET32_MSB(mode, client_mode_list->data);
980 /* Check if we have this client cached already. */
981 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
983 /* No, we don't have it, add entry for it. */
985 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
986 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
989 /* Join client to the channel */
990 if (!silc_client_on_channel(channel, client_entry)) {
991 chu = silc_calloc(1, sizeof(*chu));
992 chu->client = client_entry;
993 chu->channel = channel;
995 silc_hash_table_add(channel->user_list, client_entry, chu);
996 silc_hash_table_add(client_entry->channels, channel, chu);
999 silc_free(client_id);
1000 silc_buffer_pull(client_id_list, idp_len);
1001 silc_buffer_pull(client_mode_list, 4);
1003 silc_buffer_push(client_id_list, client_id_list->data -
1004 client_id_list->head);
1005 silc_buffer_push(client_mode_list, client_mode_list->data -
1006 client_mode_list->head);
1008 /* Save channel key */
1009 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1010 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1012 /* Notify application */
1013 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1014 keyp ? keyp->head : NULL, NULL,
1015 NULL, topic, hmac, list_count, client_id_list,
1019 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1020 silc_client_command_reply_free(cmd);
1023 silc_buffer_free(keyp);
1025 silc_buffer_free(client_id_list);
1026 if (client_mode_list)
1027 silc_buffer_free(client_mode_list);
1030 /* Received reply for MOTD command */
1032 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1034 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1035 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1037 char *motd = NULL, *cp, line[256];
1039 if (cmd->error != SILC_STATUS_OK) {
1040 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1041 "%s", silc_get_status_message(cmd->error));
1042 COMMAND_REPLY_ERROR;
1046 argc = silc_argument_get_arg_num(cmd->args);
1048 COMMAND_REPLY_ERROR;
1053 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1055 COMMAND_REPLY_ERROR;
1062 if (cp[i++] == '\n') {
1063 memset(line, 0, sizeof(line));
1064 strncat(line, cp, i - 1);
1070 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1079 /* Notify application */
1080 COMMAND_REPLY((ARGS, motd));
1083 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1084 silc_client_command_reply_free(cmd);
1087 /* Received reply tot he UMODE command. Save the current user mode */
1089 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1091 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1092 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1096 if (cmd->error != SILC_STATUS_OK) {
1097 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1098 "%s", silc_get_status_message(cmd->error));
1099 COMMAND_REPLY_ERROR;
1103 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1105 COMMAND_REPLY_ERROR;
1109 SILC_GET32_MSB(mode, tmp);
1110 conn->local_entry->mode = mode;
1112 /* Notify application */
1113 COMMAND_REPLY((ARGS, mode));
1116 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1117 silc_client_command_reply_free(cmd);
1120 /* Received reply for CMODE command. */
1122 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1124 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1125 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1128 SilcChannelID *channel_id;
1129 SilcChannelEntry channel;
1132 if (cmd->error != SILC_STATUS_OK) {
1133 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1134 "%s", silc_get_status_message(cmd->error));
1135 COMMAND_REPLY_ERROR;
1139 /* Take Channel ID */
1140 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1143 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1147 /* Get the channel entry */
1148 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1150 silc_free(channel_id);
1151 COMMAND_REPLY_ERROR;
1155 /* Get channel mode */
1156 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1158 silc_free(channel_id);
1159 COMMAND_REPLY_ERROR;
1164 SILC_GET32_MSB(mode, tmp);
1165 channel->mode = mode;
1167 /* Notify application */
1168 COMMAND_REPLY((ARGS, channel, mode));
1170 silc_free(channel_id);
1173 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1174 silc_client_command_reply_free(cmd);
1177 /* Received reply for CUMODE command */
1179 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1181 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1182 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1183 SilcClientID *client_id;
1184 SilcChannelID *channel_id;
1185 SilcClientEntry client_entry;
1186 SilcChannelEntry channel;
1187 SilcChannelUser chu;
1188 unsigned char *modev, *tmp, *id;
1189 SilcUInt32 len, mode;
1191 if (cmd->error != SILC_STATUS_OK) {
1192 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1193 "%s", silc_get_status_message(cmd->error));
1194 COMMAND_REPLY_ERROR;
1198 /* Get channel mode */
1199 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1201 COMMAND_REPLY_ERROR;
1205 /* Take Channel ID */
1206 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1209 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1213 /* Get the channel entry */
1214 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1216 silc_free(channel_id);
1217 COMMAND_REPLY_ERROR;
1222 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1224 silc_free(channel_id);
1225 COMMAND_REPLY_ERROR;
1228 client_id = silc_id_payload_parse_id(id, len, NULL);
1230 silc_free(channel_id);
1231 COMMAND_REPLY_ERROR;
1235 /* Get client entry */
1236 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1237 if (!client_entry) {
1238 silc_free(channel_id);
1239 silc_free(client_id);
1240 COMMAND_REPLY_ERROR;
1245 SILC_GET32_MSB(mode, modev);
1246 chu = silc_client_on_channel(channel, client_entry);
1250 /* Notify application */
1251 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1252 silc_free(client_id);
1253 silc_free(channel_id);
1256 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1257 silc_client_command_reply_free(cmd);
1260 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1262 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1263 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1265 if (cmd->error != SILC_STATUS_OK) {
1266 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1267 "%s", silc_get_status_message(cmd->error));
1268 COMMAND_REPLY_ERROR;
1272 /* Notify application */
1273 COMMAND_REPLY((ARGS));
1276 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1277 silc_client_command_reply_free(cmd);
1280 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1282 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1283 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1285 if (cmd->error != SILC_STATUS_OK) {
1286 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1287 "%s", silc_get_status_message(cmd->error));
1288 COMMAND_REPLY_ERROR;
1292 /* Notify application */
1293 COMMAND_REPLY((ARGS));
1296 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1297 silc_client_command_reply_free(cmd);
1300 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1302 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1303 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1305 if (cmd->error != SILC_STATUS_OK) {
1306 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1307 "%s", silc_get_status_message(cmd->error));
1308 COMMAND_REPLY_ERROR;
1312 /* Notify application */
1313 COMMAND_REPLY((ARGS));
1316 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1317 silc_client_command_reply_free(cmd);
1320 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1322 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1323 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1326 if (cmd->error != SILC_STATUS_OK) {
1327 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1328 "%s", silc_get_status_message(cmd->error));
1329 COMMAND_REPLY_ERROR;
1333 /* Notify application */
1334 COMMAND_REPLY((ARGS));
1336 /* Generate the detachment data and deliver it to the client in the
1337 detach client operation */
1338 detach = silc_client_get_detach_data(cmd->client, conn);
1340 cmd->client->internal->ops->detach(cmd->client, conn,
1341 detach->data, detach->len);
1342 silc_buffer_free(detach);
1346 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1347 silc_client_command_reply_free(cmd);
1350 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1352 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1353 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1355 if (cmd->error != SILC_STATUS_OK) {
1356 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1357 "%s", silc_get_status_message(cmd->error));
1358 COMMAND_REPLY_ERROR;
1362 /* Notify application */
1363 COMMAND_REPLY((ARGS));
1366 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1367 silc_client_command_reply_free(cmd);
1370 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1372 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1373 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1374 SilcChannelEntry channel;
1375 SilcChannelID *channel_id;
1379 if (cmd->error != SILC_STATUS_OK) {
1380 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1381 "%s", silc_get_status_message(cmd->error));
1382 COMMAND_REPLY_ERROR;
1386 /* Take Channel ID */
1387 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1391 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1395 /* Get the channel entry */
1396 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1398 silc_free(channel_id);
1399 COMMAND_REPLY_ERROR;
1403 /* Get the ban list */
1404 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1406 /* Notify application */
1407 COMMAND_REPLY((ARGS, channel, tmp));
1410 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1411 silc_client_command_reply_free(cmd);
1414 /* Reply to LEAVE command. */
1416 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1418 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1419 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1420 SilcChannelID *channel_id;
1421 SilcChannelEntry channel = NULL;
1425 if (cmd->error != SILC_STATUS_OK) {
1426 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1427 "%s", silc_get_status_message(cmd->error));
1428 COMMAND_REPLY_ERROR;
1432 /* From protocol version 1.1 we get the channel ID of the left channel */
1433 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1435 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1439 /* Get the channel entry */
1440 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1442 silc_free(channel_id);
1443 COMMAND_REPLY_ERROR;
1447 silc_free(channel_id);
1450 /* Notify application */
1451 COMMAND_REPLY((ARGS, channel));
1454 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1455 silc_client_command_reply_free(cmd);
1458 /* Channel resolving callback for USERS command reply. */
1460 static void silc_client_command_reply_users_cb(SilcClient client,
1461 SilcClientConnection conn,
1462 SilcChannelEntry *channels,
1463 SilcUInt32 channels_count,
1466 if (!channels_count) {
1467 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1468 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1470 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1471 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1472 "%s", silc_get_status_message(cmd->error));
1473 COMMAND_REPLY_ERROR;
1474 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1475 silc_client_command_reply_free(cmd);
1479 silc_client_command_reply_users(context, NULL);
1483 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1486 SilcGetChannelCallback get_channel,
1487 SilcCommandCb get_clients)
1489 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1490 SilcChannelEntry channel;
1491 SilcClientEntry client_entry;
1492 SilcChannelUser chu;
1493 SilcChannelID *channel_id = NULL;
1494 SilcBufferStruct client_id_list, client_mode_list;
1496 SilcUInt32 tmp_len, list_count;
1498 unsigned char **res_argv = NULL;
1499 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1500 bool wait_res = FALSE;
1502 SILC_LOG_DEBUG(("Start"));
1504 /* Get channel ID */
1505 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1507 COMMAND_REPLY_ERROR;
1510 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1512 COMMAND_REPLY_ERROR;
1516 /* Get the list count */
1517 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1519 COMMAND_REPLY_ERROR;
1522 SILC_GET32_MSB(list_count, tmp);
1524 /* Get Client ID list */
1525 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1527 COMMAND_REPLY_ERROR;
1530 silc_buffer_set(&client_id_list, tmp, tmp_len);
1532 /* Get client mode list */
1533 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1535 COMMAND_REPLY_ERROR;
1538 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1540 /* Get channel entry */
1541 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1543 /* Resolve the channel from server */
1544 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1546 silc_free(channel_id);
1550 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1552 /* Cache the received Client ID's and modes. */
1553 for (i = 0; i < list_count; i++) {
1556 SilcClientID *client_id;
1559 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1561 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1566 SILC_GET32_MSB(mode, client_mode_list.data);
1568 /* Check if we have this client cached already. */
1569 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1570 if (!client_entry || !client_entry->username || !client_entry->realname) {
1572 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1573 /* Attach to this resolving and wait until it finishes */
1574 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1575 client_entry->resolve_cmd_ident,
1579 silc_buffer_pull(&client_id_list, idp_len);
1580 silc_buffer_pull(&client_mode_list, 4);
1583 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1584 client_entry->resolve_cmd_ident = conn->cmd_ident + 1;
1587 /* No we don't have it (or it is incomplete in information), query
1588 it from the server. Assemble argument table that will be sent
1589 for the WHOIS command later. */
1590 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1592 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1594 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1596 res_argv[res_argc] = client_id_list.data;
1597 res_argv_lens[res_argc] = idp_len;
1598 res_argv_types[res_argc] = res_argc + 3;
1601 if (!silc_client_on_channel(channel, client_entry)) {
1602 chu = silc_calloc(1, sizeof(*chu));
1603 chu->client = client_entry;
1605 chu->channel = channel;
1606 silc_hash_table_add(channel->user_list, client_entry, chu);
1607 silc_hash_table_add(client_entry->channels, channel, chu);
1611 silc_free(client_id);
1612 silc_buffer_pull(&client_id_list, idp_len);
1613 silc_buffer_pull(&client_mode_list, 4);
1616 /* Query the client information from server if the list included clients
1617 that we don't know about. */
1621 /* Send the WHOIS command to server */
1622 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1623 silc_client_command_reply_whois_i, 0,
1625 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1626 res_argc, res_argv, res_argv_lens,
1627 res_argv_types, conn->cmd_ident);
1628 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1629 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1632 /* Register pending command callback. After we've received the WHOIS
1633 command reply we will reprocess this command reply by re-calling this
1634 USERS command reply callback. */
1635 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1638 silc_buffer_free(res_cmd);
1639 silc_free(channel_id);
1640 silc_free(res_argv);
1641 silc_free(res_argv_lens);
1642 silc_free(res_argv_types);
1649 silc_buffer_push(&client_id_list, (client_id_list.data -
1650 client_id_list.head));
1651 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1652 client_mode_list.head));
1654 /* Notify application */
1656 COMMAND_REPLY((ARGS, channel, list_count, &client_id_list,
1657 &client_mode_list));
1660 silc_free(channel_id);
1664 /* Reply to USERS command. Received list of client ID's and theirs modes
1665 on the channel we requested. */
1667 SILC_CLIENT_CMD_REPLY_FUNC(users)
1669 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1670 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1672 SILC_LOG_DEBUG(("Start"));
1674 if (cmd->error != SILC_STATUS_OK) {
1675 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1676 "%s", silc_get_status_message(cmd->error));
1677 COMMAND_REPLY_ERROR;
1681 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
1682 silc_client_command_reply_users_cb,
1683 silc_client_command_reply_users))
1687 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1688 silc_client_command_reply_free(cmd);
1691 /* Received command reply to GETKEY command. WE've received the remote
1692 client's public key. */
1694 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1696 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1697 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1698 SilcIDPayload idp = NULL;
1699 SilcClientID *client_id = NULL;
1700 SilcClientEntry client_entry;
1701 SilcServerID *server_id = NULL;
1702 SilcServerEntry server_entry;
1704 unsigned char *tmp, *pk;
1708 SilcPublicKey public_key = NULL;
1710 SILC_LOG_DEBUG(("Start"));
1712 if (cmd->error != SILC_STATUS_OK) {
1713 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1714 "%s", silc_get_status_message(cmd->error));
1715 COMMAND_REPLY_ERROR;
1719 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1721 COMMAND_REPLY_ERROR;
1724 idp = silc_id_payload_parse(tmp, len);
1726 COMMAND_REPLY_ERROR;
1730 /* Get the public key payload */
1731 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1733 /* Decode the public key */
1734 SILC_GET16_MSB(pk_len, tmp);
1735 SILC_GET16_MSB(type, tmp + 2);
1738 if (type == SILC_SKE_PK_TYPE_SILC)
1739 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1743 id_type = silc_id_payload_get_type(idp);
1744 if (id_type == SILC_ID_CLIENT) {
1745 /* Received client's public key */
1746 client_id = silc_id_payload_get_id(idp);
1747 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1748 if (!client_entry) {
1749 COMMAND_REPLY_ERROR;
1753 /* Notify application */
1754 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1755 } else if (id_type == SILC_ID_SERVER) {
1756 /* Received server's public key */
1757 server_id = silc_id_payload_get_id(idp);
1758 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1759 if (!server_entry) {
1760 COMMAND_REPLY_ERROR;
1764 /* Notify application */
1765 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1769 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1771 silc_id_payload_free(idp);
1773 silc_pkcs_public_key_free(public_key);
1774 silc_free(client_id);
1775 silc_free(server_id);
1776 silc_client_command_reply_free(cmd);
1779 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1781 silc_client_command_reply_free(context);
1785 /******************************************************************************
1787 Internal command reply functions
1789 ******************************************************************************/
1791 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1793 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1794 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1796 SILC_LOG_DEBUG(("Start"));
1798 if (cmd->error != SILC_STATUS_OK)
1801 /* Save WHOIS info */
1802 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1804 /* Pending callbacks are not executed if this was an list entry */
1805 if (cmd->status != SILC_STATUS_OK &&
1806 cmd->status != SILC_STATUS_LIST_END) {
1807 silc_client_command_reply_free(cmd);
1812 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1814 /* If we received notify for invalid ID we'll remove the ID if we
1816 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1817 SilcClientEntry client_entry;
1819 unsigned char *tmp =
1820 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1823 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1825 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1828 silc_client_del_client(cmd->client, conn, client_entry);
1829 silc_free(client_id);
1834 /* Unregister this command reply */
1835 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1836 NULL, silc_client_command_reply_whois_i,
1839 silc_client_command_reply_free(cmd);
1842 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1844 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1845 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1847 SILC_LOG_DEBUG(("Start"));
1849 if (cmd->error != SILC_STATUS_OK)
1852 /* Save IDENTIFY info */
1853 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1855 /* Pending callbacks are not executed if this was an list entry */
1856 if (cmd->status != SILC_STATUS_OK &&
1857 cmd->status != SILC_STATUS_LIST_END) {
1858 silc_client_command_reply_free(cmd);
1863 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1865 /* If we received notify for invalid ID we'll remove the ID if we
1867 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1868 SilcClientEntry client_entry;
1870 unsigned char *tmp =
1871 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1874 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1876 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1879 silc_client_del_client(cmd->client, conn, client_entry);
1880 silc_free(client_id);
1885 /* Unregister this command reply */
1886 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1887 NULL, silc_client_command_reply_identify_i,
1890 silc_client_command_reply_free(cmd);
1893 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1895 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1896 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1898 SilcServerEntry server;
1899 SilcServerID *server_id = NULL;
1900 char *server_name, *server_info;
1903 SILC_LOG_DEBUG(("Start"));
1905 if (cmd->error != SILC_STATUS_OK)
1909 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1913 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1917 /* Get server name */
1918 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1922 /* Get server info */
1923 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1927 /* See whether we have this server cached. If not create it. */
1928 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1930 SILC_LOG_DEBUG(("New server entry"));
1931 silc_client_add_server(cmd->client, conn, server_name, server_info,
1932 silc_id_dup(server_id, SILC_ID_SERVER));
1936 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1937 silc_free(server_id);
1938 silc_client_command_reply_free(cmd);
1941 static void silc_client_command_reply_users_i_cb(SilcClient client,
1942 SilcClientConnection conn,
1943 SilcChannelEntry *channels,
1944 SilcUInt32 channels_count,
1947 if (!channels_count) {
1948 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1949 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1951 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1952 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1953 "%s", silc_get_status_message(cmd->error));
1954 COMMAND_REPLY_ERROR;
1955 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1956 silc_client_command_reply_free(cmd);
1960 silc_client_command_reply_users_i(context, NULL);
1963 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
1965 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1967 SILC_LOG_DEBUG(("Start"));
1969 if (cmd->error != SILC_STATUS_OK)
1972 /* Save USERS info */
1973 if (silc_client_command_reply_users_save(
1974 cmd, cmd->status, FALSE,
1975 silc_client_command_reply_users_i_cb,
1976 silc_client_command_reply_users_i))
1980 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1982 /* Unregister this command reply */
1983 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
1984 NULL, silc_client_command_reply_users_i,
1987 silc_client_command_reply_free(cmd);
1990 /* Private range commands, specific to this implementation (and compatible
1991 with SILC Server >= 0.9). */
1993 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1995 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1996 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1998 if (cmd->error != SILC_STATUS_OK) {
1999 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2000 "%s", silc_get_status_message(cmd->error));
2001 COMMAND_REPLY_ERROR;
2005 /* Notify application */
2006 COMMAND_REPLY((ARGS));
2009 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2010 silc_client_command_reply_free(cmd);
2013 SILC_CLIENT_CMD_REPLY_FUNC(close)
2015 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2016 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2018 if (cmd->error != SILC_STATUS_OK) {
2019 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2020 "%s", silc_get_status_message(cmd->error));
2021 COMMAND_REPLY_ERROR;
2025 /* Notify application */
2026 COMMAND_REPLY((ARGS));
2029 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2030 silc_client_command_reply_free(cmd);
2033 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2035 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2036 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2038 if (cmd->error != SILC_STATUS_OK) {
2039 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2040 "%s", silc_get_status_message(cmd->error));
2041 COMMAND_REPLY_ERROR;
2045 /* Notify application */
2046 COMMAND_REPLY((ARGS));
2049 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2050 silc_client_command_reply_free(cmd);