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
42 out: and err: goto labels. out label should call the pending
43 command replies, and the err label just handle error condition. */
45 #define COMMAND_CHECK_STATUS \
47 SILC_LOG_DEBUG(("Start")); \
48 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
49 if (SILC_STATUS_IS_ERROR(cmd->status)) { \
51 COMMAND_REPLY_ERROR; \
54 /* List of errors */ \
55 COMMAND_REPLY_ERROR; \
56 if (cmd->status == SILC_STATUS_LIST_END) \
62 /* Same as COMMAND_CHECK_STATUS but doesn't call client operation */
63 #define COMMAND_CHECK_STATUS_I \
65 SILC_LOG_DEBUG(("Start")); \
66 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
67 if (SILC_STATUS_IS_ERROR(cmd->status)) \
69 if (cmd->status == SILC_STATUS_LIST_END) \
75 /* Process received command reply. */
77 void silc_client_command_reply_process(SilcClient client,
78 SilcSocketConnection sock,
79 SilcPacketContext *packet)
81 SilcBuffer buffer = packet->buffer;
82 SilcClientCommand cmd;
83 SilcClientCommandReplyContext ctx;
84 SilcCommandPayload payload;
86 SilcCommandCb reply = NULL;
88 /* Get command reply payload from packet */
89 payload = silc_command_payload_parse(buffer->data, buffer->len);
91 /* Silently ignore bad reply packet */
92 SILC_LOG_DEBUG(("Bad command reply packet"));
96 /* Allocate command reply context. This must be free'd by the
97 command reply routine receiving it. */
98 ctx = silc_calloc(1, sizeof(*ctx));
100 ctx->client = client;
102 ctx->payload = payload;
103 ctx->args = silc_command_get_args(ctx->payload);
104 ctx->packet = packet;
105 ctx->ident = silc_command_get_ident(ctx->payload);
106 silc_command_get_status(ctx->payload, &ctx->status, &ctx->error);
108 /* Check for pending commands and mark to be exeucted */
110 silc_client_command_pending_check(sock->user_data, ctx,
111 silc_command_get(ctx->payload),
112 ctx->ident, &ctx->callbacks_count);
114 /* Execute command reply */
116 command = silc_command_get(ctx->payload);
118 /* Try to find matching the command identifier */
119 silc_list_start(client->internal->commands);
120 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
121 if (cmd->cmd == command && !cmd->ident)
123 if (cmd->cmd == command && cmd->ident == ctx->ident) {
124 (*cmd->reply)((void *)ctx, NULL);
129 if (cmd == SILC_LIST_END) {
131 /* No specific identifier for command reply, call first one found */
138 /* Duplicate Command Reply Context by adding reference counter. The context
139 won't be free'd untill it hits zero. */
141 SilcClientCommandReplyContext
142 silc_client_command_reply_dup(SilcClientCommandReplyContext cmd)
145 SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
146 cmd->users - 1, cmd->users));
150 /* Free command reply context and its internals. */
152 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
155 SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
156 cmd->users + 1, cmd->users));
157 if (cmd->users < 1) {
158 silc_command_payload_free(cmd->payload);
164 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
168 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
169 SilcClientID *client_id;
170 SilcClientEntry client_entry = NULL;
172 unsigned char *id_data, *tmp;
173 char *nickname = NULL, *username = NULL;
174 char *realname = NULL;
175 SilcUInt32 idle = 0, mode = 0;
176 SilcBufferStruct channels, ch_user_modes;
177 bool has_channels = FALSE, has_user_modes = FALSE;
178 unsigned char *fingerprint;
179 SilcUInt32 fingerprint_len;
181 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
188 client_id = silc_id_payload_parse_id(id_data, len, NULL);
195 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
196 username = silc_argument_get_arg_type(cmd->args, 4, &len);
197 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
198 if (!nickname || !username || !realname) {
204 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
206 silc_buffer_set(&channels, tmp, len);
210 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
212 SILC_GET32_MSB(mode, tmp);
214 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
216 SILC_GET32_MSB(idle, tmp);
218 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
220 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
222 silc_buffer_set(&ch_user_modes, tmp, len);
223 has_user_modes = TRUE;
226 /* Check if we have this client cached already. */
227 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
229 SILC_LOG_DEBUG(("Adding new client entry"));
231 silc_client_add_client(cmd->client, conn, nickname, username, realname,
234 silc_client_update_client(cmd->client, conn, client_entry,
235 nickname, username, realname, mode);
236 silc_free(client_id);
239 if (fingerprint && !client_entry->fingerprint) {
240 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
241 client_entry->fingerprint_len = fingerprint_len;
244 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
246 /* Notify application */
247 if (!cmd->callbacks_count && notify)
248 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
249 has_channels ? &channels : NULL, mode, idle,
250 fingerprint, has_user_modes ? &ch_user_modes : NULL));
253 /* Received reply for WHOIS command. This maybe called several times
254 for one WHOIS command as server may reply with list of results. */
256 SILC_CLIENT_CMD_REPLY_FUNC(whois)
258 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
259 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
261 COMMAND_CHECK_STATUS;
263 /* Save WHOIS info */
264 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
266 /* Pending callbacks are not executed if this was an list entry */
267 if (cmd->status != SILC_STATUS_OK &&
268 cmd->status != SILC_STATUS_LIST_END) {
269 silc_client_command_reply_free(cmd);
274 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
277 /* If we received notify for invalid ID we'll remove the ID if we
279 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
280 SilcClientEntry client_entry;
283 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
286 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
288 client_entry = silc_client_get_client_by_id(cmd->client, conn,
291 silc_client_del_client(cmd->client, conn, client_entry);
292 silc_free(client_id);
297 silc_client_command_reply_free(cmd);
300 /* Received reply for WHOWAS command. */
302 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
304 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
305 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
306 SilcClientID *client_id;
307 SilcClientEntry client_entry = NULL;
309 unsigned char *id_data;
310 char *nickname, *username;
311 char *realname = NULL;
313 COMMAND_CHECK_STATUS;
315 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
321 client_id = silc_id_payload_parse_id(id_data, len, NULL);
327 /* Get the client entry, if exists */
328 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
329 silc_free(client_id);
331 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
332 username = silc_argument_get_arg_type(cmd->args, 4, &len);
333 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
334 if (!nickname || !username) {
339 /* Notify application. We don't save any history information to any
340 cache. Just pass the data to the application for displaying on
342 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
344 /* Pending callbacks are not executed if this was an list entry */
345 if (cmd->status != SILC_STATUS_OK &&
346 cmd->status != SILC_STATUS_LIST_END) {
347 silc_client_command_reply_free(cmd);
352 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
354 silc_client_command_reply_free(cmd);
358 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
362 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
363 SilcClient client = cmd->client;
364 SilcClientID *client_id = NULL;
365 SilcServerID *server_id = NULL;
366 SilcChannelID *channel_id = NULL;
367 SilcClientEntry client_entry;
368 SilcServerEntry server_entry;
369 SilcChannelEntry channel_entry;
371 unsigned char *id_data;
372 char *name = NULL, *info = NULL;
373 SilcIDPayload idp = NULL;
376 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
382 idp = silc_id_payload_parse(id_data, len);
389 name = silc_argument_get_arg_type(cmd->args, 3, &len);
390 info = silc_argument_get_arg_type(cmd->args, 4, &len);
392 id_type = silc_id_payload_get_type(idp);
396 client_id = silc_id_payload_get_id(idp);
398 SILC_LOG_DEBUG(("Received client information"));
400 /* Check if we have this client cached already. */
401 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
403 SILC_LOG_DEBUG(("Adding new client entry"));
405 silc_client_add_client(cmd->client, conn, name, info, NULL,
406 silc_id_dup(client_id, id_type), 0);
408 silc_client_update_client(cmd->client, conn, client_entry,
409 name, info, NULL, 0);
412 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
414 /* Notify application */
416 COMMAND_REPLY((ARGS, client_entry, name, info));
420 server_id = silc_id_payload_get_id(idp);
422 SILC_LOG_DEBUG(("Received server information"));
424 /* Check if we have this server cached already. */
425 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
427 SILC_LOG_DEBUG(("Adding new server entry"));
428 server_entry = silc_client_add_server(cmd->client, conn, name, info,
429 silc_id_dup(server_id, id_type));
437 /* Notify application */
439 COMMAND_REPLY((ARGS, server_entry, name, info));
442 case SILC_ID_CHANNEL:
443 channel_id = silc_id_payload_get_id(idp);
445 SILC_LOG_DEBUG(("Received channel information"));
447 /* Check if we have this channel cached already. */
448 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
449 if (!channel_entry) {
453 /* Add new channel entry */
454 channel_entry = silc_client_add_channel(client, conn, name, 0,
459 /* Notify application */
461 COMMAND_REPLY((ARGS, channel_entry, name, info));
465 silc_id_payload_free(idp);
466 silc_free(client_id);
467 silc_free(server_id);
468 silc_free(channel_id);
471 /* Received reply for IDENTIFY command. This maybe called several times
472 for one IDENTIFY command as server may reply with list of results.
473 This is totally silent and does not print anything on screen. */
475 SILC_CLIENT_CMD_REPLY_FUNC(identify)
477 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
478 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
480 COMMAND_CHECK_STATUS;
482 /* Save IDENTIFY info */
483 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
485 /* Pending callbacks are not executed if this was an list entry */
486 if (cmd->status != SILC_STATUS_OK &&
487 cmd->status != SILC_STATUS_LIST_END) {
488 silc_client_command_reply_free(cmd);
493 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
496 /* If we received notify for invalid ID we'll remove the ID if we
498 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
499 SilcClientEntry client_entry;
502 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
505 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
507 client_entry = silc_client_get_client_by_id(cmd->client, conn,
510 silc_client_del_client(cmd->client, conn, client_entry);
511 silc_free(client_id);
516 silc_client_command_reply_free(cmd);
519 /* Received reply for command NICK. If everything went without errors
520 we just received our new Client ID. */
522 SILC_CLIENT_CMD_REPLY_FUNC(nick)
524 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
525 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
528 SilcUInt32 argc, len;
530 SILC_LOG_DEBUG(("Start"));
532 if (cmd->error != SILC_STATUS_OK) {
533 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
534 "Cannot set nickname: %s",
535 silc_get_status_message(cmd->error));
540 argc = silc_argument_get_arg_num(cmd->args);
541 if (argc < 2 || argc > 3) {
542 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
543 "Cannot set nickname: bad reply to command");
548 /* Take received Client ID */
549 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
550 idp = silc_id_payload_parse(tmp, len);
555 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
557 /* Take the new nickname too */
558 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
560 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
562 silc_free(conn->nickname);
563 conn->nickname = strdup(tmp);
564 conn->local_entry->nickname = conn->nickname;
565 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
566 silc_idcache_add(conn->client_cache, strdup(tmp),
567 conn->local_entry->id, conn->local_entry, 0, NULL);
570 /* Notify application */
571 COMMAND_REPLY((ARGS, conn->local_entry, conn->local_entry->nickname));
574 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
575 silc_client_command_reply_free(cmd);
578 /* Received reply to the LIST command. */
580 SILC_CLIENT_CMD_REPLY_FUNC(list)
582 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
583 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
584 unsigned char *tmp, *name, *topic;
585 SilcUInt32 usercount = 0, len;
586 SilcChannelID *channel_id = NULL;
587 SilcChannelEntry channel_entry;
589 COMMAND_CHECK_STATUS;
591 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
597 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
603 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
609 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
610 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
612 SILC_GET32_MSB(usercount, tmp);
614 /* Check whether the channel exists, and add it to cache if it doesn't. */
615 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
617 if (!channel_entry) {
618 /* Add new channel entry */
619 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
621 if (!channel_entry) {
628 /* Notify application */
629 COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount));
631 /* Pending callbacks are not executed if this was an list entry */
632 if (cmd->status != SILC_STATUS_OK &&
633 cmd->status != SILC_STATUS_LIST_END) {
634 silc_client_command_reply_free(cmd);
639 silc_free(channel_id);
640 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
642 silc_client_command_reply_free(cmd);
645 /* Received reply to topic command. */
647 SILC_CLIENT_CMD_REPLY_FUNC(topic)
649 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
650 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
651 SilcChannelEntry channel;
652 SilcChannelID *channel_id = NULL;
655 SilcUInt32 argc, len;
657 if (cmd->error != SILC_STATUS_OK) {
658 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
659 "%s", silc_get_status_message(cmd->error));
664 argc = silc_argument_get_arg_num(cmd->args);
665 if (argc < 1 || argc > 3) {
670 /* Take Channel ID */
671 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
676 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
680 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
684 /* Get the channel entry */
685 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
687 silc_free(channel_id);
692 /* Notify application */
693 COMMAND_REPLY((ARGS, channel, topic));
696 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
697 silc_client_command_reply_free(cmd);
700 /* Received reply to invite command. */
702 SILC_CLIENT_CMD_REPLY_FUNC(invite)
704 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
705 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
706 SilcChannelEntry channel;
707 SilcChannelID *channel_id;
711 if (cmd->error != SILC_STATUS_OK) {
712 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
713 "%s", silc_get_status_message(cmd->error));
718 /* Take Channel ID */
719 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
723 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
727 /* Get the channel entry */
728 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
730 silc_free(channel_id);
735 /* Get the invite list */
736 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
738 /* Notify application */
739 COMMAND_REPLY((ARGS, channel, tmp));
742 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
743 silc_client_command_reply_free(cmd);
746 /* Received reply to the KILL command. */
748 SILC_CLIENT_CMD_REPLY_FUNC(kill)
750 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
751 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
753 if (cmd->error != SILC_STATUS_OK) {
754 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
755 "%s", silc_get_status_message(cmd->error));
760 /* Notify application */
761 COMMAND_REPLY((ARGS));
764 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
765 silc_client_command_reply_free(cmd);
768 /* Received reply to INFO command. We receive the server ID and some
769 information about the server user requested. */
771 SILC_CLIENT_CMD_REPLY_FUNC(info)
773 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
774 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
776 SilcServerEntry server;
777 SilcServerID *server_id = NULL;
778 char *server_name, *server_info;
781 SILC_LOG_DEBUG(("Start"));
783 if (cmd->error != SILC_STATUS_OK) {
784 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
785 silc_get_status_message(cmd->error));
791 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
795 server_id = silc_id_payload_parse_id(tmp, len, NULL);
799 /* Get server name */
800 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
804 /* Get server info */
805 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
809 /* See whether we have this server cached. If not create it. */
810 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
812 SILC_LOG_DEBUG(("New server entry"));
813 server = silc_client_add_server(cmd->client, conn, server_name,
815 silc_id_dup(server_id, SILC_ID_SERVER));
820 /* Notify application */
821 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
824 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
825 silc_free(server_id);
826 silc_client_command_reply_free(cmd);
829 /* Received reply to PING command. The reply time is shown to user. */
831 SILC_CLIENT_CMD_REPLY_FUNC(ping)
833 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
834 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
837 time_t diff, curtime;
839 if (cmd->error != SILC_STATUS_OK) {
840 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
841 "%s", silc_get_status_message(cmd->error));
846 curtime = time(NULL);
847 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
848 cmd->packet->src_id_type);
849 if (!id || !conn->ping) {
854 for (i = 0; i < conn->ping_count; i++) {
855 if (!conn->ping[i].dest_id)
857 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
858 diff = curtime - conn->ping[i].start_time;
859 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
860 "Ping reply from %s: %d second%s",
861 conn->ping[i].dest_name, diff,
862 diff == 1 ? "" : "s");
864 conn->ping[i].start_time = 0;
865 silc_free(conn->ping[i].dest_id);
866 conn->ping[i].dest_id = NULL;
867 silc_free(conn->ping[i].dest_name);
868 conn->ping[i].dest_name = NULL;
875 /* Notify application */
876 COMMAND_REPLY((ARGS));
879 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
880 silc_client_command_reply_free(cmd);
883 /* Received reply for JOIN command. */
885 SILC_CLIENT_CMD_REPLY_FUNC(join)
887 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
888 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
889 SilcChannelEntry channel;
891 SilcChannelID *channel_id;
892 SilcUInt32 argc, mode = 0, len, list_count;
893 char *topic, *tmp, *channel_name = NULL, *hmac;
894 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
897 SILC_LOG_DEBUG(("Start"));
899 if (cmd->error != SILC_STATUS_OK) {
900 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
901 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
902 "%s", silc_get_status_message(cmd->error));
907 argc = silc_argument_get_arg_num(cmd->args);
908 if (argc < 7 || argc > 15) {
909 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
910 "Cannot join channel: Bad reply packet");
915 /* Get channel name */
916 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
918 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
919 "Cannot join channel: Bad reply packet");
926 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
928 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
929 "Cannot join channel: Bad reply packet");
933 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
939 /* Get channel mode */
940 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
942 SILC_GET32_MSB(mode, tmp);
944 /* Get channel key */
945 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
947 keyp = silc_buffer_alloc(len);
948 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
949 silc_buffer_put(keyp, tmp, len);
953 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
955 /* Check whether we have this channel entry already. */
956 channel = silc_client_get_channel(cmd->client, conn, channel_name);
958 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
959 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
961 /* Create new channel entry */
962 channel = silc_client_add_channel(cmd->client, conn, channel_name,
966 conn->current_channel = channel;
969 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
971 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
972 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
973 "Cannot join channel: Unsupported HMAC `%s'", hmac);
979 /* Get the list count */
980 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
983 SILC_GET32_MSB(list_count, tmp);
985 /* Get Client ID list */
986 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
990 client_id_list = silc_buffer_alloc(len);
991 silc_buffer_pull_tail(client_id_list, len);
992 silc_buffer_put(client_id_list, tmp, len);
994 /* Get client mode list */
995 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
999 client_mode_list = silc_buffer_alloc(len);
1000 silc_buffer_pull_tail(client_mode_list, len);
1001 silc_buffer_put(client_mode_list, tmp, len);
1003 /* Add clients we received in the reply to the channel */
1004 for (i = 0; i < list_count; i++) {
1007 SilcClientID *client_id;
1008 SilcClientEntry client_entry;
1011 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1013 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1018 SILC_GET32_MSB(mode, client_mode_list->data);
1020 /* Check if we have this client cached already. */
1021 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1022 if (!client_entry) {
1023 /* No, we don't have it, add entry for it. */
1025 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1026 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1029 /* Join client to the channel */
1030 if (!silc_client_on_channel(channel, client_entry)) {
1031 chu = silc_calloc(1, sizeof(*chu));
1032 chu->client = client_entry;
1033 chu->channel = channel;
1035 silc_hash_table_add(channel->user_list, client_entry, chu);
1036 silc_hash_table_add(client_entry->channels, channel, chu);
1039 silc_free(client_id);
1040 silc_buffer_pull(client_id_list, idp_len);
1041 silc_buffer_pull(client_mode_list, 4);
1043 silc_buffer_push(client_id_list, client_id_list->data -
1044 client_id_list->head);
1045 silc_buffer_push(client_mode_list, client_mode_list->data -
1046 client_mode_list->head);
1048 /* Save channel key */
1049 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1050 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1052 /* Notify application */
1053 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1054 keyp ? keyp->head : NULL, NULL,
1055 NULL, topic, hmac, list_count, client_id_list,
1059 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1060 silc_client_command_reply_free(cmd);
1063 silc_buffer_free(keyp);
1065 silc_buffer_free(client_id_list);
1066 if (client_mode_list)
1067 silc_buffer_free(client_mode_list);
1070 /* Received reply for MOTD command */
1072 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1074 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1075 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1077 char *motd = NULL, *cp, line[256];
1079 if (cmd->error != SILC_STATUS_OK) {
1080 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1081 "%s", silc_get_status_message(cmd->error));
1082 COMMAND_REPLY_ERROR;
1086 argc = silc_argument_get_arg_num(cmd->args);
1088 COMMAND_REPLY_ERROR;
1093 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1095 COMMAND_REPLY_ERROR;
1102 if (cp[i++] == '\n') {
1103 memset(line, 0, sizeof(line));
1104 strncat(line, cp, i - 1);
1110 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1119 /* Notify application */
1120 COMMAND_REPLY((ARGS, motd));
1123 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1124 silc_client_command_reply_free(cmd);
1127 /* Received reply tot he UMODE command. Save the current user mode */
1129 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1131 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1132 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1136 if (cmd->error != SILC_STATUS_OK) {
1137 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1138 "%s", silc_get_status_message(cmd->error));
1139 COMMAND_REPLY_ERROR;
1143 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1145 COMMAND_REPLY_ERROR;
1149 SILC_GET32_MSB(mode, tmp);
1150 conn->local_entry->mode = mode;
1152 /* Notify application */
1153 COMMAND_REPLY((ARGS, mode));
1156 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1157 silc_client_command_reply_free(cmd);
1160 /* Received reply for CMODE command. */
1162 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1164 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1165 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1168 SilcChannelID *channel_id;
1169 SilcChannelEntry channel;
1172 if (cmd->error != SILC_STATUS_OK) {
1173 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1174 "%s", silc_get_status_message(cmd->error));
1175 COMMAND_REPLY_ERROR;
1179 /* Take Channel ID */
1180 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1183 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1187 /* Get the channel entry */
1188 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1190 silc_free(channel_id);
1191 COMMAND_REPLY_ERROR;
1195 /* Get channel mode */
1196 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1198 silc_free(channel_id);
1199 COMMAND_REPLY_ERROR;
1204 SILC_GET32_MSB(mode, tmp);
1205 channel->mode = mode;
1207 /* Notify application */
1208 COMMAND_REPLY((ARGS, channel, mode));
1210 silc_free(channel_id);
1213 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1214 silc_client_command_reply_free(cmd);
1217 /* Received reply for CUMODE command */
1219 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1221 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1222 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1223 SilcClientID *client_id;
1224 SilcChannelID *channel_id;
1225 SilcClientEntry client_entry;
1226 SilcChannelEntry channel;
1227 SilcChannelUser chu;
1228 unsigned char *modev, *tmp, *id;
1229 SilcUInt32 len, mode;
1231 if (cmd->error != SILC_STATUS_OK) {
1232 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1233 "%s", silc_get_status_message(cmd->error));
1234 COMMAND_REPLY_ERROR;
1238 /* Get channel mode */
1239 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1241 COMMAND_REPLY_ERROR;
1245 /* Take Channel ID */
1246 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1249 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1253 /* Get the channel entry */
1254 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1256 silc_free(channel_id);
1257 COMMAND_REPLY_ERROR;
1262 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1264 silc_free(channel_id);
1265 COMMAND_REPLY_ERROR;
1268 client_id = silc_id_payload_parse_id(id, len, NULL);
1270 silc_free(channel_id);
1271 COMMAND_REPLY_ERROR;
1275 /* Get client entry */
1276 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1277 if (!client_entry) {
1278 silc_free(channel_id);
1279 silc_free(client_id);
1280 COMMAND_REPLY_ERROR;
1285 SILC_GET32_MSB(mode, modev);
1286 chu = silc_client_on_channel(channel, client_entry);
1290 /* Notify application */
1291 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1292 silc_free(client_id);
1293 silc_free(channel_id);
1296 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1297 silc_client_command_reply_free(cmd);
1300 SILC_CLIENT_CMD_REPLY_FUNC(kick)
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_KICK);
1317 silc_client_command_reply_free(cmd);
1320 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1322 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1323 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1325 if (cmd->error != SILC_STATUS_OK) {
1326 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1327 "%s", silc_get_status_message(cmd->error));
1328 COMMAND_REPLY_ERROR;
1332 /* Notify application */
1333 COMMAND_REPLY((ARGS));
1336 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1337 silc_client_command_reply_free(cmd);
1340 SILC_CLIENT_CMD_REPLY_FUNC(oper)
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_OPER);
1357 silc_client_command_reply_free(cmd);
1360 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1362 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1363 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1366 if (cmd->error != SILC_STATUS_OK) {
1367 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1368 "%s", silc_get_status_message(cmd->error));
1369 COMMAND_REPLY_ERROR;
1373 /* Notify application */
1374 COMMAND_REPLY((ARGS));
1376 /* Generate the detachment data and deliver it to the client in the
1377 detach client operation */
1378 detach = silc_client_get_detach_data(cmd->client, conn);
1380 cmd->client->internal->ops->detach(cmd->client, conn,
1381 detach->data, detach->len);
1382 silc_buffer_free(detach);
1386 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1387 silc_client_command_reply_free(cmd);
1390 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1392 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1393 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1395 if (cmd->error != SILC_STATUS_OK) {
1396 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1397 "%s", silc_get_status_message(cmd->error));
1398 COMMAND_REPLY_ERROR;
1402 /* Notify application */
1403 COMMAND_REPLY((ARGS));
1406 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1407 silc_client_command_reply_free(cmd);
1410 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1412 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1413 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1414 SilcChannelEntry channel;
1415 SilcChannelID *channel_id;
1419 if (cmd->error != SILC_STATUS_OK) {
1420 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1421 "%s", silc_get_status_message(cmd->error));
1422 COMMAND_REPLY_ERROR;
1426 /* Take Channel ID */
1427 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1431 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1435 /* Get the channel entry */
1436 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1438 silc_free(channel_id);
1439 COMMAND_REPLY_ERROR;
1443 /* Get the ban list */
1444 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1446 /* Notify application */
1447 COMMAND_REPLY((ARGS, channel, tmp));
1450 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1451 silc_client_command_reply_free(cmd);
1454 /* Reply to LEAVE command. */
1456 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1458 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1459 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1460 SilcChannelID *channel_id;
1461 SilcChannelEntry channel = NULL;
1465 if (cmd->error != SILC_STATUS_OK) {
1466 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1467 "%s", silc_get_status_message(cmd->error));
1468 COMMAND_REPLY_ERROR;
1472 /* From protocol version 1.1 we get the channel ID of the left channel */
1473 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1475 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1479 /* Get the channel entry */
1480 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1482 silc_free(channel_id);
1483 COMMAND_REPLY_ERROR;
1487 silc_free(channel_id);
1490 /* Notify application */
1491 COMMAND_REPLY((ARGS, channel));
1494 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1495 silc_client_command_reply_free(cmd);
1498 /* Channel resolving callback for USERS command reply. */
1500 static void silc_client_command_reply_users_cb(SilcClient client,
1501 SilcClientConnection conn,
1502 SilcChannelEntry *channels,
1503 SilcUInt32 channels_count,
1506 if (!channels_count) {
1507 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1508 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1510 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1511 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1512 "%s", silc_get_status_message(cmd->error));
1513 COMMAND_REPLY_ERROR;
1514 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1515 silc_client_command_reply_free(cmd);
1519 silc_client_command_reply_users(context, NULL);
1523 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1526 SilcGetChannelCallback get_channel,
1527 SilcCommandCb get_clients)
1529 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1530 SilcChannelEntry channel;
1531 SilcClientEntry client_entry;
1532 SilcChannelUser chu;
1533 SilcChannelID *channel_id = NULL;
1534 SilcBufferStruct client_id_list, client_mode_list;
1536 SilcUInt32 tmp_len, list_count;
1538 unsigned char **res_argv = NULL;
1539 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1540 bool wait_res = FALSE;
1542 SILC_LOG_DEBUG(("Start"));
1544 /* Get channel ID */
1545 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1547 COMMAND_REPLY_ERROR;
1550 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1552 COMMAND_REPLY_ERROR;
1556 /* Get the list count */
1557 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1559 COMMAND_REPLY_ERROR;
1562 SILC_GET32_MSB(list_count, tmp);
1564 /* Get Client ID list */
1565 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1567 COMMAND_REPLY_ERROR;
1570 silc_buffer_set(&client_id_list, tmp, tmp_len);
1572 /* Get client mode list */
1573 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1575 COMMAND_REPLY_ERROR;
1578 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1580 /* Get channel entry */
1581 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1583 /* Resolve the channel from server */
1584 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1586 silc_free(channel_id);
1590 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1592 /* Cache the received Client ID's and modes. */
1593 for (i = 0; i < list_count; i++) {
1596 SilcClientID *client_id;
1599 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1601 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1606 SILC_GET32_MSB(mode, client_mode_list.data);
1608 /* Check if we have this client cached already. */
1609 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1610 if (!client_entry || !client_entry->username || !client_entry->realname) {
1611 /* No we don't have it (or it is incomplete in information), query
1612 it from the server. Assemble argument table that will be sent
1613 for the WHOIS command later. */
1614 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1616 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1618 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1620 res_argv[res_argc] = client_id_list.data;
1621 res_argv_lens[res_argc] = idp_len;
1622 res_argv_types[res_argc] = res_argc + 4;
1625 if (!silc_client_on_channel(channel, client_entry)) {
1626 chu = silc_calloc(1, sizeof(*chu));
1627 chu->client = client_entry;
1629 chu->channel = channel;
1630 silc_hash_table_add(channel->user_list, client_entry, chu);
1631 silc_hash_table_add(client_entry->channels, channel, chu);
1635 silc_free(client_id);
1636 silc_buffer_pull(&client_id_list, idp_len);
1637 silc_buffer_pull(&client_mode_list, 4);
1640 /* Query the client information from server if the list included clients
1641 that we don't know about. */
1645 /* Send the WHOIS command to server */
1646 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1647 silc_client_command_reply_whois_i, 0,
1649 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1650 res_argc, res_argv, res_argv_lens,
1651 res_argv_types, conn->cmd_ident);
1652 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1653 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1656 /* Register pending command callback. After we've received the WHOIS
1657 command reply we will reprocess this command reply by re-calling this
1658 USERS command reply callback. */
1659 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1662 silc_buffer_free(res_cmd);
1663 silc_free(channel_id);
1664 silc_free(res_argv);
1665 silc_free(res_argv_lens);
1666 silc_free(res_argv_types);
1673 silc_buffer_push(&client_id_list, (client_id_list.data -
1674 client_id_list.head));
1675 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1676 client_mode_list.head));
1678 /* Notify application */
1680 COMMAND_REPLY((ARGS, channel, list_count, &client_id_list,
1681 &client_mode_list));
1684 silc_free(channel_id);
1688 /* Reply to USERS command. Received list of client ID's and theirs modes
1689 on the channel we requested. */
1691 SILC_CLIENT_CMD_REPLY_FUNC(users)
1693 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1694 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1696 SILC_LOG_DEBUG(("Start"));
1698 if (cmd->error != SILC_STATUS_OK) {
1699 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1700 "%s", silc_get_status_message(cmd->error));
1701 COMMAND_REPLY_ERROR;
1705 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
1706 silc_client_command_reply_users_cb,
1707 silc_client_command_reply_users))
1711 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1712 silc_client_command_reply_free(cmd);
1715 /* Received command reply to GETKEY command. WE've received the remote
1716 client's public key. */
1718 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1720 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1721 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1722 SilcIDPayload idp = NULL;
1723 SilcClientID *client_id = NULL;
1724 SilcClientEntry client_entry;
1725 SilcServerID *server_id = NULL;
1726 SilcServerEntry server_entry;
1728 unsigned char *tmp, *pk;
1732 SilcPublicKey public_key = NULL;
1734 SILC_LOG_DEBUG(("Start"));
1736 if (cmd->error != SILC_STATUS_OK) {
1737 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1738 "%s", silc_get_status_message(cmd->error));
1739 COMMAND_REPLY_ERROR;
1743 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1745 COMMAND_REPLY_ERROR;
1748 idp = silc_id_payload_parse(tmp, len);
1750 COMMAND_REPLY_ERROR;
1754 /* Get the public key payload */
1755 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1757 /* Decode the public key */
1758 SILC_GET16_MSB(pk_len, tmp);
1759 SILC_GET16_MSB(type, tmp + 2);
1762 if (type == SILC_SKE_PK_TYPE_SILC)
1763 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1767 id_type = silc_id_payload_get_type(idp);
1768 if (id_type == SILC_ID_CLIENT) {
1769 /* Received client's public key */
1770 client_id = silc_id_payload_get_id(idp);
1771 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1772 if (!client_entry) {
1773 COMMAND_REPLY_ERROR;
1777 /* Notify application */
1778 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1779 } else if (id_type == SILC_ID_SERVER) {
1780 /* Received server's public key */
1781 server_id = silc_id_payload_get_id(idp);
1782 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1783 if (!server_entry) {
1784 COMMAND_REPLY_ERROR;
1788 /* Notify application */
1789 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1793 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1795 silc_id_payload_free(idp);
1797 silc_pkcs_public_key_free(public_key);
1798 silc_free(client_id);
1799 silc_free(server_id);
1800 silc_client_command_reply_free(cmd);
1803 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1805 silc_client_command_reply_free(context);
1809 /******************************************************************************
1811 Internal command reply functions
1813 ******************************************************************************/
1815 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1817 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1818 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1820 COMMAND_CHECK_STATUS_I;
1822 /* Save WHOIS info */
1823 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1825 /* Pending callbacks are not executed if this was an list entry */
1826 if (cmd->status != SILC_STATUS_OK &&
1827 cmd->status != SILC_STATUS_LIST_END) {
1828 silc_client_command_reply_free(cmd);
1833 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1836 /* If we received notify for invalid ID we'll remove the ID if we
1838 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1839 SilcClientEntry client_entry;
1841 unsigned char *tmp =
1842 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1845 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1847 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1850 silc_client_del_client(cmd->client, conn, client_entry);
1851 silc_free(client_id);
1856 /* Unregister this command reply */
1857 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1858 NULL, silc_client_command_reply_whois_i,
1861 silc_client_command_reply_free(cmd);
1864 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1866 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1867 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1869 COMMAND_CHECK_STATUS_I;
1871 /* Save IDENTIFY info */
1872 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1874 /* Pending callbacks are not executed if this was an list entry */
1875 if (cmd->status != SILC_STATUS_OK &&
1876 cmd->status != SILC_STATUS_LIST_END) {
1877 silc_client_command_reply_free(cmd);
1882 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1885 /* If we received notify for invalid ID we'll remove the ID if we
1887 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1888 SilcClientEntry client_entry;
1890 unsigned char *tmp =
1891 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1894 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1896 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1899 silc_client_del_client(cmd->client, conn, client_entry);
1900 silc_free(client_id);
1905 /* Unregister this command reply */
1906 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1907 NULL, silc_client_command_reply_identify_i,
1910 silc_client_command_reply_free(cmd);
1913 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1915 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1916 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1918 SilcServerEntry server;
1919 SilcServerID *server_id = NULL;
1920 char *server_name, *server_info;
1923 COMMAND_CHECK_STATUS_I;
1926 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1930 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1934 /* Get server name */
1935 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1939 /* Get server info */
1940 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1944 /* See whether we have this server cached. If not create it. */
1945 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1947 SILC_LOG_DEBUG(("New server entry"));
1948 silc_client_add_server(cmd->client, conn, server_name, server_info,
1949 silc_id_dup(server_id, SILC_ID_SERVER));
1953 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1954 silc_free(server_id);
1956 silc_client_command_reply_free(cmd);
1959 static void silc_client_command_reply_users_i_cb(SilcClient client,
1960 SilcClientConnection conn,
1961 SilcChannelEntry *channels,
1962 SilcUInt32 channels_count,
1965 if (!channels_count) {
1966 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1967 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1969 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1970 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1971 "%s", silc_get_status_message(cmd->error));
1972 COMMAND_REPLY_ERROR;
1973 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1974 silc_client_command_reply_free(cmd);
1978 silc_client_command_reply_users_i(context, NULL);
1981 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
1983 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1985 COMMAND_CHECK_STATUS_I;
1987 /* Save USERS info */
1988 if (silc_client_command_reply_users_save(
1989 cmd, cmd->status, FALSE,
1990 silc_client_command_reply_users_i_cb,
1991 silc_client_command_reply_users_i))
1995 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1998 /* Unregister this command reply */
1999 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2000 NULL, silc_client_command_reply_users_i,
2003 silc_client_command_reply_free(cmd);
2006 /* Private range commands, specific to this implementation (and compatible
2007 with SILC Server >= 0.9). */
2009 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2011 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2012 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2014 if (cmd->error != SILC_STATUS_OK) {
2015 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2016 "%s", silc_get_status_message(cmd->error));
2017 COMMAND_REPLY_ERROR;
2021 /* Notify application */
2022 COMMAND_REPLY((ARGS));
2025 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2026 silc_client_command_reply_free(cmd);
2029 SILC_CLIENT_CMD_REPLY_FUNC(close)
2031 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2032 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2034 if (cmd->error != SILC_STATUS_OK) {
2035 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2036 "%s", silc_get_status_message(cmd->error));
2037 COMMAND_REPLY_ERROR;
2041 /* Notify application */
2042 COMMAND_REPLY((ARGS));
2045 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2046 silc_client_command_reply_free(cmd);
2049 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2051 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2052 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2054 if (cmd->error != SILC_STATUS_OK) {
2055 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2056 "%s", silc_get_status_message(cmd->error));
2057 COMMAND_REPLY_ERROR;
2061 /* Notify application */
2062 COMMAND_REPLY((ARGS));
2065 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2066 silc_client_command_reply_free(cmd);