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 const SilcCommandStatusMessage silc_command_status_messages[] = {
41 { STAT(NO_SUCH_NICK), "There was no such nickname" },
42 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
43 { STAT(NO_SUCH_SERVER), "There was no such server" },
44 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
45 { STAT(NO_RECIPIENT), "No recipient given" },
46 { STAT(UNKNOWN_COMMAND), "Unknown command" },
47 { STAT(WILDCARDS), "Unknown command" },
48 { STAT(NO_CLIENT_ID), "No Client ID given" },
49 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
50 { STAT(NO_SERVER_ID), "No Server ID given" },
51 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
52 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
53 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
54 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
55 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
56 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
57 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
58 { STAT(USER_ON_CHANNEL), "User already on the channel" },
59 { STAT(NOT_REGISTERED), "You have not registered" },
60 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
61 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
62 { STAT(PERM_DENIED), "Permission denied" },
63 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
64 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
65 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
66 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
67 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
68 { STAT(UNKNOWN_MODE), "Unknown mode" },
69 { STAT(NOT_YOU), "Cannot change mode for other users" },
70 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
71 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
72 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
73 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
74 { STAT(BAD_NICKNAME), "Bad nickname" },
75 { STAT(BAD_CHANNEL), "Bad channel name" },
76 { STAT(AUTH_FAILED), "Authentication failed" },
77 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
78 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
82 /* Command reply operation that is called at the end of all command replys.
83 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
84 #define COMMAND_REPLY(args) cmd->client->internal->ops->command_reply args
85 #define ARGS cmd->client, cmd->sock->user_data, \
86 cmd->payload, TRUE, silc_command_get(cmd->payload), cmd->status
88 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
89 #define COMMAND_REPLY_ERROR cmd->client->internal->ops-> \
90 command_reply(cmd->client, cmd->sock->user_data, cmd->payload, \
91 FALSE, silc_command_get(cmd->payload), cmd->status)
93 #define SAY cmd->client->internal->ops->say
95 /* All functions that call the COMMAND_CHECK_STATUS macro must have
98 #define COMMAND_CHECK_STATUS \
100 SILC_LOG_DEBUG(("Start")); \
101 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
102 COMMAND_REPLY_ERROR; \
107 /* Process received command reply. */
109 void silc_client_command_reply_process(SilcClient client,
110 SilcSocketConnection sock,
111 SilcPacketContext *packet)
113 SilcBuffer buffer = packet->buffer;
114 SilcClientCommand cmd;
115 SilcClientCommandReplyContext ctx;
116 SilcCommandPayload payload;
118 SilcCommandCb reply = NULL;
120 /* Get command reply payload from packet */
121 payload = silc_command_payload_parse(buffer->data, buffer->len);
123 /* Silently ignore bad reply packet */
124 SILC_LOG_DEBUG(("Bad command reply packet"));
128 /* Allocate command reply context. This must be free'd by the
129 command reply routine receiving it. */
130 ctx = silc_calloc(1, sizeof(*ctx));
131 ctx->client = client;
133 ctx->payload = payload;
134 ctx->args = silc_command_get_args(ctx->payload);
135 ctx->packet = packet;
136 ctx->ident = silc_command_get_ident(ctx->payload);
137 silc_command_get_status(ctx->payload, &ctx->status, &ctx->error);
139 /* Check for pending commands and mark to be exeucted */
140 silc_client_command_pending_check(sock->user_data, ctx,
141 silc_command_get(ctx->payload),
144 /* Execute command reply */
146 command = silc_command_get(ctx->payload);
148 /* Try to find matching the command identifier */
149 silc_list_start(client->internal->commands);
150 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
151 if (cmd->cmd == command && !cmd->ident)
153 if (cmd->cmd == command && cmd->ident == ctx->ident) {
154 (*cmd->reply)((void *)ctx, NULL);
159 if (cmd == SILC_LIST_END) {
161 /* No specific identifier for command reply, call first one found */
168 /* Returns status message string */
170 char *silc_client_command_status_message(SilcCommandStatus status)
174 for (i = 0; silc_command_status_messages[i].message; i++) {
175 if (silc_command_status_messages[i].status == status)
179 if (silc_command_status_messages[i].message == NULL)
182 return silc_command_status_messages[i].message;
185 /* Free command reply context and its internals. */
187 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
190 silc_command_payload_free(cmd->payload);
196 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
197 SilcCommandStatus status,
200 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
201 SilcClientID *client_id;
202 SilcClientEntry client_entry = NULL;
205 unsigned char *id_data, *tmp;
206 char *nickname = NULL, *username = NULL;
207 char *realname = NULL;
208 SilcUInt32 idle = 0, mode = 0;
209 SilcBuffer channels = NULL;
210 unsigned char *fingerprint;
211 SilcUInt32 fingerprint_len;
213 argc = silc_argument_get_arg_num(cmd->args);
215 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
222 client_id = silc_id_payload_parse_id(id_data, len, NULL);
229 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
230 username = silc_argument_get_arg_type(cmd->args, 4, &len);
231 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
232 if (!nickname || !username || !realname) {
238 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
240 channels = silc_buffer_alloc(len);
241 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
242 silc_buffer_put(channels, tmp, len);
245 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
247 SILC_GET32_MSB(mode, tmp);
249 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
251 SILC_GET32_MSB(idle, tmp);
253 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
255 /* Check if we have this client cached already. */
256 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
258 SILC_LOG_DEBUG(("Adding new client entry"));
260 silc_client_add_client(cmd->client, conn, nickname, username, realname,
263 silc_client_update_client(cmd->client, conn, client_entry,
264 nickname, username, realname, mode);
265 silc_free(client_id);
268 if (fingerprint && !client_entry->fingerprint) {
269 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
270 client_entry->fingerprint_len = fingerprint_len;
273 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
274 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
276 /* Notify application */
277 if (!cmd->callback && notify)
278 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
279 channels, mode, idle, fingerprint));
282 silc_buffer_free(channels);
285 /* Received reply for WHOIS command. This maybe called several times
286 for one WHOIS command as server may reply with list of results. */
288 SILC_CLIENT_CMD_REPLY_FUNC(whois)
290 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
291 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
293 COMMAND_CHECK_STATUS;
295 /* Save WHOIS info */
296 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
298 /* Pending callbacks are not executed if this was an list entry */
299 if (cmd->status != SILC_STATUS_OK &&
300 cmd->status != SILC_STATUS_LIST_END) {
301 silc_client_command_reply_free(cmd);
306 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
308 /* If we received notify for invalid ID we'll remove the ID if we
310 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
311 SilcClientEntry client_entry;
314 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
317 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
319 client_entry = silc_client_get_client_by_id(cmd->client, conn,
322 silc_client_del_client(cmd->client, conn, client_entry);
323 silc_free(client_id);
328 silc_client_command_reply_free(cmd);
331 /* Received reply for WHOWAS command. */
333 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
335 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
336 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
337 SilcClientID *client_id;
338 SilcClientEntry client_entry = NULL;
340 unsigned char *id_data;
341 char *nickname, *username;
342 char *realname = NULL;
344 COMMAND_CHECK_STATUS;
346 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
352 client_id = silc_id_payload_parse_id(id_data, len, NULL);
358 /* Get the client entry, if exists */
359 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
360 silc_free(client_id);
362 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
363 username = silc_argument_get_arg_type(cmd->args, 4, &len);
364 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
365 if (!nickname || !username) {
370 /* Notify application. We don't save any history information to any
371 cache. Just pass the data to the application for displaying on
373 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
375 /* Pending callbacks are not executed if this was an list entry */
376 if (cmd->status != SILC_STATUS_OK &&
377 cmd->status != SILC_STATUS_LIST_END) {
378 silc_client_command_reply_free(cmd);
383 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
384 silc_client_command_reply_free(cmd);
388 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
389 SilcCommandStatus status,
392 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
393 SilcClient client = cmd->client;
394 SilcClientID *client_id = NULL;
395 SilcServerID *server_id = NULL;
396 SilcChannelID *channel_id = NULL;
397 SilcClientEntry client_entry;
398 SilcServerEntry server_entry;
399 SilcChannelEntry channel_entry;
402 unsigned char *id_data;
403 char *name = NULL, *info = NULL;
404 SilcIDPayload idp = NULL;
407 argc = silc_argument_get_arg_num(cmd->args);
409 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
415 idp = silc_id_payload_parse(id_data, len);
422 name = silc_argument_get_arg_type(cmd->args, 3, &len);
423 info = silc_argument_get_arg_type(cmd->args, 4, &len);
425 id_type = silc_id_payload_get_type(idp);
429 client_id = silc_id_payload_get_id(idp);
431 SILC_LOG_DEBUG(("Received client information"));
433 /* Check if we have this client cached already. */
434 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
436 SILC_LOG_DEBUG(("Adding new client entry"));
438 silc_client_add_client(cmd->client, conn, name, info, NULL,
439 silc_id_dup(client_id, id_type), 0);
441 silc_client_update_client(cmd->client, conn, client_entry,
442 name, info, NULL, 0);
445 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
446 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
448 /* Notify application */
450 COMMAND_REPLY((ARGS, client_entry, name, info));
454 server_id = silc_id_payload_get_id(idp);
456 SILC_LOG_DEBUG(("Received server information"));
458 /* Check if we have this server cached already. */
459 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
461 SILC_LOG_DEBUG(("Adding new server entry"));
462 server_entry = silc_client_add_server(cmd->client, conn, name, info,
463 silc_id_dup(server_id, id_type));
471 /* Notify application */
473 COMMAND_REPLY((ARGS, server_entry, name, info));
476 case SILC_ID_CHANNEL:
477 channel_id = silc_id_payload_get_id(idp);
479 SILC_LOG_DEBUG(("Received channel information"));
481 /* Check if we have this channel cached already. */
482 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
483 if (!channel_entry) {
487 /* Add new channel entry */
488 channel_entry = silc_client_add_channel(client, conn, name, 0,
493 /* Notify application */
495 COMMAND_REPLY((ARGS, channel_entry, name, info));
499 silc_id_payload_free(idp);
500 silc_free(client_id);
501 silc_free(server_id);
502 silc_free(channel_id);
505 /* Received reply for IDENTIFY command. This maybe called several times
506 for one IDENTIFY command as server may reply with list of results.
507 This is totally silent and does not print anything on screen. */
509 SILC_CLIENT_CMD_REPLY_FUNC(identify)
511 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
512 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
514 COMMAND_CHECK_STATUS;
516 /* Save IDENTIFY info */
517 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
519 /* Pending callbacks are not executed if this was an list entry */
520 if (cmd->status != SILC_STATUS_OK &&
521 cmd->status != SILC_STATUS_LIST_END) {
522 silc_client_command_reply_free(cmd);
527 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
529 /* If we received notify for invalid ID we'll remove the ID if we
531 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
532 SilcClientEntry client_entry;
535 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
538 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
540 client_entry = silc_client_get_client_by_id(cmd->client, conn,
543 silc_client_del_client(cmd->client, conn, client_entry);
544 silc_free(client_id);
549 silc_client_command_reply_free(cmd);
552 /* Received reply for command NICK. If everything went without errors
553 we just received our new Client ID. */
555 SILC_CLIENT_CMD_REPLY_FUNC(nick)
557 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
558 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
561 SilcUInt32 argc, len;
563 SILC_LOG_DEBUG(("Start"));
565 if (cmd->error != SILC_STATUS_OK) {
566 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
567 "Cannot set nickname: %s",
568 silc_client_command_status_message(cmd->error));
573 argc = silc_argument_get_arg_num(cmd->args);
574 if (argc < 2 || argc > 2) {
575 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
576 "Cannot set nickname: bad reply to command");
581 /* Take received Client ID */
582 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
583 idp = silc_id_payload_parse(tmp, len);
588 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
590 /* Notify application */
591 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
592 COMMAND_REPLY((ARGS, conn->local_entry));
593 silc_client_command_reply_free(cmd);
597 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
598 silc_client_command_reply_free(cmd);
601 /* Received reply to the LIST command. */
603 SILC_CLIENT_CMD_REPLY_FUNC(list)
605 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
606 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
607 unsigned char *tmp, *name, *topic;
608 SilcUInt32 usercount = 0, len;
609 SilcChannelID *channel_id = NULL;
610 SilcChannelEntry channel_entry;
612 COMMAND_CHECK_STATUS;
614 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
620 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
626 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
632 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
633 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
635 SILC_GET32_MSB(usercount, tmp);
637 /* Check whether the channel exists, and add it to cache if it doesn't. */
638 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
640 if (!channel_entry) {
641 /* Add new channel entry */
642 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
644 if (!channel_entry) {
651 /* Notify application */
652 COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount));
654 /* Pending callbacks are not executed if this was an list entry */
655 if (cmd->status != SILC_STATUS_OK &&
656 cmd->status != SILC_STATUS_LIST_END) {
657 silc_client_command_reply_free(cmd);
662 silc_free(channel_id);
663 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
664 silc_client_command_reply_free(cmd);
667 /* Received reply to topic command. */
669 SILC_CLIENT_CMD_REPLY_FUNC(topic)
671 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
672 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
673 SilcChannelEntry channel;
674 SilcChannelID *channel_id = NULL;
677 SilcUInt32 argc, len;
679 if (cmd->error != SILC_STATUS_OK) {
680 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
681 "%s", silc_client_command_status_message(cmd->error));
686 argc = silc_argument_get_arg_num(cmd->args);
687 if (argc < 1 || argc > 3) {
692 /* Take Channel ID */
693 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
698 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
702 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
706 /* Get the channel entry */
707 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
709 silc_free(channel_id);
714 /* Notify application */
715 COMMAND_REPLY((ARGS, channel, topic));
718 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
719 silc_client_command_reply_free(cmd);
722 /* Received reply to invite command. */
724 SILC_CLIENT_CMD_REPLY_FUNC(invite)
726 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
727 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
728 SilcChannelEntry channel;
729 SilcChannelID *channel_id;
733 if (cmd->error != SILC_STATUS_OK) {
734 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
735 "%s", silc_client_command_status_message(cmd->error));
740 /* Take Channel ID */
741 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
745 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
749 /* Get the channel entry */
750 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
752 silc_free(channel_id);
757 /* Get the invite list */
758 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
760 /* Notify application */
761 COMMAND_REPLY((ARGS, channel, tmp));
764 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
765 silc_client_command_reply_free(cmd);
768 /* Received reply to the KILL command. */
770 SILC_CLIENT_CMD_REPLY_FUNC(kill)
772 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
773 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
775 if (cmd->error != SILC_STATUS_OK) {
776 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
777 "%s", silc_client_command_status_message(cmd->error));
782 /* Notify application */
783 COMMAND_REPLY((ARGS));
786 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
787 silc_client_command_reply_free(cmd);
790 /* Received reply to INFO command. We receive the server ID and some
791 information about the server user requested. */
793 SILC_CLIENT_CMD_REPLY_FUNC(info)
795 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
796 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
798 SilcServerEntry server;
799 SilcServerID *server_id = NULL;
800 char *server_name, *server_info;
803 SILC_LOG_DEBUG(("Start"));
805 if (cmd->error != SILC_STATUS_OK) {
806 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
807 silc_client_command_status_message(cmd->error));
813 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
817 server_id = silc_id_payload_parse_id(tmp, len, NULL);
821 /* Get server name */
822 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
826 /* Get server info */
827 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
831 /* See whether we have this server cached. If not create it. */
832 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
834 SILC_LOG_DEBUG(("New server entry"));
835 server = silc_client_add_server(cmd->client, conn, server_name,
837 silc_id_dup(server_id, SILC_ID_SERVER));
842 /* Notify application */
843 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
846 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
847 silc_free(server_id);
848 silc_client_command_reply_free(cmd);
851 /* Received reply to PING command. The reply time is shown to user. */
853 SILC_CLIENT_CMD_REPLY_FUNC(ping)
855 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
856 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
859 time_t diff, curtime;
861 if (cmd->error != SILC_STATUS_OK) {
862 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
863 "%s", silc_client_command_status_message(cmd->error));
868 curtime = time(NULL);
869 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
870 cmd->packet->src_id_type);
871 if (!id || !conn->ping) {
876 for (i = 0; i < conn->ping_count; i++) {
877 if (!conn->ping[i].dest_id)
879 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
880 diff = curtime - conn->ping[i].start_time;
881 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
882 "Ping reply from %s: %d second%s",
883 conn->ping[i].dest_name, diff,
884 diff == 1 ? "" : "s");
886 conn->ping[i].start_time = 0;
887 silc_free(conn->ping[i].dest_id);
888 conn->ping[i].dest_id = NULL;
889 silc_free(conn->ping[i].dest_name);
890 conn->ping[i].dest_name = NULL;
897 /* Notify application */
898 COMMAND_REPLY((ARGS));
901 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
902 silc_client_command_reply_free(cmd);
905 /* Received reply for JOIN command. */
907 SILC_CLIENT_CMD_REPLY_FUNC(join)
909 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
910 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
911 SilcChannelEntry channel;
913 SilcChannelID *channel_id;
914 SilcUInt32 argc, mode = 0, len, list_count;
915 char *topic, *tmp, *channel_name = NULL, *hmac;
916 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
919 SILC_LOG_DEBUG(("Start"));
921 if (cmd->error != SILC_STATUS_OK) {
922 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
923 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
924 "%s", silc_client_command_status_message(cmd->error));
929 argc = silc_argument_get_arg_num(cmd->args);
930 if (argc < 7 || argc > 14) {
931 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
932 "Cannot join channel: Bad reply packet");
937 /* Get channel name */
938 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
940 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
941 "Cannot join channel: Bad reply packet");
948 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
950 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
951 "Cannot join channel: Bad reply packet");
955 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
961 /* Get channel mode */
962 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
964 SILC_GET32_MSB(mode, tmp);
966 /* Get channel key */
967 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
969 keyp = silc_buffer_alloc(len);
970 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
971 silc_buffer_put(keyp, tmp, len);
975 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
977 /* Check whether we have this channel entry already. */
978 channel = silc_client_get_channel(cmd->client, conn, channel_name);
980 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
981 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
983 /* Create new channel entry */
984 channel = silc_client_add_channel(cmd->client, conn, channel_name,
988 conn->current_channel = channel;
991 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
993 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
994 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
995 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1001 /* Get the list count */
1002 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1005 SILC_GET32_MSB(list_count, tmp);
1007 /* Get Client ID list */
1008 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1012 client_id_list = silc_buffer_alloc(len);
1013 silc_buffer_pull_tail(client_id_list, len);
1014 silc_buffer_put(client_id_list, tmp, len);
1016 /* Get client mode list */
1017 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1021 client_mode_list = silc_buffer_alloc(len);
1022 silc_buffer_pull_tail(client_mode_list, len);
1023 silc_buffer_put(client_mode_list, tmp, len);
1025 /* Add clients we received in the reply to the channel */
1026 for (i = 0; i < list_count; i++) {
1029 SilcClientID *client_id;
1030 SilcClientEntry client_entry;
1033 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1035 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1040 SILC_GET32_MSB(mode, client_mode_list->data);
1042 /* Check if we have this client cached already. */
1043 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1044 if (!client_entry) {
1045 /* No, we don't have it, add entry for it. */
1047 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1048 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1051 /* Join client to the channel */
1052 if (!silc_client_on_channel(channel, client_entry)) {
1053 chu = silc_calloc(1, sizeof(*chu));
1054 chu->client = client_entry;
1055 chu->channel = channel;
1057 silc_hash_table_add(channel->user_list, client_entry, chu);
1058 silc_hash_table_add(client_entry->channels, channel, chu);
1061 silc_free(client_id);
1062 silc_buffer_pull(client_id_list, idp_len);
1063 silc_buffer_pull(client_mode_list, 4);
1065 silc_buffer_push(client_id_list, client_id_list->data -
1066 client_id_list->head);
1067 silc_buffer_push(client_mode_list, client_mode_list->data -
1068 client_mode_list->head);
1070 /* Save channel key */
1071 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1072 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1074 /* Notify application */
1075 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1076 keyp ? keyp->head : NULL, NULL,
1077 NULL, topic, hmac, list_count, client_id_list,
1081 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1082 silc_client_command_reply_free(cmd);
1085 silc_buffer_free(keyp);
1087 silc_buffer_free(client_id_list);
1088 if (client_mode_list)
1089 silc_buffer_free(client_mode_list);
1092 /* Received reply for MOTD command */
1094 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1096 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1097 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1099 char *motd = NULL, *cp, line[256];
1101 if (cmd->error != SILC_STATUS_OK) {
1102 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1103 "%s", silc_client_command_status_message(cmd->error));
1104 COMMAND_REPLY_ERROR;
1108 argc = silc_argument_get_arg_num(cmd->args);
1110 COMMAND_REPLY_ERROR;
1115 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1117 COMMAND_REPLY_ERROR;
1124 if (cp[i++] == '\n') {
1125 memset(line, 0, sizeof(line));
1126 strncat(line, cp, i - 1);
1132 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1141 /* Notify application */
1142 COMMAND_REPLY((ARGS, motd));
1145 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1146 silc_client_command_reply_free(cmd);
1149 /* Received reply tot he UMODE command. Save the current user mode */
1151 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1153 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1154 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1158 if (cmd->error != SILC_STATUS_OK) {
1159 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1160 "%s", silc_client_command_status_message(cmd->error));
1161 COMMAND_REPLY_ERROR;
1165 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1167 COMMAND_REPLY_ERROR;
1171 SILC_GET32_MSB(mode, tmp);
1172 conn->local_entry->mode = mode;
1174 /* Notify application */
1175 COMMAND_REPLY((ARGS, mode));
1178 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1179 silc_client_command_reply_free(cmd);
1182 /* Received reply for CMODE command. */
1184 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1186 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1187 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1190 SilcChannelID *channel_id;
1191 SilcChannelEntry channel;
1194 if (cmd->error != SILC_STATUS_OK) {
1195 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1196 "%s", silc_client_command_status_message(cmd->error));
1197 COMMAND_REPLY_ERROR;
1201 /* Take Channel ID */
1202 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1205 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1209 /* Get the channel entry */
1210 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1212 silc_free(channel_id);
1213 COMMAND_REPLY_ERROR;
1217 /* Get channel mode */
1218 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1220 silc_free(channel_id);
1221 COMMAND_REPLY_ERROR;
1226 SILC_GET32_MSB(mode, tmp);
1227 channel->mode = mode;
1229 /* Notify application */
1230 COMMAND_REPLY((ARGS, channel, mode));
1232 silc_free(channel_id);
1235 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1236 silc_client_command_reply_free(cmd);
1239 /* Received reply for CUMODE command */
1241 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1243 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1244 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1245 SilcClientID *client_id;
1246 SilcChannelID *channel_id;
1247 SilcClientEntry client_entry;
1248 SilcChannelEntry channel;
1249 SilcChannelUser chu;
1250 unsigned char *modev, *tmp, *id;
1251 SilcUInt32 len, mode;
1253 if (cmd->error != SILC_STATUS_OK) {
1254 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1255 "%s", silc_client_command_status_message(cmd->error));
1256 COMMAND_REPLY_ERROR;
1260 /* Get channel mode */
1261 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1263 COMMAND_REPLY_ERROR;
1267 /* Take Channel ID */
1268 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1271 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1275 /* Get the channel entry */
1276 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1278 silc_free(channel_id);
1279 COMMAND_REPLY_ERROR;
1284 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1286 silc_free(channel_id);
1287 COMMAND_REPLY_ERROR;
1290 client_id = silc_id_payload_parse_id(id, len, NULL);
1292 silc_free(channel_id);
1293 COMMAND_REPLY_ERROR;
1297 /* Get client entry */
1298 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1299 if (!client_entry) {
1300 silc_free(channel_id);
1301 silc_free(client_id);
1302 COMMAND_REPLY_ERROR;
1307 SILC_GET32_MSB(mode, modev);
1308 chu = silc_client_on_channel(channel, client_entry);
1312 /* Notify application */
1313 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1314 silc_free(client_id);
1315 silc_free(channel_id);
1318 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1319 silc_client_command_reply_free(cmd);
1322 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1324 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1325 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1327 if (cmd->error != SILC_STATUS_OK) {
1328 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1329 "%s", silc_client_command_status_message(cmd->error));
1330 COMMAND_REPLY_ERROR;
1334 /* Notify application */
1335 COMMAND_REPLY((ARGS));
1338 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1339 silc_client_command_reply_free(cmd);
1342 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1344 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1345 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1347 if (cmd->error != SILC_STATUS_OK) {
1348 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1349 "%s", silc_client_command_status_message(cmd->error));
1350 COMMAND_REPLY_ERROR;
1354 /* Notify application */
1355 COMMAND_REPLY((ARGS));
1358 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1359 silc_client_command_reply_free(cmd);
1362 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1364 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1365 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1367 if (cmd->error != SILC_STATUS_OK) {
1368 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1369 "%s", silc_client_command_status_message(cmd->error));
1370 COMMAND_REPLY_ERROR;
1374 /* Notify application */
1375 COMMAND_REPLY((ARGS));
1378 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1379 silc_client_command_reply_free(cmd);
1382 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1384 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1385 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1386 SilcChannelEntry channel;
1387 SilcChannelID *channel_id;
1391 if (cmd->error != SILC_STATUS_OK) {
1392 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1393 "%s", silc_client_command_status_message(cmd->error));
1394 COMMAND_REPLY_ERROR;
1398 /* Take Channel ID */
1399 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1403 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1407 /* Get the channel entry */
1408 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1410 silc_free(channel_id);
1411 COMMAND_REPLY_ERROR;
1415 /* Get the ban list */
1416 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1418 /* Notify application */
1419 COMMAND_REPLY((ARGS, channel, tmp));
1422 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1423 silc_client_command_reply_free(cmd);
1426 /* Reply to LEAVE command. */
1428 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1430 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1431 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1432 SilcChannelID *channel_id;
1433 SilcChannelEntry channel = NULL;
1437 if (cmd->error != SILC_STATUS_OK) {
1438 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1439 "%s", silc_client_command_status_message(cmd->error));
1440 COMMAND_REPLY_ERROR;
1444 /* From protocol version 1.1 we get the channel ID of the left channel */
1445 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1447 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1451 /* Get the channel entry */
1452 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1454 silc_free(channel_id);
1455 COMMAND_REPLY_ERROR;
1459 silc_free(channel_id);
1462 /* Notify application */
1463 COMMAND_REPLY((ARGS, channel));
1466 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1467 silc_client_command_reply_free(cmd);
1470 /* Channel resolving callback for USERS command reply. */
1472 static void silc_client_command_reply_users_cb(SilcClient client,
1473 SilcClientConnection conn,
1474 SilcChannelEntry *channels,
1475 SilcUInt32 channels_count,
1478 if (!channels_count) {
1479 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1480 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1482 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1483 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1484 "%s", silc_client_command_status_message(cmd->error));
1485 COMMAND_REPLY_ERROR;
1486 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1487 silc_client_command_reply_free(cmd);
1491 silc_client_command_reply_users(context, NULL);
1494 /* Reply to USERS command. Received list of client ID's and theirs modes
1495 on the channel we requested. */
1497 SILC_CLIENT_CMD_REPLY_FUNC(users)
1499 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1500 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1501 SilcChannelEntry channel;
1502 SilcClientEntry client_entry;
1503 SilcChannelUser chu;
1504 SilcChannelID *channel_id = NULL;
1505 SilcBuffer client_id_list = NULL;
1506 SilcBuffer client_mode_list = NULL;
1508 SilcUInt32 tmp_len, list_count;
1510 unsigned char **res_argv = NULL;
1511 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1513 SILC_LOG_DEBUG(("Start"));
1515 if (cmd->error != SILC_STATUS_OK) {
1516 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1517 "%s", silc_client_command_status_message(cmd->error));
1518 COMMAND_REPLY_ERROR;
1522 /* Get channel ID */
1523 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1525 COMMAND_REPLY_ERROR;
1528 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1530 COMMAND_REPLY_ERROR;
1534 /* Get the list count */
1535 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1537 COMMAND_REPLY_ERROR;
1540 SILC_GET32_MSB(list_count, tmp);
1542 /* Get Client ID list */
1543 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1545 COMMAND_REPLY_ERROR;
1549 client_id_list = silc_buffer_alloc(tmp_len);
1550 silc_buffer_pull_tail(client_id_list, tmp_len);
1551 silc_buffer_put(client_id_list, tmp, tmp_len);
1553 /* Get client mode list */
1554 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1556 COMMAND_REPLY_ERROR;
1560 client_mode_list = silc_buffer_alloc(tmp_len);
1561 silc_buffer_pull_tail(client_mode_list, tmp_len);
1562 silc_buffer_put(client_mode_list, tmp, tmp_len);
1564 /* Get channel entry */
1565 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1567 /* Resolve the channel from server */
1568 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1569 silc_client_command_reply_users_cb,
1571 silc_free(channel_id);
1573 silc_buffer_free(client_id_list);
1574 if (client_mode_list)
1575 silc_buffer_free(client_mode_list);
1579 /* Cache the received Client ID's and modes. */
1580 for (i = 0; i < list_count; i++) {
1583 SilcClientID *client_id;
1586 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1588 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1593 SILC_GET32_MSB(mode, client_mode_list->data);
1595 /* Check if we have this client cached already. */
1596 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1597 if (!client_entry || !client_entry->username || !client_entry->realname) {
1599 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1600 silc_buffer_pull(client_id_list, idp_len);
1601 silc_buffer_pull(client_mode_list, 4);
1604 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1607 /* No we don't have it (or it is incomplete in information), query
1608 it from the server. Assemble argument table that will be sent
1609 for the WHOIS command later. */
1610 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1612 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1614 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1616 res_argv[res_argc] = client_id_list->data;
1617 res_argv_lens[res_argc] = idp_len;
1618 res_argv_types[res_argc] = res_argc + 3;
1621 if (!silc_client_on_channel(channel, client_entry)) {
1622 chu = silc_calloc(1, sizeof(*chu));
1623 chu->client = client_entry;
1625 chu->channel = channel;
1626 silc_hash_table_add(channel->user_list, client_entry, chu);
1627 silc_hash_table_add(client_entry->channels, channel, chu);
1631 silc_free(client_id);
1632 silc_buffer_pull(client_id_list, idp_len);
1633 silc_buffer_pull(client_mode_list, 4);
1636 /* Query the client information from server if the list included clients
1637 that we don't know about. */
1641 /* Send the WHOIS command to server */
1642 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1643 silc_client_command_reply_whois_i, 0,
1645 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1646 res_argc, res_argv, res_argv_lens,
1647 res_argv_types, conn->cmd_ident);
1648 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1649 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1652 /* Register pending command callback. After we've received the WHOIS
1653 command reply we will reprocess this command reply by re-calling this
1654 USERS command reply callback. */
1655 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1656 silc_client_command_reply_users, cmd);
1658 silc_buffer_free(res_cmd);
1659 silc_free(channel_id);
1660 silc_free(res_argv);
1661 silc_free(res_argv_lens);
1662 silc_free(res_argv_types);
1664 silc_buffer_free(client_id_list);
1665 if (client_mode_list)
1666 silc_buffer_free(client_mode_list);
1670 silc_buffer_push(client_id_list, (client_id_list->data -
1671 client_id_list->head));
1672 silc_buffer_push(client_mode_list, (client_mode_list->data -
1673 client_mode_list->head));
1675 /* Notify application */
1676 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1679 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1680 silc_client_command_reply_free(cmd);
1681 silc_free(channel_id);
1683 silc_buffer_free(client_id_list);
1684 if (client_mode_list)
1685 silc_buffer_free(client_mode_list);
1688 /* Received command reply to GETKEY command. WE've received the remote
1689 client's public key. */
1691 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1693 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1694 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1695 SilcIDPayload idp = NULL;
1696 SilcClientID *client_id = NULL;
1697 SilcClientEntry client_entry;
1698 SilcServerID *server_id = NULL;
1699 SilcServerEntry server_entry;
1701 unsigned char *tmp, *pk;
1705 SilcPublicKey public_key = NULL;
1707 SILC_LOG_DEBUG(("Start"));
1709 if (cmd->error != SILC_STATUS_OK) {
1710 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1711 "%s", silc_client_command_status_message(cmd->error));
1712 COMMAND_REPLY_ERROR;
1716 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1718 COMMAND_REPLY_ERROR;
1721 idp = silc_id_payload_parse(tmp, len);
1723 COMMAND_REPLY_ERROR;
1727 /* Get the public key payload */
1728 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1730 /* Decode the public key */
1731 SILC_GET16_MSB(pk_len, tmp);
1732 SILC_GET16_MSB(type, tmp + 2);
1735 if (type == SILC_SKE_PK_TYPE_SILC)
1736 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1740 id_type = silc_id_payload_get_type(idp);
1741 if (id_type == SILC_ID_CLIENT) {
1742 /* Received client's public key */
1743 client_id = silc_id_payload_get_id(idp);
1744 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1745 if (!client_entry) {
1746 COMMAND_REPLY_ERROR;
1750 /* Notify application */
1751 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1752 } else if (id_type == SILC_ID_SERVER) {
1753 /* Received server's public key */
1754 server_id = silc_id_payload_get_id(idp);
1755 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1756 if (!server_entry) {
1757 COMMAND_REPLY_ERROR;
1761 /* Notify application */
1762 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1766 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1768 silc_id_payload_free(idp);
1770 silc_pkcs_public_key_free(public_key);
1771 silc_free(client_id);
1772 silc_free(server_id);
1773 silc_client_command_reply_free(cmd);
1776 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1778 silc_client_command_reply_free(context);
1782 /******************************************************************************
1784 Internal command reply functions
1786 ******************************************************************************/
1788 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1790 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1791 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1793 SILC_LOG_DEBUG(("Start"));
1795 if (cmd->error != SILC_STATUS_OK)
1798 /* Save WHOIS info */
1799 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1801 /* Pending callbacks are not executed if this was an list entry */
1802 if (cmd->status != SILC_STATUS_OK &&
1803 cmd->status != SILC_STATUS_LIST_END) {
1804 silc_client_command_reply_free(cmd);
1809 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1811 /* If we received notify for invalid ID we'll remove the ID if we
1813 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1814 SilcClientEntry client_entry;
1816 unsigned char *tmp =
1817 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1820 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1822 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1825 silc_client_del_client(cmd->client, conn, client_entry);
1826 silc_free(client_id);
1831 /* Unregister this command reply */
1832 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1833 NULL, silc_client_command_reply_whois_i,
1836 silc_client_command_reply_free(cmd);
1839 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1841 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1842 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1844 SILC_LOG_DEBUG(("Start"));
1846 if (cmd->error != SILC_STATUS_OK)
1849 /* Save IDENTIFY info */
1850 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1852 /* Pending callbacks are not executed if this was an list entry */
1853 if (cmd->status != SILC_STATUS_OK &&
1854 cmd->status != SILC_STATUS_LIST_END) {
1855 silc_client_command_reply_free(cmd);
1860 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1862 /* If we received notify for invalid ID we'll remove the ID if we
1864 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1865 SilcClientEntry client_entry;
1867 unsigned char *tmp =
1868 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1871 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1873 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1876 silc_client_del_client(cmd->client, conn, client_entry);
1877 silc_free(client_id);
1882 /* Unregister this command reply */
1883 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1884 NULL, silc_client_command_reply_identify_i,
1887 silc_client_command_reply_free(cmd);
1890 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1892 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1893 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1895 SilcServerEntry server;
1896 SilcServerID *server_id = NULL;
1897 char *server_name, *server_info;
1900 SILC_LOG_DEBUG(("Start"));
1902 if (cmd->error != SILC_STATUS_OK)
1906 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1910 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1914 /* Get server name */
1915 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1919 /* Get server info */
1920 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1924 /* See whether we have this server cached. If not create it. */
1925 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1927 SILC_LOG_DEBUG(("New server entry"));
1928 silc_client_add_server(cmd->client, conn, server_name, server_info,
1929 silc_id_dup(server_id, SILC_ID_SERVER));
1933 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1934 silc_free(server_id);
1935 silc_client_command_reply_free(cmd);
1939 /* Private range commands, specific to this implementation (and compatible
1940 with SILC Server). */
1942 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1944 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1945 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1947 if (cmd->error != SILC_STATUS_OK) {
1948 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1949 "%s", silc_client_command_status_message(cmd->error));
1950 COMMAND_REPLY_ERROR;
1954 /* Notify application */
1955 COMMAND_REPLY((ARGS));
1958 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
1959 silc_client_command_reply_free(cmd);
1962 SILC_CLIENT_CMD_REPLY_FUNC(close)
1964 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1965 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1967 if (cmd->error != SILC_STATUS_OK) {
1968 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1969 "%s", silc_client_command_status_message(cmd->error));
1970 COMMAND_REPLY_ERROR;
1974 /* Notify application */
1975 COMMAND_REPLY((ARGS));
1978 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
1979 silc_client_command_reply_free(cmd);
1982 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1984 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1985 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1987 if (cmd->error != SILC_STATUS_OK) {
1988 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1989 "%s", silc_client_command_status_message(cmd->error));
1990 COMMAND_REPLY_ERROR;
1994 /* Notify application */
1995 COMMAND_REPLY((ARGS));
1998 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
1999 silc_client_command_reply_free(cmd);