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 > 2) {
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 /* Notify application */
519 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
520 COMMAND_REPLY((ARGS, conn->local_entry));
521 silc_client_command_reply_free(cmd);
525 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
526 silc_client_command_reply_free(cmd);
529 /* Received reply to the LIST command. */
531 SILC_CLIENT_CMD_REPLY_FUNC(list)
533 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
534 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
535 unsigned char *tmp, *name, *topic;
536 SilcUInt32 usercount = 0, len;
537 SilcChannelID *channel_id = NULL;
538 SilcChannelEntry channel_entry;
540 COMMAND_CHECK_STATUS;
542 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
548 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
554 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
560 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
561 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
563 SILC_GET32_MSB(usercount, tmp);
565 /* Check whether the channel exists, and add it to cache if it doesn't. */
566 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
568 if (!channel_entry) {
569 /* Add new channel entry */
570 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
572 if (!channel_entry) {
579 /* Notify application */
580 COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount));
582 /* Pending callbacks are not executed if this was an list entry */
583 if (cmd->status != SILC_STATUS_OK &&
584 cmd->status != SILC_STATUS_LIST_END) {
585 silc_client_command_reply_free(cmd);
590 silc_free(channel_id);
591 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
592 silc_client_command_reply_free(cmd);
595 /* Received reply to topic command. */
597 SILC_CLIENT_CMD_REPLY_FUNC(topic)
599 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
600 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
601 SilcChannelEntry channel;
602 SilcChannelID *channel_id = NULL;
605 SilcUInt32 argc, len;
607 if (cmd->error != SILC_STATUS_OK) {
608 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
609 "%s", silc_get_status_message(cmd->error));
614 argc = silc_argument_get_arg_num(cmd->args);
615 if (argc < 1 || argc > 3) {
620 /* Take Channel ID */
621 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
626 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
630 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
634 /* Get the channel entry */
635 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
637 silc_free(channel_id);
642 /* Notify application */
643 COMMAND_REPLY((ARGS, channel, topic));
646 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
647 silc_client_command_reply_free(cmd);
650 /* Received reply to invite command. */
652 SILC_CLIENT_CMD_REPLY_FUNC(invite)
654 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
655 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
656 SilcChannelEntry channel;
657 SilcChannelID *channel_id;
661 if (cmd->error != SILC_STATUS_OK) {
662 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
663 "%s", silc_get_status_message(cmd->error));
668 /* Take Channel ID */
669 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
673 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
677 /* Get the channel entry */
678 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
680 silc_free(channel_id);
685 /* Get the invite list */
686 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
688 /* Notify application */
689 COMMAND_REPLY((ARGS, channel, tmp));
692 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
693 silc_client_command_reply_free(cmd);
696 /* Received reply to the KILL command. */
698 SILC_CLIENT_CMD_REPLY_FUNC(kill)
700 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
701 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
703 if (cmd->error != SILC_STATUS_OK) {
704 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
705 "%s", silc_get_status_message(cmd->error));
710 /* Notify application */
711 COMMAND_REPLY((ARGS));
714 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
715 silc_client_command_reply_free(cmd);
718 /* Received reply to INFO command. We receive the server ID and some
719 information about the server user requested. */
721 SILC_CLIENT_CMD_REPLY_FUNC(info)
723 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
724 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
726 SilcServerEntry server;
727 SilcServerID *server_id = NULL;
728 char *server_name, *server_info;
731 SILC_LOG_DEBUG(("Start"));
733 if (cmd->error != SILC_STATUS_OK) {
734 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
735 silc_get_status_message(cmd->error));
741 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
745 server_id = silc_id_payload_parse_id(tmp, len, NULL);
749 /* Get server name */
750 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
754 /* Get server info */
755 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
759 /* See whether we have this server cached. If not create it. */
760 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
762 SILC_LOG_DEBUG(("New server entry"));
763 server = silc_client_add_server(cmd->client, conn, server_name,
765 silc_id_dup(server_id, SILC_ID_SERVER));
770 /* Notify application */
771 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
774 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
775 silc_free(server_id);
776 silc_client_command_reply_free(cmd);
779 /* Received reply to PING command. The reply time is shown to user. */
781 SILC_CLIENT_CMD_REPLY_FUNC(ping)
783 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
784 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
787 time_t diff, curtime;
789 if (cmd->error != SILC_STATUS_OK) {
790 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
791 "%s", silc_get_status_message(cmd->error));
796 curtime = time(NULL);
797 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
798 cmd->packet->src_id_type);
799 if (!id || !conn->ping) {
804 for (i = 0; i < conn->ping_count; i++) {
805 if (!conn->ping[i].dest_id)
807 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
808 diff = curtime - conn->ping[i].start_time;
809 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
810 "Ping reply from %s: %d second%s",
811 conn->ping[i].dest_name, diff,
812 diff == 1 ? "" : "s");
814 conn->ping[i].start_time = 0;
815 silc_free(conn->ping[i].dest_id);
816 conn->ping[i].dest_id = NULL;
817 silc_free(conn->ping[i].dest_name);
818 conn->ping[i].dest_name = NULL;
825 /* Notify application */
826 COMMAND_REPLY((ARGS));
829 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
830 silc_client_command_reply_free(cmd);
833 /* Received reply for JOIN command. */
835 SILC_CLIENT_CMD_REPLY_FUNC(join)
837 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
838 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
839 SilcChannelEntry channel;
841 SilcChannelID *channel_id;
842 SilcUInt32 argc, mode = 0, len, list_count;
843 char *topic, *tmp, *channel_name = NULL, *hmac;
844 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
847 SILC_LOG_DEBUG(("Start"));
849 if (cmd->error != SILC_STATUS_OK) {
850 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
851 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
852 "%s", silc_get_status_message(cmd->error));
857 argc = silc_argument_get_arg_num(cmd->args);
858 if (argc < 7 || argc > 14) {
859 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
860 "Cannot join channel: Bad reply packet");
865 /* Get channel name */
866 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
868 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
869 "Cannot join channel: Bad reply packet");
876 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
878 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
879 "Cannot join channel: Bad reply packet");
883 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
889 /* Get channel mode */
890 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
892 SILC_GET32_MSB(mode, tmp);
894 /* Get channel key */
895 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
897 keyp = silc_buffer_alloc(len);
898 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
899 silc_buffer_put(keyp, tmp, len);
903 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
905 /* Check whether we have this channel entry already. */
906 channel = silc_client_get_channel(cmd->client, conn, channel_name);
908 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
909 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
911 /* Create new channel entry */
912 channel = silc_client_add_channel(cmd->client, conn, channel_name,
916 conn->current_channel = channel;
919 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
921 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
922 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
923 "Cannot join channel: Unsupported HMAC `%s'", hmac);
929 /* Get the list count */
930 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
933 SILC_GET32_MSB(list_count, tmp);
935 /* Get Client ID list */
936 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
940 client_id_list = silc_buffer_alloc(len);
941 silc_buffer_pull_tail(client_id_list, len);
942 silc_buffer_put(client_id_list, tmp, len);
944 /* Get client mode list */
945 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
949 client_mode_list = silc_buffer_alloc(len);
950 silc_buffer_pull_tail(client_mode_list, len);
951 silc_buffer_put(client_mode_list, tmp, len);
953 /* Add clients we received in the reply to the channel */
954 for (i = 0; i < list_count; i++) {
957 SilcClientID *client_id;
958 SilcClientEntry client_entry;
961 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
963 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
968 SILC_GET32_MSB(mode, client_mode_list->data);
970 /* Check if we have this client cached already. */
971 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
973 /* No, we don't have it, add entry for it. */
975 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
976 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
979 /* Join client to the channel */
980 if (!silc_client_on_channel(channel, client_entry)) {
981 chu = silc_calloc(1, sizeof(*chu));
982 chu->client = client_entry;
983 chu->channel = channel;
985 silc_hash_table_add(channel->user_list, client_entry, chu);
986 silc_hash_table_add(client_entry->channels, channel, chu);
989 silc_free(client_id);
990 silc_buffer_pull(client_id_list, idp_len);
991 silc_buffer_pull(client_mode_list, 4);
993 silc_buffer_push(client_id_list, client_id_list->data -
994 client_id_list->head);
995 silc_buffer_push(client_mode_list, client_mode_list->data -
996 client_mode_list->head);
998 /* Save channel key */
999 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1000 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1002 /* Notify application */
1003 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1004 keyp ? keyp->head : NULL, NULL,
1005 NULL, topic, hmac, list_count, client_id_list,
1009 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1010 silc_client_command_reply_free(cmd);
1013 silc_buffer_free(keyp);
1015 silc_buffer_free(client_id_list);
1016 if (client_mode_list)
1017 silc_buffer_free(client_mode_list);
1020 /* Received reply for MOTD command */
1022 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1024 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1025 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1027 char *motd = NULL, *cp, line[256];
1029 if (cmd->error != SILC_STATUS_OK) {
1030 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1031 "%s", silc_get_status_message(cmd->error));
1032 COMMAND_REPLY_ERROR;
1036 argc = silc_argument_get_arg_num(cmd->args);
1038 COMMAND_REPLY_ERROR;
1043 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1045 COMMAND_REPLY_ERROR;
1052 if (cp[i++] == '\n') {
1053 memset(line, 0, sizeof(line));
1054 strncat(line, cp, i - 1);
1060 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1069 /* Notify application */
1070 COMMAND_REPLY((ARGS, motd));
1073 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1074 silc_client_command_reply_free(cmd);
1077 /* Received reply tot he UMODE command. Save the current user mode */
1079 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1081 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1082 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1086 if (cmd->error != SILC_STATUS_OK) {
1087 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1088 "%s", silc_get_status_message(cmd->error));
1089 COMMAND_REPLY_ERROR;
1093 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1095 COMMAND_REPLY_ERROR;
1099 SILC_GET32_MSB(mode, tmp);
1100 conn->local_entry->mode = mode;
1102 /* Notify application */
1103 COMMAND_REPLY((ARGS, mode));
1106 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1107 silc_client_command_reply_free(cmd);
1110 /* Received reply for CMODE command. */
1112 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1114 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1115 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1118 SilcChannelID *channel_id;
1119 SilcChannelEntry channel;
1122 if (cmd->error != SILC_STATUS_OK) {
1123 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1124 "%s", silc_get_status_message(cmd->error));
1125 COMMAND_REPLY_ERROR;
1129 /* Take Channel ID */
1130 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1133 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1137 /* Get the channel entry */
1138 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1140 silc_free(channel_id);
1141 COMMAND_REPLY_ERROR;
1145 /* Get channel mode */
1146 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1148 silc_free(channel_id);
1149 COMMAND_REPLY_ERROR;
1154 SILC_GET32_MSB(mode, tmp);
1155 channel->mode = mode;
1157 /* Notify application */
1158 COMMAND_REPLY((ARGS, channel, mode));
1160 silc_free(channel_id);
1163 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1164 silc_client_command_reply_free(cmd);
1167 /* Received reply for CUMODE command */
1169 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1171 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1172 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1173 SilcClientID *client_id;
1174 SilcChannelID *channel_id;
1175 SilcClientEntry client_entry;
1176 SilcChannelEntry channel;
1177 SilcChannelUser chu;
1178 unsigned char *modev, *tmp, *id;
1179 SilcUInt32 len, mode;
1181 if (cmd->error != SILC_STATUS_OK) {
1182 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1183 "%s", silc_get_status_message(cmd->error));
1184 COMMAND_REPLY_ERROR;
1188 /* Get channel mode */
1189 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1191 COMMAND_REPLY_ERROR;
1195 /* Take Channel ID */
1196 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1199 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1203 /* Get the channel entry */
1204 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1206 silc_free(channel_id);
1207 COMMAND_REPLY_ERROR;
1212 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1214 silc_free(channel_id);
1215 COMMAND_REPLY_ERROR;
1218 client_id = silc_id_payload_parse_id(id, len, NULL);
1220 silc_free(channel_id);
1221 COMMAND_REPLY_ERROR;
1225 /* Get client entry */
1226 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1227 if (!client_entry) {
1228 silc_free(channel_id);
1229 silc_free(client_id);
1230 COMMAND_REPLY_ERROR;
1235 SILC_GET32_MSB(mode, modev);
1236 chu = silc_client_on_channel(channel, client_entry);
1240 /* Notify application */
1241 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1242 silc_free(client_id);
1243 silc_free(channel_id);
1246 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1247 silc_client_command_reply_free(cmd);
1250 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1252 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1253 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1255 if (cmd->error != SILC_STATUS_OK) {
1256 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1257 "%s", silc_get_status_message(cmd->error));
1258 COMMAND_REPLY_ERROR;
1262 /* Notify application */
1263 COMMAND_REPLY((ARGS));
1266 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1267 silc_client_command_reply_free(cmd);
1270 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1272 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1273 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1275 if (cmd->error != SILC_STATUS_OK) {
1276 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1277 "%s", silc_get_status_message(cmd->error));
1278 COMMAND_REPLY_ERROR;
1282 /* Notify application */
1283 COMMAND_REPLY((ARGS));
1286 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1287 silc_client_command_reply_free(cmd);
1290 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1292 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1293 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1295 if (cmd->error != SILC_STATUS_OK) {
1296 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1297 "%s", silc_get_status_message(cmd->error));
1298 COMMAND_REPLY_ERROR;
1302 /* Notify application */
1303 COMMAND_REPLY((ARGS));
1306 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1307 silc_client_command_reply_free(cmd);
1310 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1312 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1313 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1316 if (cmd->error != SILC_STATUS_OK) {
1317 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1318 "%s", silc_get_status_message(cmd->error));
1319 COMMAND_REPLY_ERROR;
1323 /* Notify application */
1324 COMMAND_REPLY((ARGS));
1326 /* Generate the detachment data and deliver it to the client in the
1327 detach client operation */
1328 detach = silc_client_get_detach_data(cmd->client, conn);
1330 cmd->client->internal->ops->detach(cmd->client, conn,
1331 detach->data, detach->len);
1332 silc_buffer_free(detach);
1336 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1337 silc_client_command_reply_free(cmd);
1340 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1342 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1343 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1345 if (cmd->error != SILC_STATUS_OK) {
1346 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1347 "%s", silc_get_status_message(cmd->error));
1348 COMMAND_REPLY_ERROR;
1352 /* Notify application */
1353 COMMAND_REPLY((ARGS));
1356 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1357 silc_client_command_reply_free(cmd);
1360 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1362 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1363 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1364 SilcChannelEntry channel;
1365 SilcChannelID *channel_id;
1369 if (cmd->error != SILC_STATUS_OK) {
1370 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1371 "%s", silc_get_status_message(cmd->error));
1372 COMMAND_REPLY_ERROR;
1376 /* Take Channel ID */
1377 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1381 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1385 /* Get the channel entry */
1386 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1388 silc_free(channel_id);
1389 COMMAND_REPLY_ERROR;
1393 /* Get the ban list */
1394 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1396 /* Notify application */
1397 COMMAND_REPLY((ARGS, channel, tmp));
1400 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1401 silc_client_command_reply_free(cmd);
1404 /* Reply to LEAVE command. */
1406 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1408 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1409 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1410 SilcChannelID *channel_id;
1411 SilcChannelEntry channel = NULL;
1415 if (cmd->error != SILC_STATUS_OK) {
1416 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1417 "%s", silc_get_status_message(cmd->error));
1418 COMMAND_REPLY_ERROR;
1422 /* From protocol version 1.1 we get the channel ID of the left channel */
1423 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1425 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1429 /* Get the channel entry */
1430 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1432 silc_free(channel_id);
1433 COMMAND_REPLY_ERROR;
1437 silc_free(channel_id);
1440 /* Notify application */
1441 COMMAND_REPLY((ARGS, channel));
1444 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1445 silc_client_command_reply_free(cmd);
1448 /* Channel resolving callback for USERS command reply. */
1450 static void silc_client_command_reply_users_cb(SilcClient client,
1451 SilcClientConnection conn,
1452 SilcChannelEntry *channels,
1453 SilcUInt32 channels_count,
1456 if (!channels_count) {
1457 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1458 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1460 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1461 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1462 "%s", silc_get_status_message(cmd->error));
1463 COMMAND_REPLY_ERROR;
1464 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1465 silc_client_command_reply_free(cmd);
1469 silc_client_command_reply_users(context, NULL);
1473 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1476 SilcGetChannelCallback get_channel,
1477 SilcCommandCb get_clients)
1479 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1480 SilcChannelEntry channel;
1481 SilcClientEntry client_entry;
1482 SilcChannelUser chu;
1483 SilcChannelID *channel_id = NULL;
1484 SilcBufferStruct client_id_list, client_mode_list;
1486 SilcUInt32 tmp_len, list_count;
1488 unsigned char **res_argv = NULL;
1489 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1490 bool wait_res = FALSE;
1492 SILC_LOG_DEBUG(("Start"));
1494 /* Get channel ID */
1495 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1497 COMMAND_REPLY_ERROR;
1500 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1502 COMMAND_REPLY_ERROR;
1506 /* Get the list count */
1507 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1509 COMMAND_REPLY_ERROR;
1512 SILC_GET32_MSB(list_count, tmp);
1514 /* Get Client ID list */
1515 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1517 COMMAND_REPLY_ERROR;
1520 silc_buffer_set(&client_id_list, tmp, tmp_len);
1522 /* Get client mode list */
1523 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1525 COMMAND_REPLY_ERROR;
1528 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1530 /* Get channel entry */
1531 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1533 /* Resolve the channel from server */
1534 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1536 silc_free(channel_id);
1540 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1542 /* Cache the received Client ID's and modes. */
1543 for (i = 0; i < list_count; i++) {
1546 SilcClientID *client_id;
1549 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1551 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1556 SILC_GET32_MSB(mode, client_mode_list.data);
1558 /* Check if we have this client cached already. */
1559 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1560 if (!client_entry || !client_entry->username || !client_entry->realname) {
1562 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1563 /* Attach to this resolving and wait until it finishes */
1564 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1565 client_entry->resolve_cmd_ident,
1569 silc_buffer_pull(&client_id_list, idp_len);
1570 silc_buffer_pull(&client_mode_list, 4);
1573 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1574 client_entry->resolve_cmd_ident = conn->cmd_ident + 1;
1577 /* No we don't have it (or it is incomplete in information), query
1578 it from the server. Assemble argument table that will be sent
1579 for the WHOIS command later. */
1580 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1582 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1584 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1586 res_argv[res_argc] = client_id_list.data;
1587 res_argv_lens[res_argc] = idp_len;
1588 res_argv_types[res_argc] = res_argc + 3;
1591 if (!silc_client_on_channel(channel, client_entry)) {
1592 chu = silc_calloc(1, sizeof(*chu));
1593 chu->client = client_entry;
1595 chu->channel = channel;
1596 silc_hash_table_add(channel->user_list, client_entry, chu);
1597 silc_hash_table_add(client_entry->channels, channel, chu);
1601 silc_free(client_id);
1602 silc_buffer_pull(&client_id_list, idp_len);
1603 silc_buffer_pull(&client_mode_list, 4);
1606 /* Query the client information from server if the list included clients
1607 that we don't know about. */
1611 /* Send the WHOIS command to server */
1612 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1613 silc_client_command_reply_whois_i, 0,
1615 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1616 res_argc, res_argv, res_argv_lens,
1617 res_argv_types, conn->cmd_ident);
1618 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1619 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1622 /* Register pending command callback. After we've received the WHOIS
1623 command reply we will reprocess this command reply by re-calling this
1624 USERS command reply callback. */
1625 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1628 silc_buffer_free(res_cmd);
1629 silc_free(channel_id);
1630 silc_free(res_argv);
1631 silc_free(res_argv_lens);
1632 silc_free(res_argv_types);
1639 silc_buffer_push(&client_id_list, (client_id_list.data -
1640 client_id_list.head));
1641 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1642 client_mode_list.head));
1644 /* Notify application */
1646 COMMAND_REPLY((ARGS, channel, list_count, &client_id_list,
1647 &client_mode_list));
1650 silc_free(channel_id);
1654 /* Reply to USERS command. Received list of client ID's and theirs modes
1655 on the channel we requested. */
1657 SILC_CLIENT_CMD_REPLY_FUNC(users)
1659 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1660 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1662 SILC_LOG_DEBUG(("Start"));
1664 if (cmd->error != SILC_STATUS_OK) {
1665 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1666 "%s", silc_get_status_message(cmd->error));
1667 COMMAND_REPLY_ERROR;
1671 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
1672 silc_client_command_reply_users_cb,
1673 silc_client_command_reply_users))
1677 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1678 silc_client_command_reply_free(cmd);
1681 /* Received command reply to GETKEY command. WE've received the remote
1682 client's public key. */
1684 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1686 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1687 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1688 SilcIDPayload idp = NULL;
1689 SilcClientID *client_id = NULL;
1690 SilcClientEntry client_entry;
1691 SilcServerID *server_id = NULL;
1692 SilcServerEntry server_entry;
1694 unsigned char *tmp, *pk;
1698 SilcPublicKey public_key = NULL;
1700 SILC_LOG_DEBUG(("Start"));
1702 if (cmd->error != SILC_STATUS_OK) {
1703 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1704 "%s", silc_get_status_message(cmd->error));
1705 COMMAND_REPLY_ERROR;
1709 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1711 COMMAND_REPLY_ERROR;
1714 idp = silc_id_payload_parse(tmp, len);
1716 COMMAND_REPLY_ERROR;
1720 /* Get the public key payload */
1721 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1723 /* Decode the public key */
1724 SILC_GET16_MSB(pk_len, tmp);
1725 SILC_GET16_MSB(type, tmp + 2);
1728 if (type == SILC_SKE_PK_TYPE_SILC)
1729 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1733 id_type = silc_id_payload_get_type(idp);
1734 if (id_type == SILC_ID_CLIENT) {
1735 /* Received client's public key */
1736 client_id = silc_id_payload_get_id(idp);
1737 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1738 if (!client_entry) {
1739 COMMAND_REPLY_ERROR;
1743 /* Notify application */
1744 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1745 } else if (id_type == SILC_ID_SERVER) {
1746 /* Received server's public key */
1747 server_id = silc_id_payload_get_id(idp);
1748 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1749 if (!server_entry) {
1750 COMMAND_REPLY_ERROR;
1754 /* Notify application */
1755 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1759 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1761 silc_id_payload_free(idp);
1763 silc_pkcs_public_key_free(public_key);
1764 silc_free(client_id);
1765 silc_free(server_id);
1766 silc_client_command_reply_free(cmd);
1769 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1771 silc_client_command_reply_free(context);
1775 /******************************************************************************
1777 Internal command reply functions
1779 ******************************************************************************/
1781 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1783 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1784 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1786 SILC_LOG_DEBUG(("Start"));
1788 if (cmd->error != SILC_STATUS_OK)
1791 /* Save WHOIS info */
1792 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1794 /* Pending callbacks are not executed if this was an list entry */
1795 if (cmd->status != SILC_STATUS_OK &&
1796 cmd->status != SILC_STATUS_LIST_END) {
1797 silc_client_command_reply_free(cmd);
1802 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1804 /* If we received notify for invalid ID we'll remove the ID if we
1806 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1807 SilcClientEntry client_entry;
1809 unsigned char *tmp =
1810 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1813 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1815 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1818 silc_client_del_client(cmd->client, conn, client_entry);
1819 silc_free(client_id);
1824 /* Unregister this command reply */
1825 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1826 NULL, silc_client_command_reply_whois_i,
1829 silc_client_command_reply_free(cmd);
1832 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1834 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1835 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1837 SILC_LOG_DEBUG(("Start"));
1839 if (cmd->error != SILC_STATUS_OK)
1842 /* Save IDENTIFY info */
1843 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1845 /* Pending callbacks are not executed if this was an list entry */
1846 if (cmd->status != SILC_STATUS_OK &&
1847 cmd->status != SILC_STATUS_LIST_END) {
1848 silc_client_command_reply_free(cmd);
1853 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1855 /* If we received notify for invalid ID we'll remove the ID if we
1857 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1858 SilcClientEntry client_entry;
1860 unsigned char *tmp =
1861 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1864 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1866 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1869 silc_client_del_client(cmd->client, conn, client_entry);
1870 silc_free(client_id);
1875 /* Unregister this command reply */
1876 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1877 NULL, silc_client_command_reply_identify_i,
1880 silc_client_command_reply_free(cmd);
1883 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1885 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1886 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1888 SilcServerEntry server;
1889 SilcServerID *server_id = NULL;
1890 char *server_name, *server_info;
1893 SILC_LOG_DEBUG(("Start"));
1895 if (cmd->error != SILC_STATUS_OK)
1899 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1903 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1907 /* Get server name */
1908 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1912 /* Get server info */
1913 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1917 /* See whether we have this server cached. If not create it. */
1918 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1920 SILC_LOG_DEBUG(("New server entry"));
1921 silc_client_add_server(cmd->client, conn, server_name, server_info,
1922 silc_id_dup(server_id, SILC_ID_SERVER));
1926 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1927 silc_free(server_id);
1928 silc_client_command_reply_free(cmd);
1931 static void silc_client_command_reply_users_i_cb(SilcClient client,
1932 SilcClientConnection conn,
1933 SilcChannelEntry *channels,
1934 SilcUInt32 channels_count,
1937 if (!channels_count) {
1938 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1939 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1941 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1942 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1943 "%s", silc_get_status_message(cmd->error));
1944 COMMAND_REPLY_ERROR;
1945 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1946 silc_client_command_reply_free(cmd);
1950 silc_client_command_reply_users_i(context, NULL);
1953 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
1955 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1957 SILC_LOG_DEBUG(("Start"));
1959 if (cmd->error != SILC_STATUS_OK)
1962 /* Save USERS info */
1963 if (silc_client_command_reply_users_save(
1964 cmd, cmd->status, FALSE,
1965 silc_client_command_reply_users_i_cb,
1966 silc_client_command_reply_users_i))
1970 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1972 /* Unregister this command reply */
1973 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
1974 NULL, silc_client_command_reply_users_i,
1977 silc_client_command_reply_free(cmd);
1980 /* Private range commands, specific to this implementation (and compatible
1981 with SILC Server >= 0.9). */
1983 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1985 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1986 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1988 if (cmd->error != SILC_STATUS_OK) {
1989 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1990 "%s", silc_get_status_message(cmd->error));
1991 COMMAND_REPLY_ERROR;
1995 /* Notify application */
1996 COMMAND_REPLY((ARGS));
1999 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2000 silc_client_command_reply_free(cmd);
2003 SILC_CLIENT_CMD_REPLY_FUNC(close)
2005 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2006 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2008 if (cmd->error != SILC_STATUS_OK) {
2009 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2010 "%s", silc_get_status_message(cmd->error));
2011 COMMAND_REPLY_ERROR;
2015 /* Notify application */
2016 COMMAND_REPLY((ARGS));
2019 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2020 silc_client_command_reply_free(cmd);
2023 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2025 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2026 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2028 if (cmd->error != SILC_STATUS_OK) {
2029 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2030 "%s", silc_get_status_message(cmd->error));
2031 COMMAND_REPLY_ERROR;
2035 /* Notify application */
2036 COMMAND_REPLY((ARGS));
2039 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2040 silc_client_command_reply_free(cmd);