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 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;
1110 SilcCommandStatus status;
1113 char *motd = NULL, *cp, line[256];
1115 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1116 SILC_GET16_MSB(status, tmp);
1117 if (status != SILC_STATUS_OK) {
1118 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1119 "%s", silc_client_command_status_message(status));
1120 COMMAND_REPLY_ERROR;
1124 argc = silc_argument_get_arg_num(cmd->args);
1126 COMMAND_REPLY_ERROR;
1131 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1133 COMMAND_REPLY_ERROR;
1140 if (cp[i++] == '\n') {
1141 memset(line, 0, sizeof(line));
1142 strncat(line, cp, i - 1);
1148 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1157 /* Notify application */
1158 COMMAND_REPLY((ARGS, motd));
1161 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1162 silc_client_command_reply_free(cmd);
1165 /* Received reply tot he UMODE command. Save the current user mode */
1167 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1169 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1170 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1171 SilcCommandStatus status;
1175 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1176 SILC_GET16_MSB(status, tmp);
1177 if (status != SILC_STATUS_OK) {
1178 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1179 "%s", silc_client_command_status_message(status));
1180 COMMAND_REPLY_ERROR;
1184 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1186 COMMAND_REPLY_ERROR;
1190 SILC_GET32_MSB(mode, tmp);
1191 conn->local_entry->mode = mode;
1193 /* Notify application */
1194 COMMAND_REPLY((ARGS, mode));
1197 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1198 silc_client_command_reply_free(cmd);
1201 /* Received reply for CMODE command. */
1203 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1205 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1206 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1207 SilcCommandStatus status;
1210 SilcChannelID *channel_id;
1211 SilcChannelEntry channel;
1214 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1215 if (status != SILC_STATUS_OK) {
1216 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1217 "%s", silc_client_command_status_message(status));
1218 COMMAND_REPLY_ERROR;
1222 /* Take Channel ID */
1223 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1226 channel_id = silc_id_payload_parse_id(tmp, len);
1230 /* Get the channel entry */
1231 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1233 silc_free(channel_id);
1234 COMMAND_REPLY_ERROR;
1238 /* Get channel mode */
1239 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1241 silc_free(channel_id);
1242 COMMAND_REPLY_ERROR;
1247 SILC_GET32_MSB(mode, tmp);
1248 channel->mode = mode;
1250 /* Notify application */
1251 COMMAND_REPLY((ARGS, channel, mode));
1253 silc_free(channel_id);
1256 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1257 silc_client_command_reply_free(cmd);
1260 /* Received reply for CUMODE command */
1262 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1264 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1265 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1266 SilcCommandStatus status;
1267 SilcClientID *client_id;
1268 SilcChannelID *channel_id;
1269 SilcClientEntry client_entry;
1270 SilcChannelEntry channel;
1271 SilcChannelUser chu;
1272 unsigned char *modev, *tmp, *id;
1273 SilcUInt32 len, mode;
1275 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1276 if (status != SILC_STATUS_OK) {
1277 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1278 "%s", silc_client_command_status_message(status));
1279 COMMAND_REPLY_ERROR;
1283 /* Get channel mode */
1284 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1286 COMMAND_REPLY_ERROR;
1290 /* Take Channel ID */
1291 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1294 channel_id = silc_id_payload_parse_id(tmp, len);
1298 /* Get the channel entry */
1299 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1301 silc_free(channel_id);
1302 COMMAND_REPLY_ERROR;
1307 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1309 silc_free(channel_id);
1310 COMMAND_REPLY_ERROR;
1313 client_id = silc_id_payload_parse_id(id, len);
1315 silc_free(channel_id);
1316 COMMAND_REPLY_ERROR;
1320 /* Get client entry */
1321 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1322 if (!client_entry) {
1323 silc_free(channel_id);
1324 silc_free(client_id);
1325 COMMAND_REPLY_ERROR;
1330 SILC_GET32_MSB(mode, modev);
1331 chu = silc_client_on_channel(channel, client_entry);
1335 /* Notify application */
1336 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1337 silc_free(client_id);
1338 silc_free(channel_id);
1341 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1342 silc_client_command_reply_free(cmd);
1345 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1347 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1348 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1349 SilcCommandStatus status;
1352 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1353 SILC_GET16_MSB(status, tmp);
1354 if (status != SILC_STATUS_OK) {
1355 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1356 "%s", silc_client_command_status_message(status));
1357 COMMAND_REPLY_ERROR;
1361 /* Notify application */
1362 COMMAND_REPLY((ARGS));
1365 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1366 silc_client_command_reply_free(cmd);
1369 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1371 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1372 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1373 SilcCommandStatus status;
1376 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1377 SILC_GET16_MSB(status, tmp);
1378 if (status != SILC_STATUS_OK) {
1379 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1380 "%s", silc_client_command_status_message(status));
1381 COMMAND_REPLY_ERROR;
1385 /* Notify application */
1386 COMMAND_REPLY((ARGS));
1389 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1390 silc_client_command_reply_free(cmd);
1393 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1395 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1396 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1397 SilcCommandStatus status;
1400 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1401 SILC_GET16_MSB(status, tmp);
1402 if (status != SILC_STATUS_OK) {
1403 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1404 "%s", silc_client_command_status_message(status));
1405 COMMAND_REPLY_ERROR;
1409 /* Notify application */
1410 COMMAND_REPLY((ARGS));
1413 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1414 silc_client_command_reply_free(cmd);
1417 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1419 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1420 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1421 SilcCommandStatus status;
1424 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1425 SILC_GET16_MSB(status, tmp);
1426 if (status != SILC_STATUS_OK) {
1427 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1428 "%s", silc_client_command_status_message(status));
1429 COMMAND_REPLY_ERROR;
1433 /* Notify application */
1434 COMMAND_REPLY((ARGS));
1437 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1438 silc_client_command_reply_free(cmd);
1441 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1443 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1444 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1445 SilcCommandStatus status;
1446 SilcChannelEntry channel;
1447 SilcChannelID *channel_id;
1451 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1452 SILC_GET16_MSB(status, tmp);
1453 if (status != SILC_STATUS_OK) {
1454 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1455 "%s", silc_client_command_status_message(status));
1456 COMMAND_REPLY_ERROR;
1460 /* Take Channel ID */
1461 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1465 channel_id = silc_id_payload_parse_id(tmp, len);
1469 /* Get the channel entry */
1470 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1472 silc_free(channel_id);
1473 COMMAND_REPLY_ERROR;
1477 /* Get the ban list */
1478 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1480 /* Notify application */
1481 COMMAND_REPLY((ARGS, channel, tmp));
1484 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1485 silc_client_command_reply_free(cmd);
1488 SILC_CLIENT_CMD_REPLY_FUNC(close)
1490 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1491 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1492 SilcCommandStatus status;
1495 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1496 SILC_GET16_MSB(status, tmp);
1497 if (status != SILC_STATUS_OK) {
1498 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1499 "%s", silc_client_command_status_message(status));
1500 COMMAND_REPLY_ERROR;
1504 /* Notify application */
1505 COMMAND_REPLY((ARGS));
1508 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1509 silc_client_command_reply_free(cmd);
1512 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1514 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1515 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1516 SilcCommandStatus status;
1519 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1520 SILC_GET16_MSB(status, tmp);
1521 if (status != SILC_STATUS_OK) {
1522 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1523 "%s", silc_client_command_status_message(status));
1524 COMMAND_REPLY_ERROR;
1528 /* Notify application */
1529 COMMAND_REPLY((ARGS));
1532 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1533 silc_client_command_reply_free(cmd);
1536 /* Reply to LEAVE command. */
1538 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1540 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1541 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1542 SilcCommandStatus status;
1545 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1546 SILC_GET16_MSB(status, tmp);
1547 if (status != SILC_STATUS_OK) {
1548 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1549 "%s", silc_client_command_status_message(status));
1550 COMMAND_REPLY_ERROR;
1554 /* Notify application */
1555 COMMAND_REPLY((ARGS));
1558 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1559 silc_client_command_reply_free(cmd);
1562 /* Channel resolving callback for USERS command reply. */
1564 static void silc_client_command_reply_users_cb(SilcClient client,
1565 SilcClientConnection conn,
1566 SilcChannelEntry *channels,
1567 SilcUInt32 channels_count,
1570 if (!channels_count) {
1571 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1572 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1573 SilcCommandStatus status = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1575 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1576 "%s", silc_client_command_status_message(status));
1577 COMMAND_REPLY_ERROR;
1578 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1579 silc_client_command_reply_free(cmd);
1583 silc_client_command_reply_users(context, NULL);
1586 /* Reply to USERS command. Received list of client ID's and theirs modes
1587 on the channel we requested. */
1589 SILC_CLIENT_CMD_REPLY_FUNC(users)
1591 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1592 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1593 SilcCommandStatus status;
1594 SilcChannelEntry channel;
1595 SilcClientEntry client_entry;
1596 SilcChannelUser chu;
1597 SilcChannelID *channel_id = NULL;
1598 SilcBuffer client_id_list = NULL;
1599 SilcBuffer client_mode_list = NULL;
1601 SilcUInt32 tmp_len, list_count;
1603 unsigned char **res_argv = NULL;
1604 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1606 SILC_LOG_DEBUG(("Start"));
1608 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1609 SILC_GET16_MSB(status, tmp);
1610 if (status != SILC_STATUS_OK) {
1611 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1612 "%s", silc_client_command_status_message(status));
1613 COMMAND_REPLY_ERROR;
1617 /* Get channel ID */
1618 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1620 COMMAND_REPLY_ERROR;
1623 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1625 COMMAND_REPLY_ERROR;
1629 /* Get the list count */
1630 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1632 COMMAND_REPLY_ERROR;
1635 SILC_GET32_MSB(list_count, tmp);
1637 /* Get Client ID list */
1638 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1640 COMMAND_REPLY_ERROR;
1644 client_id_list = silc_buffer_alloc(tmp_len);
1645 silc_buffer_pull_tail(client_id_list, tmp_len);
1646 silc_buffer_put(client_id_list, tmp, tmp_len);
1648 /* Get client mode list */
1649 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1651 COMMAND_REPLY_ERROR;
1655 client_mode_list = silc_buffer_alloc(tmp_len);
1656 silc_buffer_pull_tail(client_mode_list, tmp_len);
1657 silc_buffer_put(client_mode_list, tmp, tmp_len);
1659 /* Get channel entry */
1660 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1662 /* Resolve the channel from server */
1663 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1664 silc_client_command_reply_users_cb,
1666 silc_free(channel_id);
1668 silc_buffer_free(client_id_list);
1669 if (client_mode_list)
1670 silc_buffer_free(client_mode_list);
1674 /* Cache the received Client ID's and modes. */
1675 for (i = 0; i < list_count; i++) {
1678 SilcClientID *client_id;
1681 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1683 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1688 SILC_GET32_MSB(mode, client_mode_list->data);
1690 /* Check if we have this client cached already. */
1691 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1692 if (!client_entry || !client_entry->username || !client_entry->realname) {
1694 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1695 silc_buffer_pull(client_id_list, idp_len);
1696 silc_buffer_pull(client_mode_list, 4);
1699 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1702 /* No we don't have it (or it is incomplete in information), query
1703 it from the server. Assemble argument table that will be sent
1704 for the WHOIS command later. */
1705 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1707 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1709 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1711 res_argv[res_argc] = client_id_list->data;
1712 res_argv_lens[res_argc] = idp_len;
1713 res_argv_types[res_argc] = res_argc + 3;
1716 if (!silc_client_on_channel(channel, client_entry)) {
1717 chu = silc_calloc(1, sizeof(*chu));
1718 chu->client = client_entry;
1720 chu->channel = channel;
1721 silc_hash_table_add(channel->user_list, client_entry, chu);
1722 silc_hash_table_add(client_entry->channels, channel, chu);
1726 silc_free(client_id);
1727 silc_buffer_pull(client_id_list, idp_len);
1728 silc_buffer_pull(client_mode_list, 4);
1731 /* Query the client information from server if the list included clients
1732 that we don't know about. */
1736 /* Send the WHOIS command to server */
1737 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1738 silc_client_command_reply_whois_i, 0,
1740 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1741 res_argc, res_argv, res_argv_lens,
1742 res_argv_types, conn->cmd_ident);
1743 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1744 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1747 /* Register pending command callback. After we've received the WHOIS
1748 command reply we will reprocess this command reply by re-calling this
1749 USERS command reply callback. */
1750 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1751 silc_client_command_reply_users, cmd);
1753 silc_buffer_free(res_cmd);
1754 silc_free(channel_id);
1755 silc_free(res_argv);
1756 silc_free(res_argv_lens);
1757 silc_free(res_argv_types);
1759 silc_buffer_free(client_id_list);
1760 if (client_mode_list)
1761 silc_buffer_free(client_mode_list);
1765 silc_buffer_push(client_id_list, (client_id_list->data -
1766 client_id_list->head));
1767 silc_buffer_push(client_mode_list, (client_mode_list->data -
1768 client_mode_list->head));
1770 /* Notify application */
1771 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1774 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1775 silc_client_command_reply_free(cmd);
1776 silc_free(channel_id);
1778 silc_buffer_free(client_id_list);
1779 if (client_mode_list)
1780 silc_buffer_free(client_mode_list);
1783 /* Received command reply to GETKEY command. WE've received the remote
1784 client's public key. */
1786 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1788 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1789 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1790 SilcCommandStatus status;
1791 SilcIDCacheEntry id_cache;
1792 SilcIDPayload idp = NULL;
1793 SilcClientID *client_id = NULL;
1794 SilcClientEntry client_entry;
1795 SilcServerID *server_id = NULL;
1796 SilcServerEntry server_entry;
1798 unsigned char *tmp, *pk;
1802 SilcPublicKey public_key = NULL;
1804 SILC_LOG_DEBUG(("Start"));
1806 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1807 SILC_GET16_MSB(status, tmp);
1808 if (status != SILC_STATUS_OK) {
1809 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1810 "%s", silc_client_command_status_message(status));
1811 COMMAND_REPLY_ERROR;
1815 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1817 COMMAND_REPLY_ERROR;
1820 idp = silc_id_payload_parse(tmp, len);
1822 COMMAND_REPLY_ERROR;
1826 /* Get the public key payload */
1827 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1829 /* Decode the public key */
1830 SILC_GET16_MSB(pk_len, tmp);
1831 SILC_GET16_MSB(type, tmp + 2);
1834 if (type == SILC_SKE_PK_TYPE_SILC)
1835 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1839 id_type = silc_id_payload_get_type(idp);
1840 if (id_type == SILC_ID_CLIENT) {
1841 /* Received client's public key */
1842 client_id = silc_id_payload_get_id(idp);
1843 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1844 if (!client_entry) {
1845 COMMAND_REPLY_ERROR;
1849 /* Notify application */
1850 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1851 } else if (id_type == SILC_ID_SERVER) {
1852 /* Received server's public key */
1853 server_id = silc_id_payload_get_id(idp);
1854 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1856 COMMAND_REPLY_ERROR;
1860 server_entry = (SilcServerEntry)id_cache->context;
1862 /* Notify application */
1863 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1867 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1869 silc_id_payload_free(idp);
1871 silc_pkcs_public_key_free(public_key);
1872 silc_free(client_id);
1873 silc_free(server_id);
1874 silc_client_command_reply_free(cmd);
1877 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1879 silc_client_command_reply_free(context);
1883 /******************************************************************************
1885 Internal command reply functions
1887 ******************************************************************************/
1889 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1891 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1892 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1893 SilcCommandStatus status;
1895 SILC_LOG_DEBUG(("Start"));
1897 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1898 if (status != SILC_STATUS_OK &&
1899 status != SILC_STATUS_LIST_START &&
1900 status != SILC_STATUS_LIST_ITEM &&
1901 status != SILC_STATUS_LIST_END)
1904 /* Save WHOIS info */
1905 silc_client_command_reply_whois_save(cmd, status, FALSE);
1907 /* Pending callbacks are not executed if this was an list entry */
1908 if (status != SILC_STATUS_OK &&
1909 status != SILC_STATUS_LIST_END) {
1910 silc_client_command_reply_free(cmd);
1915 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1917 /* If we received notify for invalid ID we'll remove the ID if we
1919 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1920 SilcClientEntry client_entry;
1922 unsigned char *tmp =
1923 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1926 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1928 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1931 silc_client_del_client(cmd->client, conn, client_entry);
1932 silc_free(client_id);
1937 /* Unregister this command reply */
1938 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1939 NULL, silc_client_command_reply_whois_i,
1942 silc_client_command_reply_free(cmd);
1945 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1947 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1948 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1949 SilcCommandStatus status;
1951 SILC_LOG_DEBUG(("Start"));
1953 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1954 if (status != SILC_STATUS_OK &&
1955 status != SILC_STATUS_LIST_START &&
1956 status != SILC_STATUS_LIST_ITEM &&
1957 status != SILC_STATUS_LIST_END)
1960 /* Save IDENTIFY info */
1961 silc_client_command_reply_identify_save(cmd, status, FALSE);
1963 /* Pending callbacks are not executed if this was an list entry */
1964 if (status != SILC_STATUS_OK &&
1965 status != SILC_STATUS_LIST_END) {
1966 silc_client_command_reply_free(cmd);
1971 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1973 /* If we received notify for invalid ID we'll remove the ID if we
1975 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1976 SilcClientEntry client_entry;
1978 unsigned char *tmp =
1979 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1982 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1984 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1987 silc_client_del_client(cmd->client, conn, client_entry);
1988 silc_free(client_id);
1993 /* Unregister this command reply */
1994 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1995 NULL, silc_client_command_reply_identify_i,
1998 silc_client_command_reply_free(cmd);
2001 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2003 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2004 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2005 SilcCommandStatus status;
2007 SilcIDCacheEntry id_cache;
2008 SilcServerEntry server;
2009 SilcServerID *server_id = NULL;
2010 char *server_name, *server_info;
2013 SILC_LOG_DEBUG(("Start"));
2015 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
2016 SILC_GET16_MSB(status, tmp);
2017 if (status != SILC_STATUS_OK)
2021 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2025 server_id = silc_id_payload_parse_id(tmp, len);
2029 /* Get server name */
2030 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2034 /* Get server info */
2035 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2039 /* See whether we have this server cached. If not create it. */
2040 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
2042 SILC_LOG_DEBUG(("New server entry"));
2043 server = silc_calloc(1, sizeof(*server));
2044 server->server_name = strdup(server_name);
2045 server->server_info = strdup(server_info);
2046 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
2048 /* Add it to the cache */
2049 silc_idcache_add(conn->server_cache, server->server_name,
2050 server->server_id, (void *)server, 0, NULL);
2054 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2055 silc_free(server_id);
2056 silc_client_command_reply_free(cmd);