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), 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), 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 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
102 if (status != SILC_STATUS_OK) { \
103 COMMAND_REPLY_ERROR; \
108 #define COMMAND_CHECK_STATUS_LIST \
110 SILC_LOG_DEBUG(("Start")); \
111 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
112 if (status != SILC_STATUS_OK && \
113 status != SILC_STATUS_LIST_START && \
114 status != SILC_STATUS_LIST_ITEM && \
115 status != SILC_STATUS_LIST_END) { \
116 COMMAND_REPLY_ERROR; \
121 /* Process received command reply. */
123 void silc_client_command_reply_process(SilcClient client,
124 SilcSocketConnection sock,
125 SilcPacketContext *packet)
127 SilcBuffer buffer = packet->buffer;
128 SilcClientCommand cmd;
129 SilcClientCommandReplyContext ctx;
130 SilcCommandPayload payload;
132 SilcCommandCb reply = NULL;
134 /* Get command reply payload from packet */
135 payload = silc_command_payload_parse(buffer->data, buffer->len);
137 /* Silently ignore bad reply packet */
138 SILC_LOG_DEBUG(("Bad command reply packet"));
142 /* Allocate command reply context. This must be free'd by the
143 command reply routine receiving it. */
144 ctx = silc_calloc(1, sizeof(*ctx));
145 ctx->client = client;
147 ctx->payload = payload;
148 ctx->args = silc_command_get_args(ctx->payload);
149 ctx->packet = packet;
150 ctx->ident = silc_command_get_ident(ctx->payload);
152 /* Check for pending commands and mark to be exeucted */
153 silc_client_command_pending_check(sock->user_data, ctx,
154 silc_command_get(ctx->payload),
157 /* Execute command reply */
159 command = silc_command_get(ctx->payload);
161 /* Try to find matching the command identifier */
162 silc_list_start(client->internal->commands);
163 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
164 if (cmd->cmd == command && !cmd->ident)
166 if (cmd->cmd == command && cmd->ident == ctx->ident) {
167 (*cmd->reply)((void *)ctx, NULL);
172 if (cmd == SILC_LIST_END) {
174 /* No specific identifier for command reply, call first one found */
181 /* Returns status message string */
183 char *silc_client_command_status_message(SilcCommandStatus status)
187 for (i = 0; silc_command_status_messages[i].message; i++) {
188 if (silc_command_status_messages[i].status == status)
192 if (silc_command_status_messages[i].message == NULL)
195 return silc_command_status_messages[i].message;
198 /* Free command reply context and its internals. */
200 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
203 silc_command_payload_free(cmd->payload);
209 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
210 SilcCommandStatus status,
213 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
214 SilcClientID *client_id;
215 SilcClientEntry client_entry = NULL;
218 unsigned char *id_data, *tmp;
219 char *nickname = NULL, *username = NULL;
220 char *realname = NULL;
221 SilcUInt32 idle = 0, mode = 0;
222 SilcBuffer channels = NULL;
223 unsigned char *fingerprint;
224 SilcUInt32 fingerprint_len;
226 argc = silc_argument_get_arg_num(cmd->args);
228 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
235 client_id = silc_id_payload_parse_id(id_data, len);
242 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
243 username = silc_argument_get_arg_type(cmd->args, 4, &len);
244 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
245 if (!nickname || !username || !realname) {
251 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
253 channels = silc_buffer_alloc(len);
254 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
255 silc_buffer_put(channels, tmp, len);
258 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
260 SILC_GET32_MSB(mode, tmp);
262 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
264 SILC_GET32_MSB(idle, tmp);
266 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
268 /* Check if we have this client cached already. */
269 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
271 SILC_LOG_DEBUG(("Adding new client entry"));
273 silc_client_add_client(cmd->client, conn, nickname, username, realname,
276 silc_client_update_client(cmd->client, conn, client_entry,
277 nickname, username, realname, mode);
278 silc_free(client_id);
281 if (fingerprint && !client_entry->fingerprint) {
282 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
283 client_entry->fingerprint_len = fingerprint_len;
286 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
287 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
289 /* Notify application */
290 if (!cmd->callback && notify)
291 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
292 channels, mode, idle, fingerprint));
295 silc_buffer_free(channels);
298 /* Received reply for WHOIS command. This maybe called several times
299 for one WHOIS command as server may reply with list of results. */
301 SILC_CLIENT_CMD_REPLY_FUNC(whois)
303 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
304 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
305 SilcCommandStatus status;
307 COMMAND_CHECK_STATUS_LIST;
309 /* Save WHOIS info */
310 silc_client_command_reply_whois_save(cmd, status, TRUE);
312 /* Pending callbacks are not executed if this was an list entry */
313 if (status != SILC_STATUS_OK &&
314 status != SILC_STATUS_LIST_END) {
315 silc_client_command_reply_free(cmd);
320 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
322 /* If we received notify for invalid ID we'll remove the ID if we
324 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
325 SilcClientEntry client_entry;
328 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
331 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
333 client_entry = silc_client_get_client_by_id(cmd->client, conn,
336 silc_client_del_client(cmd->client, conn, client_entry);
337 silc_free(client_id);
342 silc_client_command_reply_free(cmd);
345 /* Received reply for WHOWAS command. */
347 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
349 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
350 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
351 SilcCommandStatus status;
352 SilcClientID *client_id;
353 SilcClientEntry client_entry = NULL;
355 unsigned char *id_data;
356 char *nickname, *username;
357 char *realname = NULL;
359 COMMAND_CHECK_STATUS_LIST;
361 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
367 client_id = silc_id_payload_parse_id(id_data, len);
373 /* Get the client entry, if exists */
374 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
375 silc_free(client_id);
377 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
378 username = silc_argument_get_arg_type(cmd->args, 4, &len);
379 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
380 if (!nickname || !username) {
385 /* Notify application. We don't save any history information to any
386 cache. Just pass the data to the application for displaying on
388 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
390 /* Pending callbacks are not executed if this was an list entry */
391 if (status != SILC_STATUS_OK &&
392 status != SILC_STATUS_LIST_END) {
393 silc_client_command_reply_free(cmd);
398 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
399 silc_client_command_reply_free(cmd);
403 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
404 SilcCommandStatus status,
407 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
408 SilcClient client = cmd->client;
409 SilcClientID *client_id = NULL;
410 SilcServerID *server_id = NULL;
411 SilcChannelID *channel_id = NULL;
412 SilcIDCacheEntry id_cache = NULL;
413 SilcClientEntry client_entry;
414 SilcServerEntry server_entry;
415 SilcChannelEntry channel_entry;
418 unsigned char *id_data;
419 char *name = NULL, *info = NULL;
420 SilcIDPayload idp = NULL;
423 argc = silc_argument_get_arg_num(cmd->args);
425 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
431 idp = silc_id_payload_parse(id_data, len);
438 name = silc_argument_get_arg_type(cmd->args, 3, &len);
439 info = silc_argument_get_arg_type(cmd->args, 4, &len);
441 id_type = silc_id_payload_get_type(idp);
445 client_id = silc_id_payload_get_id(idp);
447 SILC_LOG_DEBUG(("Received client information"));
449 /* Check if we have this client cached already. */
450 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
452 SILC_LOG_DEBUG(("Adding new client entry"));
454 silc_client_add_client(cmd->client, conn, name, info, NULL,
455 silc_id_dup(client_id, id_type), 0);
457 silc_client_update_client(cmd->client, conn, client_entry,
458 name, info, NULL, 0);
461 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
462 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
464 /* Notify application */
466 COMMAND_REPLY((ARGS, client_entry, name, info));
470 server_id = silc_id_payload_get_id(idp);
472 SILC_LOG_DEBUG(("Received server information"));
474 /* Check if we have this server cached already. */
475 if (!silc_idcache_find_by_id_one(conn->server_cache,
476 (void *)server_id, &id_cache)) {
477 SILC_LOG_DEBUG(("Adding new server entry"));
479 server_entry = silc_calloc(1, sizeof(*server_entry));
480 server_entry->server_id = silc_id_dup(server_id, id_type);
482 server_entry->server_name = strdup(name);
484 server_entry->server_info = strdup(info);
486 /* Add server to cache */
487 silc_idcache_add(conn->server_cache, server_entry->server_name,
488 server_entry->server_id, (void *)server_entry,
491 server_entry = (SilcServerEntry)id_cache->context;
494 /* Notify application */
496 COMMAND_REPLY((ARGS, server_entry, name, info));
499 case SILC_ID_CHANNEL:
500 channel_id = silc_id_payload_get_id(idp);
502 SILC_LOG_DEBUG(("Received channel information"));
504 /* Check if we have this channel cached already. */
505 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
506 if (!channel_entry) {
510 /* Add new channel entry */
511 channel_entry = silc_client_add_channel(client, conn, name, 0,
516 /* Notify application */
518 COMMAND_REPLY((ARGS, channel_entry, name, info));
522 silc_id_payload_free(idp);
523 silc_free(client_id);
524 silc_free(server_id);
525 silc_free(channel_id);
528 /* Received reply for IDENTIFY command. This maybe called several times
529 for one IDENTIFY command as server may reply with list of results.
530 This is totally silent and does not print anything on screen. */
532 SILC_CLIENT_CMD_REPLY_FUNC(identify)
534 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
535 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
536 SilcCommandStatus status;
538 COMMAND_CHECK_STATUS_LIST;
540 /* Save IDENTIFY info */
541 silc_client_command_reply_identify_save(cmd, status, TRUE);
543 /* Pending callbacks are not executed if this was an list entry */
544 if (status != SILC_STATUS_OK &&
545 status != SILC_STATUS_LIST_END) {
546 silc_client_command_reply_free(cmd);
551 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
553 /* If we received notify for invalid ID we'll remove the ID if we
555 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
556 SilcClientEntry client_entry;
559 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
562 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
564 client_entry = silc_client_get_client_by_id(cmd->client, conn,
567 silc_client_del_client(cmd->client, conn, client_entry);
568 silc_free(client_id);
573 silc_client_command_reply_free(cmd);
576 /* Received reply for command NICK. If everything went without errors
577 we just received our new Client ID. */
579 SILC_CLIENT_CMD_REPLY_FUNC(nick)
581 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
582 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
583 SilcCommandStatus status;
586 SilcUInt32 argc, len;
588 SILC_LOG_DEBUG(("Start"));
590 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
591 if (status != SILC_STATUS_OK) {
592 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
593 "Cannot set nickname: %s", silc_client_command_status_message(status));
598 argc = silc_argument_get_arg_num(cmd->args);
599 if (argc < 2 || argc > 2) {
600 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
601 "Cannot set nickname: bad reply to command");
606 /* Take received Client ID */
607 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
608 idp = silc_id_payload_parse(tmp, len);
613 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
615 /* Notify application */
616 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
617 COMMAND_REPLY((ARGS, conn->local_entry));
618 silc_client_command_reply_free(cmd);
622 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
623 silc_client_command_reply_free(cmd);
626 /* Received reply to the LIST command. */
628 SILC_CLIENT_CMD_REPLY_FUNC(list)
630 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
631 SilcCommandStatus status;
632 unsigned char *tmp, *name, *topic;
633 SilcUInt32 usercount = 0;
635 COMMAND_CHECK_STATUS_LIST;
637 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
638 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
639 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
641 SILC_GET32_MSB(usercount, tmp);
643 /* Notify application */
644 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
646 /* Pending callbacks are not executed if this was an list entry */
647 if (status != SILC_STATUS_OK &&
648 status != SILC_STATUS_LIST_END) {
649 silc_client_command_reply_free(cmd);
654 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
655 silc_client_command_reply_free(cmd);
658 /* Received reply to topic command. */
660 SILC_CLIENT_CMD_REPLY_FUNC(topic)
662 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
663 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
664 SilcCommandStatus status;
665 SilcChannelEntry channel;
666 SilcChannelID *channel_id = NULL;
669 SilcUInt32 argc, len;
671 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
672 if (status != SILC_STATUS_OK) {
673 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
674 "%s", silc_client_command_status_message(status));
679 argc = silc_argument_get_arg_num(cmd->args);
680 if (argc < 1 || argc > 3) {
685 /* Take Channel ID */
686 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
691 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
695 channel_id = silc_id_payload_parse_id(tmp, len);
699 /* Get the channel entry */
700 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
702 silc_free(channel_id);
707 /* Notify application */
708 COMMAND_REPLY((ARGS, channel, topic));
711 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
712 silc_client_command_reply_free(cmd);
715 /* Received reply to invite command. */
717 SILC_CLIENT_CMD_REPLY_FUNC(invite)
719 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
720 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
721 SilcCommandStatus status;
722 SilcChannelEntry channel;
723 SilcChannelID *channel_id;
727 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
728 SILC_GET16_MSB(status, tmp);
729 if (status != SILC_STATUS_OK) {
730 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
731 "%s", silc_client_command_status_message(status));
736 /* Take Channel ID */
737 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
741 channel_id = silc_id_payload_parse_id(tmp, len);
745 /* Get the channel entry */
746 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
748 silc_free(channel_id);
753 /* Get the invite list */
754 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
756 /* Notify application */
757 COMMAND_REPLY((ARGS, channel, tmp));
760 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
761 silc_client_command_reply_free(cmd);
764 /* Received reply to the KILL command. */
766 SILC_CLIENT_CMD_REPLY_FUNC(kill)
768 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
769 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
770 SilcCommandStatus status;
772 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
773 if (status != SILC_STATUS_OK) {
774 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
775 "%s", silc_client_command_status_message(status));
780 /* Notify application */
781 COMMAND_REPLY((ARGS));
784 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
785 silc_client_command_reply_free(cmd);
788 /* Received reply to INFO command. We receive the server ID and some
789 information about the server user requested. */
791 SILC_CLIENT_CMD_REPLY_FUNC(info)
793 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
794 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
795 SilcCommandStatus status;
797 SilcIDCacheEntry id_cache;
798 SilcServerEntry server;
799 SilcServerID *server_id = NULL;
800 char *server_name, *server_info;
803 SILC_LOG_DEBUG(("Start"));
805 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
806 SILC_GET16_MSB(status, tmp);
807 if (status != SILC_STATUS_OK) {
808 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
809 silc_client_command_status_message(status));
815 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
819 server_id = silc_id_payload_parse_id(tmp, len);
823 /* Get server name */
824 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
828 /* Get server info */
829 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
833 /* See whether we have this server cached. If not create it. */
834 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
836 SILC_LOG_DEBUG(("New server entry"));
838 server = silc_calloc(1, sizeof(*server));
839 server->server_name = strdup(server_name);
840 server->server_info = strdup(server_info);
841 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
843 /* Add it to the cache */
844 silc_idcache_add(conn->server_cache, server->server_name,
845 server->server_id, (void *)server, 0, NULL);
847 server = (SilcServerEntry)id_cache->context;
850 /* Notify application */
851 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
854 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
855 silc_free(server_id);
856 silc_client_command_reply_free(cmd);
859 /* Received reply to PING command. The reply time is shown to user. */
861 SILC_CLIENT_CMD_REPLY_FUNC(ping)
863 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
864 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
865 SilcCommandStatus status;
868 time_t diff, curtime;
870 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
871 if (status != SILC_STATUS_OK) {
872 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
873 "%s", silc_client_command_status_message(status));
878 curtime = time(NULL);
879 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
880 cmd->packet->src_id_type);
881 if (!id || !conn->ping) {
886 for (i = 0; i < conn->ping_count; i++) {
887 if (!conn->ping[i].dest_id)
889 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
890 diff = curtime - conn->ping[i].start_time;
891 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
892 "Ping reply from %s: %d second%s",
893 conn->ping[i].dest_name, diff,
894 diff == 1 ? "" : "s");
896 conn->ping[i].start_time = 0;
897 silc_free(conn->ping[i].dest_id);
898 conn->ping[i].dest_id = NULL;
899 silc_free(conn->ping[i].dest_name);
900 conn->ping[i].dest_name = NULL;
907 /* Notify application */
908 COMMAND_REPLY((ARGS));
911 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
912 silc_client_command_reply_free(cmd);
915 /* Received reply for JOIN command. */
917 SILC_CLIENT_CMD_REPLY_FUNC(join)
919 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
920 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
921 SilcCommandStatus status;
922 SilcChannelEntry channel;
924 SilcChannelID *channel_id;
925 SilcUInt32 argc, mode = 0, len, list_count;
926 char *topic, *tmp, *channel_name = NULL, *hmac;
927 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
930 SILC_LOG_DEBUG(("Start"));
932 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
933 if (status != SILC_STATUS_OK) {
934 if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
935 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
936 "%s", silc_client_command_status_message(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);
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);
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 chu = silc_calloc(1, sizeof(*chu));
1065 chu->client = client_entry;
1066 chu->channel = channel;
1068 silc_hash_table_add(channel->user_list, client_entry, chu);
1069 silc_hash_table_add(client_entry->channels, channel, chu);
1071 silc_free(client_id);
1072 silc_buffer_pull(client_id_list, idp_len);
1073 silc_buffer_pull(client_mode_list, 4);
1075 silc_buffer_push(client_id_list, client_id_list->data -
1076 client_id_list->head);
1077 silc_buffer_push(client_mode_list, client_mode_list->data -
1078 client_mode_list->head);
1080 /* Save channel key */
1081 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1082 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1084 /* Notify application */
1085 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1086 keyp ? keyp->head : NULL, NULL,
1087 NULL, topic, hmac, list_count, client_id_list,
1091 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1092 silc_client_command_reply_free(cmd);
1095 silc_buffer_free(keyp);
1097 silc_buffer_free(client_id_list);
1098 if (client_mode_list)
1099 silc_buffer_free(client_mode_list);
1102 /* Received reply for MOTD command */
1104 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1106 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1107 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1108 SilcCommandStatus status;
1111 char *motd = NULL, *cp, line[256];
1113 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1114 SILC_GET16_MSB(status, tmp);
1115 if (status != SILC_STATUS_OK) {
1116 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1117 "%s", silc_client_command_status_message(status));
1118 COMMAND_REPLY_ERROR;
1122 argc = silc_argument_get_arg_num(cmd->args);
1124 COMMAND_REPLY_ERROR;
1129 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1131 COMMAND_REPLY_ERROR;
1138 if (cp[i++] == '\n') {
1139 memset(line, 0, sizeof(line));
1140 strncat(line, cp, i - 1);
1146 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1155 /* Notify application */
1156 COMMAND_REPLY((ARGS, motd));
1159 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1160 silc_client_command_reply_free(cmd);
1163 /* Received reply tot he UMODE command. Save the current user mode */
1165 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1167 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1168 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1169 SilcCommandStatus status;
1173 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1174 SILC_GET16_MSB(status, tmp);
1175 if (status != SILC_STATUS_OK) {
1176 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1177 "%s", silc_client_command_status_message(status));
1178 COMMAND_REPLY_ERROR;
1182 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1184 COMMAND_REPLY_ERROR;
1188 SILC_GET32_MSB(mode, tmp);
1189 conn->local_entry->mode = mode;
1191 /* Notify application */
1192 COMMAND_REPLY((ARGS, mode));
1195 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1196 silc_client_command_reply_free(cmd);
1199 /* Received reply for CMODE command. */
1201 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1203 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1204 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1205 SilcCommandStatus status;
1208 SilcChannelID *channel_id;
1209 SilcChannelEntry channel;
1212 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1213 if (status != SILC_STATUS_OK) {
1214 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1215 "%s", silc_client_command_status_message(status));
1216 COMMAND_REPLY_ERROR;
1220 /* Take Channel ID */
1221 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1224 channel_id = silc_id_payload_parse_id(tmp, len);
1228 /* Get the channel entry */
1229 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1231 silc_free(channel_id);
1232 COMMAND_REPLY_ERROR;
1236 /* Get channel mode */
1237 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1239 silc_free(channel_id);
1240 COMMAND_REPLY_ERROR;
1245 SILC_GET32_MSB(mode, tmp);
1246 channel->mode = mode;
1248 /* Notify application */
1249 COMMAND_REPLY((ARGS, channel, mode));
1251 silc_free(channel_id);
1254 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1255 silc_client_command_reply_free(cmd);
1258 /* Received reply for CUMODE command */
1260 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1262 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1263 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1264 SilcCommandStatus status;
1265 SilcClientID *client_id;
1266 SilcChannelID *channel_id;
1267 SilcClientEntry client_entry;
1268 SilcChannelEntry channel;
1269 SilcChannelUser chu;
1270 unsigned char *modev, *tmp, *id;
1271 SilcUInt32 len, mode;
1273 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1274 if (status != SILC_STATUS_OK) {
1275 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1276 "%s", silc_client_command_status_message(status));
1277 COMMAND_REPLY_ERROR;
1281 /* Get channel mode */
1282 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1284 COMMAND_REPLY_ERROR;
1288 /* Take Channel ID */
1289 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1292 channel_id = silc_id_payload_parse_id(tmp, len);
1296 /* Get the channel entry */
1297 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1299 silc_free(channel_id);
1300 COMMAND_REPLY_ERROR;
1305 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1307 silc_free(channel_id);
1308 COMMAND_REPLY_ERROR;
1311 client_id = silc_id_payload_parse_id(id, len);
1313 silc_free(channel_id);
1314 COMMAND_REPLY_ERROR;
1318 /* Get client entry */
1319 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1320 if (!client_entry) {
1321 silc_free(channel_id);
1322 silc_free(client_id);
1323 COMMAND_REPLY_ERROR;
1328 SILC_GET32_MSB(mode, modev);
1329 chu = silc_client_on_channel(channel, client_entry);
1333 /* Notify application */
1334 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1335 silc_free(client_id);
1336 silc_free(channel_id);
1339 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1340 silc_client_command_reply_free(cmd);
1343 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1345 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1346 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1347 SilcCommandStatus status;
1350 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1351 SILC_GET16_MSB(status, tmp);
1352 if (status != SILC_STATUS_OK) {
1353 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1354 "%s", silc_client_command_status_message(status));
1355 COMMAND_REPLY_ERROR;
1359 /* Notify application */
1360 COMMAND_REPLY((ARGS));
1363 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1364 silc_client_command_reply_free(cmd);
1367 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1369 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1370 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1371 SilcCommandStatus status;
1374 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1375 SILC_GET16_MSB(status, tmp);
1376 if (status != SILC_STATUS_OK) {
1377 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1378 "%s", silc_client_command_status_message(status));
1379 COMMAND_REPLY_ERROR;
1383 /* Notify application */
1384 COMMAND_REPLY((ARGS));
1387 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1388 silc_client_command_reply_free(cmd);
1391 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1393 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1394 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1395 SilcCommandStatus status;
1398 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1399 SILC_GET16_MSB(status, tmp);
1400 if (status != SILC_STATUS_OK) {
1401 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1402 "%s", silc_client_command_status_message(status));
1403 COMMAND_REPLY_ERROR;
1407 /* Notify application */
1408 COMMAND_REPLY((ARGS));
1411 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1412 silc_client_command_reply_free(cmd);
1415 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1417 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1418 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1419 SilcCommandStatus status;
1422 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1423 SILC_GET16_MSB(status, tmp);
1424 if (status != SILC_STATUS_OK) {
1425 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1426 "%s", silc_client_command_status_message(status));
1427 COMMAND_REPLY_ERROR;
1431 /* Notify application */
1432 COMMAND_REPLY((ARGS));
1435 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1436 silc_client_command_reply_free(cmd);
1439 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1441 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1442 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1443 SilcCommandStatus status;
1444 SilcChannelEntry channel;
1445 SilcChannelID *channel_id;
1449 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1450 SILC_GET16_MSB(status, tmp);
1451 if (status != SILC_STATUS_OK) {
1452 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1453 "%s", silc_client_command_status_message(status));
1454 COMMAND_REPLY_ERROR;
1458 /* Take Channel ID */
1459 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1463 channel_id = silc_id_payload_parse_id(tmp, len);
1467 /* Get the channel entry */
1468 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1470 silc_free(channel_id);
1471 COMMAND_REPLY_ERROR;
1475 /* Get the ban list */
1476 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1478 /* Notify application */
1479 COMMAND_REPLY((ARGS, channel, tmp));
1482 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1483 silc_client_command_reply_free(cmd);
1486 SILC_CLIENT_CMD_REPLY_FUNC(close)
1488 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1489 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1490 SilcCommandStatus status;
1493 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1494 SILC_GET16_MSB(status, tmp);
1495 if (status != SILC_STATUS_OK) {
1496 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1497 "%s", silc_client_command_status_message(status));
1498 COMMAND_REPLY_ERROR;
1502 /* Notify application */
1503 COMMAND_REPLY((ARGS));
1506 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1507 silc_client_command_reply_free(cmd);
1510 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1512 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1513 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1514 SilcCommandStatus status;
1517 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1518 SILC_GET16_MSB(status, tmp);
1519 if (status != SILC_STATUS_OK) {
1520 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1521 "%s", silc_client_command_status_message(status));
1522 COMMAND_REPLY_ERROR;
1526 /* Notify application */
1527 COMMAND_REPLY((ARGS));
1530 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1531 silc_client_command_reply_free(cmd);
1534 /* Reply to LEAVE command. */
1536 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1538 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1539 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1540 SilcCommandStatus status;
1543 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1544 SILC_GET16_MSB(status, tmp);
1545 if (status != SILC_STATUS_OK) {
1546 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1547 "%s", silc_client_command_status_message(status));
1548 COMMAND_REPLY_ERROR;
1552 /* Notify application */
1553 COMMAND_REPLY((ARGS));
1556 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1557 silc_client_command_reply_free(cmd);
1560 /* Channel resolving callback for USERS command reply. */
1562 static void silc_client_command_reply_users_cb(SilcClient client,
1563 SilcClientConnection conn,
1564 SilcChannelEntry *channels,
1565 SilcUInt32 channels_count,
1568 if (!channels_count) {
1569 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1570 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1571 SilcCommandStatus status = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1573 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1574 "%s", silc_client_command_status_message(status));
1575 COMMAND_REPLY_ERROR;
1576 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1577 silc_client_command_reply_free(cmd);
1581 silc_client_command_reply_users(context, NULL);
1584 /* Reply to USERS command. Received list of client ID's and theirs modes
1585 on the channel we requested. */
1587 SILC_CLIENT_CMD_REPLY_FUNC(users)
1589 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1590 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1591 SilcCommandStatus status;
1592 SilcChannelEntry channel;
1593 SilcClientEntry client_entry;
1594 SilcChannelUser chu;
1595 SilcChannelID *channel_id = NULL;
1596 SilcBuffer client_id_list = NULL;
1597 SilcBuffer client_mode_list = NULL;
1599 SilcUInt32 tmp_len, list_count;
1601 unsigned char **res_argv = NULL;
1602 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1604 SILC_LOG_DEBUG(("Start"));
1606 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1607 SILC_GET16_MSB(status, tmp);
1608 if (status != SILC_STATUS_OK) {
1609 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1610 "%s", silc_client_command_status_message(status));
1611 COMMAND_REPLY_ERROR;
1615 /* Get channel ID */
1616 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1618 COMMAND_REPLY_ERROR;
1621 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1623 COMMAND_REPLY_ERROR;
1627 /* Get the list count */
1628 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1630 COMMAND_REPLY_ERROR;
1633 SILC_GET32_MSB(list_count, tmp);
1635 /* Get Client ID list */
1636 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1638 COMMAND_REPLY_ERROR;
1642 client_id_list = silc_buffer_alloc(tmp_len);
1643 silc_buffer_pull_tail(client_id_list, tmp_len);
1644 silc_buffer_put(client_id_list, tmp, tmp_len);
1646 /* Get client mode list */
1647 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1649 COMMAND_REPLY_ERROR;
1653 client_mode_list = silc_buffer_alloc(tmp_len);
1654 silc_buffer_pull_tail(client_mode_list, tmp_len);
1655 silc_buffer_put(client_mode_list, tmp, tmp_len);
1657 /* Get channel entry */
1658 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1660 /* Resolve the channel from server */
1661 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1662 silc_client_command_reply_users_cb,
1664 silc_free(channel_id);
1666 silc_buffer_free(client_id_list);
1667 if (client_mode_list)
1668 silc_buffer_free(client_mode_list);
1672 /* Cache the received Client ID's and modes. */
1673 for (i = 0; i < list_count; i++) {
1676 SilcClientID *client_id;
1679 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1681 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1686 SILC_GET32_MSB(mode, client_mode_list->data);
1688 /* Check if we have this client cached already. */
1689 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1690 if (!client_entry || !client_entry->username || !client_entry->realname) {
1692 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1693 silc_buffer_pull(client_id_list, idp_len);
1694 silc_buffer_pull(client_mode_list, 4);
1697 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1700 /* No we don't have it (or it is incomplete in information), query
1701 it from the server. Assemble argument table that will be sent
1702 for the WHOIS command later. */
1703 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1705 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1707 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1709 res_argv[res_argc] = client_id_list->data;
1710 res_argv_lens[res_argc] = idp_len;
1711 res_argv_types[res_argc] = res_argc + 3;
1714 if (!silc_client_on_channel(channel, client_entry)) {
1715 chu = silc_calloc(1, sizeof(*chu));
1716 chu->client = client_entry;
1717 chu->channel = channel;
1718 silc_hash_table_add(channel->user_list, client_entry, chu);
1719 silc_hash_table_add(client_entry->channels, channel, chu);
1723 silc_free(client_id);
1724 silc_buffer_pull(client_id_list, idp_len);
1725 silc_buffer_pull(client_mode_list, 4);
1728 /* Query the client information from server if the list included clients
1729 that we don't know about. */
1733 /* Send the WHOIS command to server */
1734 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1735 silc_client_command_reply_whois_i, 0,
1737 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1738 res_argc, res_argv, res_argv_lens,
1739 res_argv_types, conn->cmd_ident);
1740 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1741 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1744 /* Register pending command callback. After we've received the WHOIS
1745 command reply we will reprocess this command reply by re-calling this
1746 USERS command reply callback. */
1747 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1748 silc_client_command_reply_users, cmd);
1750 silc_buffer_free(res_cmd);
1751 silc_free(channel_id);
1752 silc_free(res_argv);
1753 silc_free(res_argv_lens);
1754 silc_free(res_argv_types);
1756 silc_buffer_free(client_id_list);
1757 if (client_mode_list)
1758 silc_buffer_free(client_mode_list);
1762 silc_buffer_push(client_id_list, (client_id_list->data -
1763 client_id_list->head));
1764 silc_buffer_push(client_mode_list, (client_mode_list->data -
1765 client_mode_list->head));
1767 /* Notify application */
1768 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1771 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1772 silc_client_command_reply_free(cmd);
1773 silc_free(channel_id);
1775 silc_buffer_free(client_id_list);
1776 if (client_mode_list)
1777 silc_buffer_free(client_mode_list);
1780 /* Received command reply to GETKEY command. WE've received the remote
1781 client's public key. */
1783 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1785 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1786 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1787 SilcCommandStatus status;
1788 SilcIDCacheEntry id_cache;
1789 SilcIDPayload idp = NULL;
1790 SilcClientID *client_id = NULL;
1791 SilcClientEntry client_entry;
1792 SilcServerID *server_id = NULL;
1793 SilcServerEntry server_entry;
1795 unsigned char *tmp, *pk;
1799 SilcPublicKey public_key = NULL;
1801 SILC_LOG_DEBUG(("Start"));
1803 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1804 SILC_GET16_MSB(status, tmp);
1805 if (status != SILC_STATUS_OK) {
1806 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1807 "%s", silc_client_command_status_message(status));
1808 COMMAND_REPLY_ERROR;
1812 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1814 COMMAND_REPLY_ERROR;
1817 idp = silc_id_payload_parse(tmp, len);
1819 COMMAND_REPLY_ERROR;
1823 /* Get the public key payload */
1824 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1826 /* Decode the public key */
1827 SILC_GET16_MSB(pk_len, tmp);
1828 SILC_GET16_MSB(type, tmp + 2);
1831 if (type == SILC_SKE_PK_TYPE_SILC)
1832 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1836 id_type = silc_id_payload_get_type(idp);
1837 if (id_type == SILC_ID_CLIENT) {
1838 /* Received client's public key */
1839 client_id = silc_id_payload_get_id(idp);
1840 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1841 if (!client_entry) {
1842 COMMAND_REPLY_ERROR;
1846 /* Notify application */
1847 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1848 } else if (id_type == SILC_ID_SERVER) {
1849 /* Received server's public key */
1850 server_id = silc_id_payload_get_id(idp);
1851 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1853 COMMAND_REPLY_ERROR;
1857 server_entry = (SilcServerEntry)id_cache->context;
1859 /* Notify application */
1860 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1864 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1866 silc_id_payload_free(idp);
1868 silc_pkcs_public_key_free(public_key);
1869 silc_free(client_id);
1870 silc_free(server_id);
1871 silc_client_command_reply_free(cmd);
1874 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1876 silc_client_command_reply_free(context);
1880 /******************************************************************************
1882 Internal command reply functions
1884 ******************************************************************************/
1886 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1888 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1889 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1890 SilcCommandStatus status;
1892 SILC_LOG_DEBUG(("Start"));
1894 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1895 if (status != SILC_STATUS_OK &&
1896 status != SILC_STATUS_LIST_START &&
1897 status != SILC_STATUS_LIST_ITEM &&
1898 status != SILC_STATUS_LIST_END)
1901 /* Save WHOIS info */
1902 silc_client_command_reply_whois_save(cmd, status, FALSE);
1904 /* Pending callbacks are not executed if this was an list entry */
1905 if (status != SILC_STATUS_OK &&
1906 status != SILC_STATUS_LIST_END) {
1907 silc_client_command_reply_free(cmd);
1912 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1914 /* If we received notify for invalid ID we'll remove the ID if we
1916 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1917 SilcClientEntry client_entry;
1919 unsigned char *tmp =
1920 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1923 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1925 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1928 silc_client_del_client(cmd->client, conn, client_entry);
1929 silc_free(client_id);
1934 /* Unregister this command reply */
1935 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1936 NULL, silc_client_command_reply_whois_i,
1939 silc_client_command_reply_free(cmd);
1942 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1944 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1945 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1946 SilcCommandStatus status;
1948 SILC_LOG_DEBUG(("Start"));
1950 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1951 if (status != SILC_STATUS_OK &&
1952 status != SILC_STATUS_LIST_START &&
1953 status != SILC_STATUS_LIST_ITEM &&
1954 status != SILC_STATUS_LIST_END)
1957 /* Save IDENTIFY info */
1958 silc_client_command_reply_identify_save(cmd, status, FALSE);
1960 /* Pending callbacks are not executed if this was an list entry */
1961 if (status != SILC_STATUS_OK &&
1962 status != SILC_STATUS_LIST_END) {
1963 silc_client_command_reply_free(cmd);
1968 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1970 /* If we received notify for invalid ID we'll remove the ID if we
1972 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1973 SilcClientEntry client_entry;
1975 unsigned char *tmp =
1976 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1979 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1981 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1984 silc_client_del_client(cmd->client, conn, client_entry);
1985 silc_free(client_id);
1990 /* Unregister this command reply */
1991 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1992 NULL, silc_client_command_reply_identify_i,
1995 silc_client_command_reply_free(cmd);
1998 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2000 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2001 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2002 SilcCommandStatus status;
2004 SilcIDCacheEntry id_cache;
2005 SilcServerEntry server;
2006 SilcServerID *server_id = NULL;
2007 char *server_name, *server_info;
2010 SILC_LOG_DEBUG(("Start"));
2012 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
2013 SILC_GET16_MSB(status, tmp);
2014 if (status != SILC_STATUS_OK)
2018 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2022 server_id = silc_id_payload_parse_id(tmp, len);
2026 /* Get server name */
2027 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2031 /* Get server info */
2032 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2036 /* See whether we have this server cached. If not create it. */
2037 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
2039 SILC_LOG_DEBUG(("New server entry"));
2040 server = silc_calloc(1, sizeof(*server));
2041 server->server_name = strdup(server_name);
2042 server->server_info = strdup(server_info);
2043 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
2045 /* Add it to the cache */
2046 silc_idcache_add(conn->server_cache, server->server_name,
2047 server->server_id, (void *)server, 0, NULL);
2051 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2052 silc_free(server_id);
2053 silc_client_command_reply_free(cmd);