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 or the
96 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
98 #define COMMAND_CHECK_STATUS \
100 SILC_LOG_DEBUG(("Start")); \
101 if (cmd->status != SILC_STATUS_OK) { \
102 COMMAND_REPLY_ERROR; \
107 #define COMMAND_CHECK_STATUS_LIST \
109 SILC_LOG_DEBUG(("Start")); \
110 if (cmd->status != SILC_STATUS_OK && \
111 cmd->status != SILC_STATUS_LIST_START && \
112 cmd->status != SILC_STATUS_LIST_ITEM && \
113 cmd->status != SILC_STATUS_LIST_END) { \
114 COMMAND_REPLY_ERROR; \
119 /* Process received command reply. */
121 void silc_client_command_reply_process(SilcClient client,
122 SilcSocketConnection sock,
123 SilcPacketContext *packet)
125 SilcBuffer buffer = packet->buffer;
126 SilcClientCommand cmd;
127 SilcClientCommandReplyContext ctx;
128 SilcCommandPayload payload;
130 SilcCommandCb reply = NULL;
132 /* Get command reply payload from packet */
133 payload = silc_command_payload_parse(buffer->data, buffer->len);
135 /* Silently ignore bad reply packet */
136 SILC_LOG_DEBUG(("Bad command reply packet"));
140 /* Allocate command reply context. This must be free'd by the
141 command reply routine receiving it. */
142 ctx = silc_calloc(1, sizeof(*ctx));
143 ctx->client = client;
145 ctx->payload = payload;
146 ctx->status = silc_command_get_status(ctx->payload);
147 ctx->args = silc_command_get_args(ctx->payload);
148 ctx->packet = packet;
149 ctx->ident = silc_command_get_ident(ctx->payload);
151 /* Check for pending commands and mark to be exeucted */
152 silc_client_command_pending_check(sock->user_data, ctx,
153 silc_command_get(ctx->payload),
156 /* Execute command reply */
158 command = silc_command_get(ctx->payload);
160 /* Try to find matching the command identifier */
161 silc_list_start(client->internal->commands);
162 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
163 if (cmd->cmd == command && !cmd->ident)
165 if (cmd->cmd == command && cmd->ident == ctx->ident) {
166 (*cmd->reply)((void *)ctx, NULL);
171 if (cmd == SILC_LIST_END) {
173 /* No specific identifier for command reply, call first one found */
180 /* Returns status message string */
182 char *silc_client_command_status_message(SilcCommandStatus status)
186 for (i = 0; silc_command_status_messages[i].message; i++) {
187 if (silc_command_status_messages[i].status == status)
191 if (silc_command_status_messages[i].message == NULL)
194 return silc_command_status_messages[i].message;
197 /* Free command reply context and its internals. */
199 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
202 silc_command_payload_free(cmd->payload);
208 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
209 SilcCommandStatus status,
212 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
213 SilcClientID *client_id;
214 SilcClientEntry client_entry = NULL;
217 unsigned char *id_data, *tmp;
218 char *nickname = NULL, *username = NULL;
219 char *realname = NULL;
220 SilcUInt32 idle = 0, mode = 0;
221 SilcBuffer channels = NULL;
222 unsigned char *fingerprint;
223 SilcUInt32 fingerprint_len;
225 argc = silc_argument_get_arg_num(cmd->args);
227 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
234 client_id = silc_id_payload_parse_id(id_data, len, NULL);
241 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
242 username = silc_argument_get_arg_type(cmd->args, 4, &len);
243 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
244 if (!nickname || !username || !realname) {
250 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
252 channels = silc_buffer_alloc(len);
253 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
254 silc_buffer_put(channels, tmp, len);
257 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
259 SILC_GET32_MSB(mode, tmp);
261 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
263 SILC_GET32_MSB(idle, tmp);
265 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
267 /* Check if we have this client cached already. */
268 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
270 SILC_LOG_DEBUG(("Adding new client entry"));
272 silc_client_add_client(cmd->client, conn, nickname, username, realname,
275 silc_client_update_client(cmd->client, conn, client_entry,
276 nickname, username, realname, mode);
277 silc_free(client_id);
280 if (fingerprint && !client_entry->fingerprint) {
281 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
282 client_entry->fingerprint_len = fingerprint_len;
285 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
286 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
288 /* Notify application */
289 if (!cmd->callback && notify)
290 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
291 channels, mode, idle, fingerprint));
294 silc_buffer_free(channels);
297 /* Received reply for WHOIS command. This maybe called several times
298 for one WHOIS command as server may reply with list of results. */
300 SILC_CLIENT_CMD_REPLY_FUNC(whois)
302 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
303 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
305 COMMAND_CHECK_STATUS_LIST;
307 /* Save WHOIS info */
308 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
310 /* Pending callbacks are not executed if this was an list entry */
311 if (cmd->status != SILC_STATUS_OK &&
312 cmd->status != SILC_STATUS_LIST_END) {
313 silc_client_command_reply_free(cmd);
318 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
320 /* If we received notify for invalid ID we'll remove the ID if we
322 if (cmd->status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
323 SilcClientEntry client_entry;
326 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
329 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
331 client_entry = silc_client_get_client_by_id(cmd->client, conn,
334 silc_client_del_client(cmd->client, conn, client_entry);
335 silc_free(client_id);
340 silc_client_command_reply_free(cmd);
343 /* Received reply for WHOWAS command. */
345 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
347 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
348 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
349 SilcClientID *client_id;
350 SilcClientEntry client_entry = NULL;
352 unsigned char *id_data;
353 char *nickname, *username;
354 char *realname = NULL;
356 COMMAND_CHECK_STATUS_LIST;
358 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
364 client_id = silc_id_payload_parse_id(id_data, len, NULL);
370 /* Get the client entry, if exists */
371 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
372 silc_free(client_id);
374 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
375 username = silc_argument_get_arg_type(cmd->args, 4, &len);
376 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
377 if (!nickname || !username) {
382 /* Notify application. We don't save any history information to any
383 cache. Just pass the data to the application for displaying on
385 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
387 /* Pending callbacks are not executed if this was an list entry */
388 if (cmd->status != SILC_STATUS_OK &&
389 cmd->status != SILC_STATUS_LIST_END) {
390 silc_client_command_reply_free(cmd);
395 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
396 silc_client_command_reply_free(cmd);
400 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
401 SilcCommandStatus status,
404 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
405 SilcClient client = cmd->client;
406 SilcClientID *client_id = NULL;
407 SilcServerID *server_id = NULL;
408 SilcChannelID *channel_id = NULL;
409 SilcClientEntry client_entry;
410 SilcServerEntry server_entry;
411 SilcChannelEntry channel_entry;
414 unsigned char *id_data;
415 char *name = NULL, *info = NULL;
416 SilcIDPayload idp = NULL;
419 argc = silc_argument_get_arg_num(cmd->args);
421 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
427 idp = silc_id_payload_parse(id_data, len);
434 name = silc_argument_get_arg_type(cmd->args, 3, &len);
435 info = silc_argument_get_arg_type(cmd->args, 4, &len);
437 id_type = silc_id_payload_get_type(idp);
441 client_id = silc_id_payload_get_id(idp);
443 SILC_LOG_DEBUG(("Received client information"));
445 /* Check if we have this client cached already. */
446 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
448 SILC_LOG_DEBUG(("Adding new client entry"));
450 silc_client_add_client(cmd->client, conn, name, info, NULL,
451 silc_id_dup(client_id, id_type), 0);
453 silc_client_update_client(cmd->client, conn, client_entry,
454 name, info, NULL, 0);
457 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
458 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
460 /* Notify application */
462 COMMAND_REPLY((ARGS, client_entry, name, info));
466 server_id = silc_id_payload_get_id(idp);
468 SILC_LOG_DEBUG(("Received server information"));
470 /* Check if we have this server cached already. */
471 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
473 SILC_LOG_DEBUG(("Adding new server entry"));
474 server_entry = silc_client_add_server(cmd->client, conn, name, info,
475 silc_id_dup(server_id, id_type));
483 /* Notify application */
485 COMMAND_REPLY((ARGS, server_entry, name, info));
488 case SILC_ID_CHANNEL:
489 channel_id = silc_id_payload_get_id(idp);
491 SILC_LOG_DEBUG(("Received channel information"));
493 /* Check if we have this channel cached already. */
494 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
495 if (!channel_entry) {
499 /* Add new channel entry */
500 channel_entry = silc_client_add_channel(client, conn, name, 0,
505 /* Notify application */
507 COMMAND_REPLY((ARGS, channel_entry, name, info));
511 silc_id_payload_free(idp);
512 silc_free(client_id);
513 silc_free(server_id);
514 silc_free(channel_id);
517 /* Received reply for IDENTIFY command. This maybe called several times
518 for one IDENTIFY command as server may reply with list of results.
519 This is totally silent and does not print anything on screen. */
521 SILC_CLIENT_CMD_REPLY_FUNC(identify)
523 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
524 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
526 COMMAND_CHECK_STATUS_LIST;
528 /* Save IDENTIFY info */
529 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
531 /* Pending callbacks are not executed if this was an list entry */
532 if (cmd->status != SILC_STATUS_OK &&
533 cmd->status != SILC_STATUS_LIST_END) {
534 silc_client_command_reply_free(cmd);
539 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
541 /* If we received notify for invalid ID we'll remove the ID if we
543 if (cmd->status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
544 SilcClientEntry client_entry;
547 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
550 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
552 client_entry = silc_client_get_client_by_id(cmd->client, conn,
555 silc_client_del_client(cmd->client, conn, client_entry);
556 silc_free(client_id);
561 silc_client_command_reply_free(cmd);
564 /* Received reply for command NICK. If everything went without errors
565 we just received our new Client ID. */
567 SILC_CLIENT_CMD_REPLY_FUNC(nick)
569 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
570 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
573 SilcUInt32 argc, len;
575 SILC_LOG_DEBUG(("Start"));
577 if (cmd->status != SILC_STATUS_OK) {
578 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
579 "Cannot set nickname: %s",
580 silc_client_command_status_message(cmd->status));
585 argc = silc_argument_get_arg_num(cmd->args);
586 if (argc < 2 || argc > 2) {
587 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
588 "Cannot set nickname: bad reply to command");
593 /* Take received Client ID */
594 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
595 idp = silc_id_payload_parse(tmp, len);
600 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
602 /* Notify application */
603 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
604 COMMAND_REPLY((ARGS, conn->local_entry));
605 silc_client_command_reply_free(cmd);
609 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
610 silc_client_command_reply_free(cmd);
613 /* Received reply to the LIST command. */
615 SILC_CLIENT_CMD_REPLY_FUNC(list)
617 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
618 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
619 unsigned char *tmp, *name, *topic;
620 SilcUInt32 usercount = 0, len;
621 SilcChannelID *channel_id = NULL;
622 SilcChannelEntry channel_entry;
624 COMMAND_CHECK_STATUS_LIST;
626 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
632 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
638 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
644 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
645 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
647 SILC_GET32_MSB(usercount, tmp);
649 /* Check whether the channel exists, and add it to cache if it doesn't. */
650 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
652 if (!channel_entry) {
653 /* Add new channel entry */
654 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
656 if (!channel_entry) {
663 /* Notify application */
664 COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount));
666 /* Pending callbacks are not executed if this was an list entry */
667 if (cmd->status != SILC_STATUS_OK &&
668 cmd->status != SILC_STATUS_LIST_END) {
669 silc_client_command_reply_free(cmd);
674 silc_free(channel_id);
675 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
676 silc_client_command_reply_free(cmd);
679 /* Received reply to topic command. */
681 SILC_CLIENT_CMD_REPLY_FUNC(topic)
683 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
684 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
685 SilcChannelEntry channel;
686 SilcChannelID *channel_id = NULL;
689 SilcUInt32 argc, len;
691 if (cmd->status != SILC_STATUS_OK) {
692 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
693 "%s", silc_client_command_status_message(cmd->status));
698 argc = silc_argument_get_arg_num(cmd->args);
699 if (argc < 1 || argc > 3) {
704 /* Take Channel ID */
705 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
710 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
714 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
718 /* Get the channel entry */
719 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
721 silc_free(channel_id);
726 /* Notify application */
727 COMMAND_REPLY((ARGS, channel, topic));
730 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
731 silc_client_command_reply_free(cmd);
734 /* Received reply to invite command. */
736 SILC_CLIENT_CMD_REPLY_FUNC(invite)
738 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
739 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
740 SilcChannelEntry channel;
741 SilcChannelID *channel_id;
745 if (cmd->status != SILC_STATUS_OK) {
746 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
747 "%s", silc_client_command_status_message(cmd->status));
752 /* Take Channel ID */
753 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
757 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
761 /* Get the channel entry */
762 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
764 silc_free(channel_id);
769 /* Get the invite list */
770 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
772 /* Notify application */
773 COMMAND_REPLY((ARGS, channel, tmp));
776 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
777 silc_client_command_reply_free(cmd);
780 /* Received reply to the KILL command. */
782 SILC_CLIENT_CMD_REPLY_FUNC(kill)
784 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
785 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
787 if (cmd->status != SILC_STATUS_OK) {
788 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
789 "%s", silc_client_command_status_message(cmd->status));
794 /* Notify application */
795 COMMAND_REPLY((ARGS));
798 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
799 silc_client_command_reply_free(cmd);
802 /* Received reply to INFO command. We receive the server ID and some
803 information about the server user requested. */
805 SILC_CLIENT_CMD_REPLY_FUNC(info)
807 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
808 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
810 SilcServerEntry server;
811 SilcServerID *server_id = NULL;
812 char *server_name, *server_info;
815 SILC_LOG_DEBUG(("Start"));
817 if (cmd->status != SILC_STATUS_OK) {
818 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
819 silc_client_command_status_message(cmd->status));
825 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
829 server_id = silc_id_payload_parse_id(tmp, len, NULL);
833 /* Get server name */
834 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
838 /* Get server info */
839 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
843 /* See whether we have this server cached. If not create it. */
844 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
846 SILC_LOG_DEBUG(("New server entry"));
847 server = silc_client_add_server(cmd->client, conn, server_name,
849 silc_id_dup(server_id, SILC_ID_SERVER));
854 /* Notify application */
855 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
858 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
859 silc_free(server_id);
860 silc_client_command_reply_free(cmd);
863 /* Received reply to PING command. The reply time is shown to user. */
865 SILC_CLIENT_CMD_REPLY_FUNC(ping)
867 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
868 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
871 time_t diff, curtime;
873 if (cmd->status != SILC_STATUS_OK) {
874 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
875 "%s", silc_client_command_status_message(cmd->status));
880 curtime = time(NULL);
881 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
882 cmd->packet->src_id_type);
883 if (!id || !conn->ping) {
888 for (i = 0; i < conn->ping_count; i++) {
889 if (!conn->ping[i].dest_id)
891 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
892 diff = curtime - conn->ping[i].start_time;
893 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
894 "Ping reply from %s: %d second%s",
895 conn->ping[i].dest_name, diff,
896 diff == 1 ? "" : "s");
898 conn->ping[i].start_time = 0;
899 silc_free(conn->ping[i].dest_id);
900 conn->ping[i].dest_id = NULL;
901 silc_free(conn->ping[i].dest_name);
902 conn->ping[i].dest_name = NULL;
909 /* Notify application */
910 COMMAND_REPLY((ARGS));
913 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
914 silc_client_command_reply_free(cmd);
917 /* Received reply for JOIN command. */
919 SILC_CLIENT_CMD_REPLY_FUNC(join)
921 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
922 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
923 SilcChannelEntry channel;
925 SilcChannelID *channel_id;
926 SilcUInt32 argc, mode = 0, len, list_count;
927 char *topic, *tmp, *channel_name = NULL, *hmac;
928 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
931 SILC_LOG_DEBUG(("Start"));
933 if (cmd->status != SILC_STATUS_OK) {
934 if (cmd->status != SILC_STATUS_ERR_USER_ON_CHANNEL)
935 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
936 "%s", silc_client_command_status_message(cmd->status));
941 argc = silc_argument_get_arg_num(cmd->args);
942 if (argc < 7 || argc > 14) {
943 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
944 "Cannot join channel: Bad reply packet");
949 /* Get channel name */
950 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
952 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
953 "Cannot join channel: Bad reply packet");
960 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
962 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
963 "Cannot join channel: Bad reply packet");
967 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
973 /* Get channel mode */
974 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
976 SILC_GET32_MSB(mode, tmp);
978 /* Get channel key */
979 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
981 keyp = silc_buffer_alloc(len);
982 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
983 silc_buffer_put(keyp, tmp, len);
987 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
989 /* Check whether we have this channel entry already. */
990 channel = silc_client_get_channel(cmd->client, conn, channel_name);
992 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
993 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
995 /* Create new channel entry */
996 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1000 conn->current_channel = channel;
1003 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1005 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1006 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1007 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1008 COMMAND_REPLY_ERROR;
1013 /* Get the list count */
1014 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1017 SILC_GET32_MSB(list_count, tmp);
1019 /* Get Client ID list */
1020 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1024 client_id_list = silc_buffer_alloc(len);
1025 silc_buffer_pull_tail(client_id_list, len);
1026 silc_buffer_put(client_id_list, tmp, len);
1028 /* Get client mode list */
1029 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1033 client_mode_list = silc_buffer_alloc(len);
1034 silc_buffer_pull_tail(client_mode_list, len);
1035 silc_buffer_put(client_mode_list, tmp, len);
1037 /* Add clients we received in the reply to the channel */
1038 for (i = 0; i < list_count; i++) {
1041 SilcClientID *client_id;
1042 SilcClientEntry client_entry;
1045 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1047 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1052 SILC_GET32_MSB(mode, client_mode_list->data);
1054 /* Check if we have this client cached already. */
1055 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1056 if (!client_entry) {
1057 /* No, we don't have it, add entry for it. */
1059 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1060 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1063 /* Join client to the channel */
1064 if (!silc_client_on_channel(channel, client_entry)) {
1065 chu = silc_calloc(1, sizeof(*chu));
1066 chu->client = client_entry;
1067 chu->channel = channel;
1069 silc_hash_table_add(channel->user_list, client_entry, chu);
1070 silc_hash_table_add(client_entry->channels, channel, chu);
1073 silc_free(client_id);
1074 silc_buffer_pull(client_id_list, idp_len);
1075 silc_buffer_pull(client_mode_list, 4);
1077 silc_buffer_push(client_id_list, client_id_list->data -
1078 client_id_list->head);
1079 silc_buffer_push(client_mode_list, client_mode_list->data -
1080 client_mode_list->head);
1082 /* Save channel key */
1083 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1084 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1086 /* Notify application */
1087 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1088 keyp ? keyp->head : NULL, NULL,
1089 NULL, topic, hmac, list_count, client_id_list,
1093 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1094 silc_client_command_reply_free(cmd);
1097 silc_buffer_free(keyp);
1099 silc_buffer_free(client_id_list);
1100 if (client_mode_list)
1101 silc_buffer_free(client_mode_list);
1104 /* Received reply for MOTD command */
1106 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1108 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1109 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1111 char *motd = NULL, *cp, line[256];
1113 if (cmd->status != SILC_STATUS_OK) {
1114 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1115 "%s", silc_client_command_status_message(cmd->status));
1116 COMMAND_REPLY_ERROR;
1120 argc = silc_argument_get_arg_num(cmd->args);
1122 COMMAND_REPLY_ERROR;
1127 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1129 COMMAND_REPLY_ERROR;
1136 if (cp[i++] == '\n') {
1137 memset(line, 0, sizeof(line));
1138 strncat(line, cp, i - 1);
1144 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1153 /* Notify application */
1154 COMMAND_REPLY((ARGS, motd));
1157 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1158 silc_client_command_reply_free(cmd);
1161 /* Received reply tot he UMODE command. Save the current user mode */
1163 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1165 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1166 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1170 if (cmd->status != SILC_STATUS_OK) {
1171 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1172 "%s", silc_client_command_status_message(cmd->status));
1173 COMMAND_REPLY_ERROR;
1177 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1179 COMMAND_REPLY_ERROR;
1183 SILC_GET32_MSB(mode, tmp);
1184 conn->local_entry->mode = mode;
1186 /* Notify application */
1187 COMMAND_REPLY((ARGS, mode));
1190 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1191 silc_client_command_reply_free(cmd);
1194 /* Received reply for CMODE command. */
1196 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1198 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1199 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1202 SilcChannelID *channel_id;
1203 SilcChannelEntry channel;
1206 if (cmd->status != SILC_STATUS_OK) {
1207 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1208 "%s", silc_client_command_status_message(cmd->status));
1209 COMMAND_REPLY_ERROR;
1213 /* Take Channel ID */
1214 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1217 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1221 /* Get the channel entry */
1222 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1224 silc_free(channel_id);
1225 COMMAND_REPLY_ERROR;
1229 /* Get channel mode */
1230 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1232 silc_free(channel_id);
1233 COMMAND_REPLY_ERROR;
1238 SILC_GET32_MSB(mode, tmp);
1239 channel->mode = mode;
1241 /* Notify application */
1242 COMMAND_REPLY((ARGS, channel, mode));
1244 silc_free(channel_id);
1247 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1248 silc_client_command_reply_free(cmd);
1251 /* Received reply for CUMODE command */
1253 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1255 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1256 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1257 SilcClientID *client_id;
1258 SilcChannelID *channel_id;
1259 SilcClientEntry client_entry;
1260 SilcChannelEntry channel;
1261 SilcChannelUser chu;
1262 unsigned char *modev, *tmp, *id;
1263 SilcUInt32 len, mode;
1265 if (cmd->status != SILC_STATUS_OK) {
1266 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1267 "%s", silc_client_command_status_message(cmd->status));
1268 COMMAND_REPLY_ERROR;
1272 /* Get channel mode */
1273 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1275 COMMAND_REPLY_ERROR;
1279 /* Take Channel ID */
1280 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1283 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1287 /* Get the channel entry */
1288 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1290 silc_free(channel_id);
1291 COMMAND_REPLY_ERROR;
1296 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1298 silc_free(channel_id);
1299 COMMAND_REPLY_ERROR;
1302 client_id = silc_id_payload_parse_id(id, len, NULL);
1304 silc_free(channel_id);
1305 COMMAND_REPLY_ERROR;
1309 /* Get client entry */
1310 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1311 if (!client_entry) {
1312 silc_free(channel_id);
1313 silc_free(client_id);
1314 COMMAND_REPLY_ERROR;
1319 SILC_GET32_MSB(mode, modev);
1320 chu = silc_client_on_channel(channel, client_entry);
1324 /* Notify application */
1325 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1326 silc_free(client_id);
1327 silc_free(channel_id);
1330 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1331 silc_client_command_reply_free(cmd);
1334 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1336 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1337 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1339 if (cmd->status != SILC_STATUS_OK) {
1340 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1341 "%s", silc_client_command_status_message(cmd->status));
1342 COMMAND_REPLY_ERROR;
1346 /* Notify application */
1347 COMMAND_REPLY((ARGS));
1350 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1351 silc_client_command_reply_free(cmd);
1354 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1356 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1357 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1359 if (cmd->status != SILC_STATUS_OK) {
1360 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1361 "%s", silc_client_command_status_message(cmd->status));
1362 COMMAND_REPLY_ERROR;
1366 /* Notify application */
1367 COMMAND_REPLY((ARGS));
1370 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1371 silc_client_command_reply_free(cmd);
1374 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1376 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1377 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1379 if (cmd->status != SILC_STATUS_OK) {
1380 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1381 "%s", silc_client_command_status_message(cmd->status));
1382 COMMAND_REPLY_ERROR;
1386 /* Notify application */
1387 COMMAND_REPLY((ARGS));
1390 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1391 silc_client_command_reply_free(cmd);
1394 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1396 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1397 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1398 SilcChannelEntry channel;
1399 SilcChannelID *channel_id;
1403 if (cmd->status != SILC_STATUS_OK) {
1404 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1405 "%s", silc_client_command_status_message(cmd->status));
1406 COMMAND_REPLY_ERROR;
1410 /* Take Channel ID */
1411 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1415 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1419 /* Get the channel entry */
1420 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1422 silc_free(channel_id);
1423 COMMAND_REPLY_ERROR;
1427 /* Get the ban list */
1428 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1430 /* Notify application */
1431 COMMAND_REPLY((ARGS, channel, tmp));
1434 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1435 silc_client_command_reply_free(cmd);
1438 /* Reply to LEAVE command. */
1440 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1442 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1443 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1444 SilcChannelID *channel_id;
1445 SilcChannelEntry channel = NULL;
1449 if (cmd->status != SILC_STATUS_OK) {
1450 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1451 "%s", silc_client_command_status_message(cmd->status));
1452 COMMAND_REPLY_ERROR;
1456 /* From protocol version 1.1 we get the channel ID of the left channel */
1457 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1459 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1463 /* Get the channel entry */
1464 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1466 silc_free(channel_id);
1467 COMMAND_REPLY_ERROR;
1471 silc_free(channel_id);
1474 /* Notify application */
1475 COMMAND_REPLY((ARGS, channel));
1478 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1479 silc_client_command_reply_free(cmd);
1482 /* Channel resolving callback for USERS command reply. */
1484 static void silc_client_command_reply_users_cb(SilcClient client,
1485 SilcClientConnection conn,
1486 SilcChannelEntry *channels,
1487 SilcUInt32 channels_count,
1490 if (!channels_count) {
1491 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1492 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1493 SilcCommandStatus status = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1495 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1496 "%s", silc_client_command_status_message(status));
1497 COMMAND_REPLY_ERROR;
1498 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1499 silc_client_command_reply_free(cmd);
1503 silc_client_command_reply_users(context, NULL);
1506 /* Reply to USERS command. Received list of client ID's and theirs modes
1507 on the channel we requested. */
1509 SILC_CLIENT_CMD_REPLY_FUNC(users)
1511 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1512 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1513 SilcChannelEntry channel;
1514 SilcClientEntry client_entry;
1515 SilcChannelUser chu;
1516 SilcChannelID *channel_id = NULL;
1517 SilcBuffer client_id_list = NULL;
1518 SilcBuffer client_mode_list = NULL;
1520 SilcUInt32 tmp_len, list_count;
1522 unsigned char **res_argv = NULL;
1523 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1525 SILC_LOG_DEBUG(("Start"));
1527 if (cmd->status != SILC_STATUS_OK) {
1528 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1529 "%s", silc_client_command_status_message(cmd->status));
1530 COMMAND_REPLY_ERROR;
1534 /* Get channel ID */
1535 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1537 COMMAND_REPLY_ERROR;
1540 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1542 COMMAND_REPLY_ERROR;
1546 /* Get the list count */
1547 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1549 COMMAND_REPLY_ERROR;
1552 SILC_GET32_MSB(list_count, tmp);
1554 /* Get Client ID list */
1555 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1557 COMMAND_REPLY_ERROR;
1561 client_id_list = silc_buffer_alloc(tmp_len);
1562 silc_buffer_pull_tail(client_id_list, tmp_len);
1563 silc_buffer_put(client_id_list, tmp, tmp_len);
1565 /* Get client mode list */
1566 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1568 COMMAND_REPLY_ERROR;
1572 client_mode_list = silc_buffer_alloc(tmp_len);
1573 silc_buffer_pull_tail(client_mode_list, tmp_len);
1574 silc_buffer_put(client_mode_list, tmp, tmp_len);
1576 /* Get channel entry */
1577 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1579 /* Resolve the channel from server */
1580 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1581 silc_client_command_reply_users_cb,
1583 silc_free(channel_id);
1585 silc_buffer_free(client_id_list);
1586 if (client_mode_list)
1587 silc_buffer_free(client_mode_list);
1591 /* Cache the received Client ID's and modes. */
1592 for (i = 0; i < list_count; i++) {
1595 SilcClientID *client_id;
1598 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1600 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1605 SILC_GET32_MSB(mode, client_mode_list->data);
1607 /* Check if we have this client cached already. */
1608 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1609 if (!client_entry || !client_entry->username || !client_entry->realname) {
1611 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1612 silc_buffer_pull(client_id_list, idp_len);
1613 silc_buffer_pull(client_mode_list, 4);
1616 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1619 /* No we don't have it (or it is incomplete in information), query
1620 it from the server. Assemble argument table that will be sent
1621 for the WHOIS command later. */
1622 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1624 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1626 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1628 res_argv[res_argc] = client_id_list->data;
1629 res_argv_lens[res_argc] = idp_len;
1630 res_argv_types[res_argc] = res_argc + 3;
1633 if (!silc_client_on_channel(channel, client_entry)) {
1634 chu = silc_calloc(1, sizeof(*chu));
1635 chu->client = client_entry;
1637 chu->channel = channel;
1638 silc_hash_table_add(channel->user_list, client_entry, chu);
1639 silc_hash_table_add(client_entry->channels, channel, chu);
1643 silc_free(client_id);
1644 silc_buffer_pull(client_id_list, idp_len);
1645 silc_buffer_pull(client_mode_list, 4);
1648 /* Query the client information from server if the list included clients
1649 that we don't know about. */
1653 /* Send the WHOIS command to server */
1654 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1655 silc_client_command_reply_whois_i, 0,
1657 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1658 res_argc, res_argv, res_argv_lens,
1659 res_argv_types, conn->cmd_ident);
1660 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1661 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1664 /* Register pending command callback. After we've received the WHOIS
1665 command reply we will reprocess this command reply by re-calling this
1666 USERS command reply callback. */
1667 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1668 silc_client_command_reply_users, cmd);
1670 silc_buffer_free(res_cmd);
1671 silc_free(channel_id);
1672 silc_free(res_argv);
1673 silc_free(res_argv_lens);
1674 silc_free(res_argv_types);
1676 silc_buffer_free(client_id_list);
1677 if (client_mode_list)
1678 silc_buffer_free(client_mode_list);
1682 silc_buffer_push(client_id_list, (client_id_list->data -
1683 client_id_list->head));
1684 silc_buffer_push(client_mode_list, (client_mode_list->data -
1685 client_mode_list->head));
1687 /* Notify application */
1688 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1691 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1692 silc_client_command_reply_free(cmd);
1693 silc_free(channel_id);
1695 silc_buffer_free(client_id_list);
1696 if (client_mode_list)
1697 silc_buffer_free(client_mode_list);
1700 /* Received command reply to GETKEY command. WE've received the remote
1701 client's public key. */
1703 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1705 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1706 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1707 SilcIDPayload idp = NULL;
1708 SilcClientID *client_id = NULL;
1709 SilcClientEntry client_entry;
1710 SilcServerID *server_id = NULL;
1711 SilcServerEntry server_entry;
1713 unsigned char *tmp, *pk;
1717 SilcPublicKey public_key = NULL;
1719 SILC_LOG_DEBUG(("Start"));
1721 if (cmd->status != SILC_STATUS_OK) {
1722 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1723 "%s", silc_client_command_status_message(cmd->status));
1724 COMMAND_REPLY_ERROR;
1728 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1730 COMMAND_REPLY_ERROR;
1733 idp = silc_id_payload_parse(tmp, len);
1735 COMMAND_REPLY_ERROR;
1739 /* Get the public key payload */
1740 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1742 /* Decode the public key */
1743 SILC_GET16_MSB(pk_len, tmp);
1744 SILC_GET16_MSB(type, tmp + 2);
1747 if (type == SILC_SKE_PK_TYPE_SILC)
1748 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1752 id_type = silc_id_payload_get_type(idp);
1753 if (id_type == SILC_ID_CLIENT) {
1754 /* Received client's public key */
1755 client_id = silc_id_payload_get_id(idp);
1756 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1757 if (!client_entry) {
1758 COMMAND_REPLY_ERROR;
1762 /* Notify application */
1763 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1764 } else if (id_type == SILC_ID_SERVER) {
1765 /* Received server's public key */
1766 server_id = silc_id_payload_get_id(idp);
1767 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1768 if (!server_entry) {
1769 COMMAND_REPLY_ERROR;
1773 /* Notify application */
1774 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1778 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1780 silc_id_payload_free(idp);
1782 silc_pkcs_public_key_free(public_key);
1783 silc_free(client_id);
1784 silc_free(server_id);
1785 silc_client_command_reply_free(cmd);
1788 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1790 silc_client_command_reply_free(context);
1794 /******************************************************************************
1796 Internal command reply functions
1798 ******************************************************************************/
1800 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1802 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1803 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1805 SILC_LOG_DEBUG(("Start"));
1807 if (cmd->status != SILC_STATUS_OK &&
1808 cmd->status != SILC_STATUS_LIST_START &&
1809 cmd->status != SILC_STATUS_LIST_ITEM &&
1810 cmd->status != SILC_STATUS_LIST_END)
1813 /* Save WHOIS info */
1814 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1816 /* Pending callbacks are not executed if this was an list entry */
1817 if (cmd->status != SILC_STATUS_OK &&
1818 cmd->status != SILC_STATUS_LIST_END) {
1819 silc_client_command_reply_free(cmd);
1824 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1826 /* If we received notify for invalid ID we'll remove the ID if we
1828 if (cmd->status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1829 SilcClientEntry client_entry;
1831 unsigned char *tmp =
1832 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1835 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1837 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1840 silc_client_del_client(cmd->client, conn, client_entry);
1841 silc_free(client_id);
1846 /* Unregister this command reply */
1847 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1848 NULL, silc_client_command_reply_whois_i,
1851 silc_client_command_reply_free(cmd);
1854 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1856 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1857 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1859 SILC_LOG_DEBUG(("Start"));
1861 if (cmd->status != SILC_STATUS_OK &&
1862 cmd->status != SILC_STATUS_LIST_START &&
1863 cmd->status != SILC_STATUS_LIST_ITEM &&
1864 cmd->status != SILC_STATUS_LIST_END)
1867 /* Save IDENTIFY info */
1868 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1870 /* Pending callbacks are not executed if this was an list entry */
1871 if (cmd->status != SILC_STATUS_OK &&
1872 cmd->status != SILC_STATUS_LIST_END) {
1873 silc_client_command_reply_free(cmd);
1878 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1880 /* If we received notify for invalid ID we'll remove the ID if we
1882 if (cmd->status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1883 SilcClientEntry client_entry;
1885 unsigned char *tmp =
1886 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1889 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1891 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1894 silc_client_del_client(cmd->client, conn, client_entry);
1895 silc_free(client_id);
1900 /* Unregister this command reply */
1901 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1902 NULL, silc_client_command_reply_identify_i,
1905 silc_client_command_reply_free(cmd);
1908 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1910 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1911 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1913 SilcServerEntry server;
1914 SilcServerID *server_id = NULL;
1915 char *server_name, *server_info;
1918 SILC_LOG_DEBUG(("Start"));
1920 if (cmd->status != SILC_STATUS_OK)
1924 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1928 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1932 /* Get server name */
1933 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1937 /* Get server info */
1938 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1942 /* See whether we have this server cached. If not create it. */
1943 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1945 SILC_LOG_DEBUG(("New server entry"));
1946 silc_client_add_server(cmd->client, conn, server_name, server_info,
1947 silc_id_dup(server_id, SILC_ID_SERVER));
1951 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1952 silc_free(server_id);
1953 silc_client_command_reply_free(cmd);
1957 /* Private range commands, specific to this implementation (and compatible
1958 with SILC Server). */
1960 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1962 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1963 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1965 if (cmd->status != SILC_STATUS_OK) {
1966 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1967 "%s", silc_client_command_status_message(cmd->status));
1968 COMMAND_REPLY_ERROR;
1972 /* Notify application */
1973 COMMAND_REPLY((ARGS));
1976 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
1977 silc_client_command_reply_free(cmd);
1980 SILC_CLIENT_CMD_REPLY_FUNC(close)
1982 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1983 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1985 if (cmd->status != SILC_STATUS_OK) {
1986 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1987 "%s", silc_client_command_status_message(cmd->status));
1988 COMMAND_REPLY_ERROR;
1992 /* Notify application */
1993 COMMAND_REPLY((ARGS));
1996 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
1997 silc_client_command_reply_free(cmd);
2000 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2002 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2003 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2005 if (cmd->status != SILC_STATUS_OK) {
2006 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2007 "%s", silc_client_command_status_message(cmd->status));
2008 COMMAND_REPLY_ERROR;
2012 /* Notify application */
2013 COMMAND_REPLY((ARGS));
2016 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2017 silc_client_command_reply_free(cmd);