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 "clientlibincludes.h"
36 #include "client_internal.h"
38 const SilcCommandStatusMessage silc_command_status_messages[] = {
40 { STAT(NO_SUCH_NICK), "There was no such nickname" },
41 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
42 { STAT(NO_SUCH_SERVER), "There was no such server" },
43 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
44 { STAT(NO_RECIPIENT), "No recipient given" },
45 { STAT(UNKNOWN_COMMAND), "Unknown command" },
46 { STAT(WILDCARDS), "Unknown command" },
47 { STAT(NO_CLIENT_ID), "No Client ID given" },
48 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
49 { STAT(NO_SERVER_ID), "No Server ID given" },
50 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
51 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
52 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
53 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
54 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
55 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
56 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
57 { STAT(USER_ON_CHANNEL), "User already on the channel" },
58 { STAT(NOT_REGISTERED), "You have not registered" },
59 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
60 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
61 { STAT(PERM_DENIED), "Permission denied" },
62 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
63 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
64 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
65 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
66 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
67 { STAT(UNKNOWN_MODE), "Unknown mode" },
68 { STAT(NOT_YOU), "Cannot change mode for other users" },
69 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
70 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
71 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
72 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
73 { STAT(BAD_NICKNAME), "Bad nickname" },
74 { STAT(BAD_CHANNEL), "Bad channel name" },
75 { STAT(AUTH_FAILED), "Authentication failed" },
76 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
77 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
81 /* Command reply operation that is called at the end of all command replys.
82 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
83 #define COMMAND_REPLY(args) cmd->client->internal->ops->command_reply args
84 #define ARGS cmd->client, cmd->sock->user_data, \
85 cmd->payload, TRUE, silc_command_get(cmd->payload), status
87 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
88 #define COMMAND_REPLY_ERROR cmd->client->internal->ops-> \
89 command_reply(cmd->client, cmd->sock->user_data, cmd->payload, \
90 FALSE, silc_command_get(cmd->payload), status)
92 #define SAY cmd->client->internal->ops->say
94 /* All functions that call the COMMAND_CHECK_STATUS or the
95 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
97 #define COMMAND_CHECK_STATUS \
99 SILC_LOG_DEBUG(("Start")); \
100 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
101 if (status != SILC_STATUS_OK) { \
102 COMMAND_REPLY_ERROR; \
107 #define COMMAND_CHECK_STATUS_LIST \
109 SILC_LOG_DEBUG(("Start")); \
110 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
111 if (status != SILC_STATUS_OK && \
112 status != SILC_STATUS_LIST_START && \
113 status != SILC_STATUS_LIST_ITEM && \
114 status != SILC_STATUS_LIST_END) { \
115 COMMAND_REPLY_ERROR; \
120 /* Process received command reply. */
122 void silc_client_command_reply_process(SilcClient client,
123 SilcSocketConnection sock,
124 SilcPacketContext *packet)
126 SilcBuffer buffer = packet->buffer;
127 SilcClientCommand cmd;
128 SilcClientCommandReplyContext ctx;
129 SilcCommandPayload payload;
131 SilcCommandCb reply = NULL;
133 /* Get command reply payload from packet */
134 payload = silc_command_payload_parse(buffer->data, buffer->len);
136 /* Silently ignore bad reply packet */
137 SILC_LOG_DEBUG(("Bad command reply packet"));
141 /* Allocate command reply context. This must be free'd by the
142 command reply routine receiving it. */
143 ctx = silc_calloc(1, sizeof(*ctx));
144 ctx->client = client;
146 ctx->payload = payload;
147 ctx->args = silc_command_get_args(ctx->payload);
148 ctx->packet = packet;
149 ctx->ident = silc_command_get_ident(ctx->payload);
151 /* Check for pending commands and mark to be exeucted */
152 silc_client_command_pending_check(sock->user_data, ctx,
153 silc_command_get(ctx->payload),
156 /* Execute command reply */
158 command = silc_command_get(ctx->payload);
160 /* Try to find matching the command identifier */
161 silc_list_start(client->internal->commands);
162 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
163 if (cmd->cmd == command && !cmd->ident)
165 if (cmd->cmd == command && cmd->ident == ctx->ident) {
166 (*cmd->reply)((void *)ctx, NULL);
171 if (cmd == SILC_LIST_END) {
173 /* No specific identifier for command reply, call first one found */
180 /* Returns status message string */
182 char *silc_client_command_status_message(SilcCommandStatus status)
186 for (i = 0; silc_command_status_messages[i].message; i++) {
187 if (silc_command_status_messages[i].status == status)
191 if (silc_command_status_messages[i].message == NULL)
194 return silc_command_status_messages[i].message;
197 /* Free command reply context and its internals. */
199 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
202 silc_command_payload_free(cmd->payload);
208 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
209 SilcCommandStatus status,
212 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
213 SilcClientID *client_id;
214 SilcClientEntry client_entry = NULL;
217 unsigned char *id_data, *tmp;
218 char *nickname = NULL, *username = NULL;
219 char *realname = NULL;
220 uint32 idle = 0, mode = 0;
221 SilcBuffer channels = NULL;
222 unsigned char *fingerprint;
223 uint32 fingerprint_len;
225 argc = silc_argument_get_arg_num(cmd->args);
227 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
234 client_id = silc_id_payload_parse_id(id_data, len);
241 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
242 username = silc_argument_get_arg_type(cmd->args, 4, &len);
243 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
244 if (!nickname || !username || !realname) {
250 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
252 channels = silc_buffer_alloc(len);
253 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
254 silc_buffer_put(channels, tmp, len);
257 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
259 SILC_GET32_MSB(mode, tmp);
261 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
263 SILC_GET32_MSB(idle, tmp);
265 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
267 /* Check if we have this client cached already. */
268 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
270 SILC_LOG_DEBUG(("Adding new client entry"));
272 silc_client_add_client(cmd->client, conn, nickname, username, realname,
275 silc_client_update_client(cmd->client, conn, client_entry,
276 nickname, username, realname, mode);
277 silc_free(client_id);
280 if (fingerprint && !client_entry->fingerprint) {
281 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
282 client_entry->fingerprint_len = fingerprint_len;
285 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
286 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
288 /* Notify application */
289 if (!cmd->callback && notify)
290 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
291 channels, mode, idle, fingerprint));
294 silc_buffer_free(channels);
297 /* Received reply for WHOIS command. This maybe called several times
298 for one WHOIS command as server may reply with list of results. */
300 SILC_CLIENT_CMD_REPLY_FUNC(whois)
302 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
303 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
304 SilcCommandStatus status;
306 COMMAND_CHECK_STATUS_LIST;
308 /* Save WHOIS info */
309 silc_client_command_reply_whois_save(cmd, status, TRUE);
311 /* Pending callbacks are not executed if this was an list entry */
312 if (status != SILC_STATUS_OK &&
313 status != SILC_STATUS_LIST_END) {
314 silc_client_command_reply_free(cmd);
319 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
321 /* If we received notify for invalid ID we'll remove the ID if we
323 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
324 SilcClientEntry client_entry;
327 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
330 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
332 client_entry = silc_client_get_client_by_id(cmd->client, conn,
335 silc_client_del_client(cmd->client, conn, client_entry);
336 silc_free(client_id);
341 silc_client_command_reply_free(cmd);
344 /* Received reply for WHOWAS command. */
346 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
348 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
349 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
350 SilcCommandStatus status;
351 SilcClientID *client_id;
352 SilcClientEntry client_entry = NULL;
354 unsigned char *id_data;
355 char *nickname, *username;
356 char *realname = NULL;
358 COMMAND_CHECK_STATUS_LIST;
360 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
366 client_id = silc_id_payload_parse_id(id_data, len);
372 /* Get the client entry, if exists */
373 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
374 silc_free(client_id);
376 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
377 username = silc_argument_get_arg_type(cmd->args, 4, &len);
378 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
379 if (!nickname || !username) {
384 /* Notify application. We don't save any history information to any
385 cache. Just pass the data to the application for displaying on
387 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
389 /* Pending callbacks are not executed if this was an list entry */
390 if (status != SILC_STATUS_OK &&
391 status != SILC_STATUS_LIST_END) {
392 silc_client_command_reply_free(cmd);
397 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
398 silc_client_command_reply_free(cmd);
402 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
403 SilcCommandStatus status,
406 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
407 SilcClient client = cmd->client;
408 SilcClientID *client_id = NULL;
409 SilcServerID *server_id = NULL;
410 SilcChannelID *channel_id = NULL;
411 SilcIDCacheEntry id_cache = NULL;
412 SilcClientEntry client_entry;
413 SilcServerEntry server_entry;
414 SilcChannelEntry channel_entry;
417 unsigned char *id_data;
418 char *name = NULL, *info = NULL;
419 SilcIDPayload idp = NULL;
422 argc = silc_argument_get_arg_num(cmd->args);
424 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
430 idp = silc_id_payload_parse(id_data, len);
437 name = silc_argument_get_arg_type(cmd->args, 3, &len);
438 info = silc_argument_get_arg_type(cmd->args, 4, &len);
440 id_type = silc_id_payload_get_type(idp);
444 client_id = silc_id_payload_get_id(idp);
446 SILC_LOG_DEBUG(("Received client information"));
448 /* Check if we have this client cached already. */
449 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
451 SILC_LOG_DEBUG(("Adding new client entry"));
453 silc_client_add_client(cmd->client, conn, name, info, NULL,
454 silc_id_dup(client_id, id_type), 0);
456 silc_client_update_client(cmd->client, conn, client_entry,
457 name, info, NULL, 0);
460 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
461 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
463 /* Notify application */
465 COMMAND_REPLY((ARGS, client_entry, name, info));
469 server_id = silc_id_payload_get_id(idp);
471 SILC_LOG_DEBUG(("Received server information"));
473 /* Check if we have this server cached already. */
474 if (!silc_idcache_find_by_id_one(conn->server_cache,
475 (void *)server_id, &id_cache)) {
476 SILC_LOG_DEBUG(("Adding new server entry"));
478 server_entry = silc_calloc(1, sizeof(*server_entry));
479 server_entry->server_id = silc_id_dup(server_id, id_type);
481 server_entry->server_name = strdup(name);
483 server_entry->server_info = strdup(info);
485 /* Add server to cache */
486 silc_idcache_add(conn->server_cache, server_entry->server_name,
487 server_entry->server_id, (void *)server_entry,
490 server_entry = (SilcServerEntry)id_cache->context;
493 /* Notify application */
495 COMMAND_REPLY((ARGS, server_entry, name, info));
498 case SILC_ID_CHANNEL:
499 channel_id = silc_id_payload_get_id(idp);
501 SILC_LOG_DEBUG(("Received channel information"));
503 /* Check if we have this channel cached already. */
504 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
505 if (!channel_entry) {
509 /* Add new channel entry */
510 channel_entry = silc_client_add_channel(client, conn, name, 0,
515 /* Notify application */
517 COMMAND_REPLY((ARGS, channel_entry, name, info));
521 silc_id_payload_free(idp);
522 silc_free(client_id);
523 silc_free(server_id);
524 silc_free(channel_id);
527 /* Received reply for IDENTIFY command. This maybe called several times
528 for one IDENTIFY command as server may reply with list of results.
529 This is totally silent and does not print anything on screen. */
531 SILC_CLIENT_CMD_REPLY_FUNC(identify)
533 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
534 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
535 SilcCommandStatus status;
537 COMMAND_CHECK_STATUS_LIST;
539 /* Save IDENTIFY info */
540 silc_client_command_reply_identify_save(cmd, status, TRUE);
542 /* Pending callbacks are not executed if this was an list entry */
543 if (status != SILC_STATUS_OK &&
544 status != SILC_STATUS_LIST_END) {
545 silc_client_command_reply_free(cmd);
550 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
552 /* If we received notify for invalid ID we'll remove the ID if we
554 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
555 SilcClientEntry client_entry;
558 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
561 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
563 client_entry = silc_client_get_client_by_id(cmd->client, conn,
566 silc_client_del_client(cmd->client, conn, client_entry);
567 silc_free(client_id);
572 silc_client_command_reply_free(cmd);
575 /* Received reply for command NICK. If everything went without errors
576 we just received our new Client ID. */
578 SILC_CLIENT_CMD_REPLY_FUNC(nick)
580 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
581 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
582 SilcCommandStatus status;
587 SILC_LOG_DEBUG(("Start"));
589 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
590 if (status != SILC_STATUS_OK) {
591 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
592 "Cannot set nickname: %s", silc_client_command_status_message(status));
597 argc = silc_argument_get_arg_num(cmd->args);
598 if (argc < 2 || argc > 2) {
599 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
600 "Cannot set nickname: bad reply to command");
605 /* Take received Client ID */
606 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
607 idp = silc_id_payload_parse(tmp, len);
612 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
614 /* Notify application */
615 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
616 COMMAND_REPLY((ARGS, conn->local_entry));
617 silc_client_command_reply_free(cmd);
621 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
622 silc_client_command_reply_free(cmd);
625 /* Received reply to the LIST command. */
627 SILC_CLIENT_CMD_REPLY_FUNC(list)
629 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
630 SilcCommandStatus status;
631 unsigned char *tmp, *name, *topic;
632 uint32 usercount = 0;
634 COMMAND_CHECK_STATUS_LIST;
636 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
637 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
638 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
640 SILC_GET32_MSB(usercount, tmp);
642 /* Notify application */
643 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
645 /* Pending callbacks are not executed if this was an list entry */
646 if (status != SILC_STATUS_OK &&
647 status != SILC_STATUS_LIST_END) {
648 silc_client_command_reply_free(cmd);
653 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
654 silc_client_command_reply_free(cmd);
657 /* Received reply to topic command. */
659 SILC_CLIENT_CMD_REPLY_FUNC(topic)
661 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
662 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
663 SilcCommandStatus status;
664 SilcChannelEntry channel;
665 SilcChannelID *channel_id = NULL;
670 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
671 if (status != SILC_STATUS_OK) {
672 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
673 "%s", silc_client_command_status_message(status));
678 argc = silc_argument_get_arg_num(cmd->args);
679 if (argc < 1 || argc > 3) {
684 /* Take Channel ID */
685 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
690 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
694 channel_id = silc_id_payload_parse_id(tmp, len);
698 /* Get the channel entry */
699 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
701 silc_free(channel_id);
706 /* Notify application */
707 COMMAND_REPLY((ARGS, channel, topic));
710 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
711 silc_client_command_reply_free(cmd);
714 /* Received reply to invite command. */
716 SILC_CLIENT_CMD_REPLY_FUNC(invite)
718 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
719 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
720 SilcCommandStatus status;
721 SilcChannelEntry channel;
722 SilcChannelID *channel_id;
726 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
727 SILC_GET16_MSB(status, tmp);
728 if (status != SILC_STATUS_OK) {
729 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
730 "%s", silc_client_command_status_message(status));
735 /* Take Channel ID */
736 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
740 channel_id = silc_id_payload_parse_id(tmp, len);
744 /* Get the channel entry */
745 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
747 silc_free(channel_id);
752 /* Get the invite list */
753 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
755 /* Notify application */
756 COMMAND_REPLY((ARGS, channel, tmp));
759 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
760 silc_client_command_reply_free(cmd);
763 /* Received reply to the KILL command. */
765 SILC_CLIENT_CMD_REPLY_FUNC(kill)
767 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
768 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
769 SilcCommandStatus status;
771 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
772 if (status != SILC_STATUS_OK) {
773 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
774 "%s", silc_client_command_status_message(status));
779 /* Notify application */
780 COMMAND_REPLY((ARGS));
783 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
784 silc_client_command_reply_free(cmd);
787 /* Received reply to INFO command. We receive the server ID and some
788 information about the server user requested. */
790 SILC_CLIENT_CMD_REPLY_FUNC(info)
792 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
793 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
794 SilcCommandStatus status;
796 SilcIDCacheEntry id_cache;
797 SilcServerEntry server;
798 SilcServerID *server_id = NULL;
799 char *server_name, *server_info;
802 SILC_LOG_DEBUG(("Start"));
804 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
805 SILC_GET16_MSB(status, tmp);
806 if (status != SILC_STATUS_OK) {
807 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
808 silc_client_command_status_message(status));
814 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
818 server_id = silc_id_payload_parse_id(tmp, len);
822 /* Get server name */
823 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
827 /* Get server info */
828 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
832 /* See whether we have this server cached. If not create it. */
833 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
835 SILC_LOG_DEBUG(("New server entry"));
837 server = silc_calloc(1, sizeof(*server));
838 server->server_name = strdup(server_name);
839 server->server_info = strdup(server_info);
840 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
842 /* Add it to the cache */
843 silc_idcache_add(conn->server_cache, server->server_name,
844 server->server_id, (void *)server, 0, NULL);
846 server = (SilcServerEntry)id_cache->context;
849 /* Notify application */
850 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
853 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
854 silc_free(server_id);
855 silc_client_command_reply_free(cmd);
858 /* Received reply to PING command. The reply time is shown to user. */
860 SILC_CLIENT_CMD_REPLY_FUNC(ping)
862 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
863 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
864 SilcCommandStatus status;
867 time_t diff, curtime;
869 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
870 if (status != SILC_STATUS_OK) {
871 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
872 "%s", silc_client_command_status_message(status));
877 curtime = time(NULL);
878 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
879 cmd->packet->src_id_type);
880 if (!id || !conn->ping) {
885 for (i = 0; i < conn->ping_count; i++) {
886 if (!conn->ping[i].dest_id)
888 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
889 diff = curtime - conn->ping[i].start_time;
890 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
891 "Ping reply from %s: %d second%s",
892 conn->ping[i].dest_name, diff,
893 diff == 1 ? "" : "s");
895 conn->ping[i].start_time = 0;
896 silc_free(conn->ping[i].dest_id);
897 conn->ping[i].dest_id = NULL;
898 silc_free(conn->ping[i].dest_name);
899 conn->ping[i].dest_name = NULL;
906 /* Notify application */
907 COMMAND_REPLY((ARGS));
910 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
911 silc_client_command_reply_free(cmd);
914 /* Received reply for JOIN command. */
916 SILC_CLIENT_CMD_REPLY_FUNC(join)
918 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
919 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
920 SilcCommandStatus status;
921 SilcChannelEntry channel;
923 SilcChannelID *channel_id;
924 uint32 argc, mode = 0, len, list_count;
925 char *topic, *tmp, *channel_name = NULL, *hmac;
926 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
929 SILC_LOG_DEBUG(("Start"));
931 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
932 if (status != SILC_STATUS_OK) {
933 if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
934 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
935 "%s", silc_client_command_status_message(status));
940 argc = silc_argument_get_arg_num(cmd->args);
941 if (argc < 7 || argc > 14) {
942 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
943 "Cannot join channel: Bad reply packet");
948 /* Get channel name */
949 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
951 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
952 "Cannot join channel: Bad reply packet");
959 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
961 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
962 "Cannot join channel: Bad reply packet");
966 channel_id = silc_id_payload_parse_id(tmp, len);
972 /* Get channel mode */
973 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
975 SILC_GET32_MSB(mode, tmp);
977 /* Get channel key */
978 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
980 keyp = silc_buffer_alloc(len);
981 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
982 silc_buffer_put(keyp, tmp, len);
986 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
988 /* Check whether we have this channel entry already. */
989 channel = silc_client_get_channel(cmd->client, conn, channel_name);
991 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
992 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
994 /* Create new channel entry */
995 channel = silc_client_add_channel(cmd->client, conn, channel_name,
999 conn->current_channel = channel;
1002 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1004 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1005 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1006 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1007 COMMAND_REPLY_ERROR;
1012 /* Get the list count */
1013 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1016 SILC_GET32_MSB(list_count, tmp);
1018 /* Get Client ID list */
1019 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1023 client_id_list = silc_buffer_alloc(len);
1024 silc_buffer_pull_tail(client_id_list, len);
1025 silc_buffer_put(client_id_list, tmp, len);
1027 /* Get client mode list */
1028 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1032 client_mode_list = silc_buffer_alloc(len);
1033 silc_buffer_pull_tail(client_mode_list, len);
1034 silc_buffer_put(client_mode_list, tmp, len);
1036 /* Add clients we received in the reply to the channel */
1037 for (i = 0; i < list_count; i++) {
1040 SilcClientID *client_id;
1041 SilcClientEntry client_entry;
1044 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1046 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1051 SILC_GET32_MSB(mode, client_mode_list->data);
1053 /* Check if we have this client cached already. */
1054 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1055 if (!client_entry) {
1056 /* No, we don't have it, add entry for it. */
1058 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1059 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1062 /* Join client to the channel */
1063 chu = silc_calloc(1, sizeof(*chu));
1064 chu->client = client_entry;
1065 chu->channel = channel;
1067 silc_hash_table_add(channel->user_list, client_entry, chu);
1068 silc_hash_table_add(client_entry->channels, channel, chu);
1070 silc_free(client_id);
1071 silc_buffer_pull(client_id_list, idp_len);
1072 silc_buffer_pull(client_mode_list, 4);
1074 silc_buffer_push(client_id_list, client_id_list->data -
1075 client_id_list->head);
1076 silc_buffer_push(client_mode_list, client_mode_list->data -
1077 client_mode_list->head);
1079 /* Save channel key */
1080 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1081 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1083 /* Notify application */
1084 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1085 keyp ? keyp->head : NULL, NULL,
1086 NULL, topic, hmac, list_count, client_id_list,
1090 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1091 silc_client_command_reply_free(cmd);
1094 silc_buffer_free(keyp);
1096 silc_buffer_free(client_id_list);
1097 if (client_mode_list)
1098 silc_buffer_free(client_mode_list);
1101 /* Received reply for MOTD command */
1103 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1105 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1106 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1107 SilcCommandStatus status;
1110 char *motd = NULL, *cp, line[256];
1112 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1113 SILC_GET16_MSB(status, tmp);
1114 if (status != SILC_STATUS_OK) {
1115 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1116 "%s", silc_client_command_status_message(status));
1117 COMMAND_REPLY_ERROR;
1121 argc = silc_argument_get_arg_num(cmd->args);
1123 COMMAND_REPLY_ERROR;
1128 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1130 COMMAND_REPLY_ERROR;
1137 if (cp[i++] == '\n') {
1138 memset(line, 0, sizeof(line));
1139 strncat(line, cp, i - 1);
1145 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1154 /* Notify application */
1155 COMMAND_REPLY((ARGS, motd));
1158 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1159 silc_client_command_reply_free(cmd);
1162 /* Received reply tot he UMODE command. Save the current user mode */
1164 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1166 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1167 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1168 SilcCommandStatus status;
1172 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1173 SILC_GET16_MSB(status, tmp);
1174 if (status != SILC_STATUS_OK) {
1175 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1176 "%s", silc_client_command_status_message(status));
1177 COMMAND_REPLY_ERROR;
1181 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1183 COMMAND_REPLY_ERROR;
1187 SILC_GET32_MSB(mode, tmp);
1188 conn->local_entry->mode = mode;
1190 /* Notify application */
1191 COMMAND_REPLY((ARGS, mode));
1194 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1195 silc_client_command_reply_free(cmd);
1198 /* Received reply for CMODE command. */
1200 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1202 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1203 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1204 SilcCommandStatus status;
1207 SilcChannelID *channel_id;
1208 SilcChannelEntry channel;
1211 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1212 if (status != SILC_STATUS_OK) {
1213 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1214 "%s", silc_client_command_status_message(status));
1215 COMMAND_REPLY_ERROR;
1219 /* Take Channel ID */
1220 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1223 channel_id = silc_id_payload_parse_id(tmp, len);
1227 /* Get the channel entry */
1228 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1230 silc_free(channel_id);
1231 COMMAND_REPLY_ERROR;
1235 /* Get channel mode */
1236 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1238 silc_free(channel_id);
1239 COMMAND_REPLY_ERROR;
1244 SILC_GET32_MSB(mode, tmp);
1245 channel->mode = mode;
1247 /* Notify application */
1248 COMMAND_REPLY((ARGS, channel, mode));
1250 silc_free(channel_id);
1253 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1254 silc_client_command_reply_free(cmd);
1257 /* Received reply for CUMODE command */
1259 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1261 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1262 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1263 SilcCommandStatus status;
1264 SilcClientID *client_id;
1265 SilcChannelID *channel_id;
1266 SilcClientEntry client_entry;
1267 SilcChannelEntry channel;
1268 SilcChannelUser chu;
1269 unsigned char *modev, *tmp, *id;
1272 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1273 if (status != SILC_STATUS_OK) {
1274 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1275 "%s", silc_client_command_status_message(status));
1276 COMMAND_REPLY_ERROR;
1280 /* Get channel mode */
1281 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1283 COMMAND_REPLY_ERROR;
1287 /* Take Channel ID */
1288 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1291 channel_id = silc_id_payload_parse_id(tmp, len);
1295 /* Get the channel entry */
1296 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1298 silc_free(channel_id);
1299 COMMAND_REPLY_ERROR;
1304 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1306 silc_free(channel_id);
1307 COMMAND_REPLY_ERROR;
1310 client_id = silc_id_payload_parse_id(id, len);
1312 silc_free(channel_id);
1313 COMMAND_REPLY_ERROR;
1317 /* Get client entry */
1318 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1319 if (!client_entry) {
1320 silc_free(channel_id);
1321 silc_free(client_id);
1322 COMMAND_REPLY_ERROR;
1327 SILC_GET32_MSB(mode, modev);
1328 chu = silc_client_on_channel(channel, client_entry);
1332 /* Notify application */
1333 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1334 silc_free(client_id);
1335 silc_free(channel_id);
1338 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1339 silc_client_command_reply_free(cmd);
1342 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1344 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1345 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1346 SilcCommandStatus status;
1349 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1350 SILC_GET16_MSB(status, tmp);
1351 if (status != SILC_STATUS_OK) {
1352 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1353 "%s", silc_client_command_status_message(status));
1354 COMMAND_REPLY_ERROR;
1358 /* Notify application */
1359 COMMAND_REPLY((ARGS));
1362 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1363 silc_client_command_reply_free(cmd);
1366 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1368 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1369 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1370 SilcCommandStatus status;
1373 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1374 SILC_GET16_MSB(status, tmp);
1375 if (status != SILC_STATUS_OK) {
1376 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1377 "%s", silc_client_command_status_message(status));
1378 COMMAND_REPLY_ERROR;
1382 /* Notify application */
1383 COMMAND_REPLY((ARGS));
1386 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1387 silc_client_command_reply_free(cmd);
1390 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1392 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1393 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1394 SilcCommandStatus status;
1397 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1398 SILC_GET16_MSB(status, tmp);
1399 if (status != SILC_STATUS_OK) {
1400 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1401 "%s", silc_client_command_status_message(status));
1402 COMMAND_REPLY_ERROR;
1406 /* Notify application */
1407 COMMAND_REPLY((ARGS));
1410 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1411 silc_client_command_reply_free(cmd);
1414 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1416 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1417 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1418 SilcCommandStatus status;
1421 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1422 SILC_GET16_MSB(status, tmp);
1423 if (status != SILC_STATUS_OK) {
1424 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1425 "%s", silc_client_command_status_message(status));
1426 COMMAND_REPLY_ERROR;
1430 /* Notify application */
1431 COMMAND_REPLY((ARGS));
1434 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1435 silc_client_command_reply_free(cmd);
1438 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1440 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1441 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1442 SilcCommandStatus status;
1443 SilcChannelEntry channel;
1444 SilcChannelID *channel_id;
1448 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1449 SILC_GET16_MSB(status, tmp);
1450 if (status != SILC_STATUS_OK) {
1451 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1452 "%s", silc_client_command_status_message(status));
1453 COMMAND_REPLY_ERROR;
1457 /* Take Channel ID */
1458 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1462 channel_id = silc_id_payload_parse_id(tmp, len);
1466 /* Get the channel entry */
1467 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1469 silc_free(channel_id);
1470 COMMAND_REPLY_ERROR;
1474 /* Get the ban list */
1475 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1477 /* Notify application */
1478 COMMAND_REPLY((ARGS, channel, tmp));
1481 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1482 silc_client_command_reply_free(cmd);
1485 SILC_CLIENT_CMD_REPLY_FUNC(close)
1487 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1488 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1489 SilcCommandStatus status;
1492 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1493 SILC_GET16_MSB(status, tmp);
1494 if (status != SILC_STATUS_OK) {
1495 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1496 "%s", silc_client_command_status_message(status));
1497 COMMAND_REPLY_ERROR;
1501 /* Notify application */
1502 COMMAND_REPLY((ARGS));
1505 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1506 silc_client_command_reply_free(cmd);
1509 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1511 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1512 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1513 SilcCommandStatus status;
1516 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1517 SILC_GET16_MSB(status, tmp);
1518 if (status != SILC_STATUS_OK) {
1519 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1520 "%s", silc_client_command_status_message(status));
1521 COMMAND_REPLY_ERROR;
1525 /* Notify application */
1526 COMMAND_REPLY((ARGS));
1529 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1530 silc_client_command_reply_free(cmd);
1533 /* Reply to LEAVE command. */
1535 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1537 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1538 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1539 SilcCommandStatus status;
1542 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1543 SILC_GET16_MSB(status, tmp);
1544 if (status != SILC_STATUS_OK) {
1545 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1546 "%s", silc_client_command_status_message(status));
1547 COMMAND_REPLY_ERROR;
1551 /* Notify application */
1552 COMMAND_REPLY((ARGS));
1555 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1556 silc_client_command_reply_free(cmd);
1559 /* Channel resolving callback for USERS command reply. */
1561 static void silc_client_command_reply_users_cb(SilcClient client,
1562 SilcClientConnection conn,
1563 SilcChannelEntry *channels,
1564 uint32 channels_count,
1567 if (!channels_count) {
1568 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1569 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1570 SilcCommandStatus status = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1572 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1573 "%s", silc_client_command_status_message(status));
1574 COMMAND_REPLY_ERROR;
1575 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1576 silc_client_command_reply_free(cmd);
1580 silc_client_command_reply_users(context, NULL);
1583 /* Reply to USERS command. Received list of client ID's and theirs modes
1584 on the channel we requested. */
1586 SILC_CLIENT_CMD_REPLY_FUNC(users)
1588 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1589 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1590 SilcCommandStatus status;
1591 SilcChannelEntry channel;
1592 SilcClientEntry client_entry;
1593 SilcChannelUser chu;
1594 SilcChannelID *channel_id = NULL;
1595 SilcBuffer client_id_list = NULL;
1596 SilcBuffer client_mode_list = NULL;
1598 uint32 tmp_len, list_count;
1600 unsigned char **res_argv = NULL;
1601 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1603 SILC_LOG_DEBUG(("Start"));
1605 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1606 SILC_GET16_MSB(status, tmp);
1607 if (status != SILC_STATUS_OK) {
1608 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1609 "%s", silc_client_command_status_message(status));
1610 COMMAND_REPLY_ERROR;
1614 /* Get channel ID */
1615 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1617 COMMAND_REPLY_ERROR;
1620 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1622 COMMAND_REPLY_ERROR;
1626 /* Get the list count */
1627 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1629 COMMAND_REPLY_ERROR;
1632 SILC_GET32_MSB(list_count, tmp);
1634 /* Get Client ID list */
1635 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1637 COMMAND_REPLY_ERROR;
1641 client_id_list = silc_buffer_alloc(tmp_len);
1642 silc_buffer_pull_tail(client_id_list, tmp_len);
1643 silc_buffer_put(client_id_list, tmp, tmp_len);
1645 /* Get client mode list */
1646 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1648 COMMAND_REPLY_ERROR;
1652 client_mode_list = silc_buffer_alloc(tmp_len);
1653 silc_buffer_pull_tail(client_mode_list, tmp_len);
1654 silc_buffer_put(client_mode_list, tmp, tmp_len);
1656 /* Get channel entry */
1657 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1659 /* Resolve the channel from server */
1660 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1661 silc_client_command_reply_users_cb,
1663 silc_free(channel_id);
1665 silc_buffer_free(client_id_list);
1666 if (client_mode_list)
1667 silc_buffer_free(client_mode_list);
1671 /* Cache the received Client ID's and modes. */
1672 for (i = 0; i < list_count; i++) {
1675 SilcClientID *client_id;
1678 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1680 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1685 SILC_GET32_MSB(mode, client_mode_list->data);
1687 /* Check if we have this client cached already. */
1688 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1689 if (!client_entry || !client_entry->username || !client_entry->realname) {
1691 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1692 silc_buffer_pull(client_id_list, idp_len);
1693 silc_buffer_pull(client_mode_list, 4);
1696 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1699 /* No we don't have it (or it is incomplete in information), query
1700 it from the server. Assemble argument table that will be sent
1701 for the WHOIS command later. */
1702 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1704 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1706 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1708 res_argv[res_argc] = client_id_list->data;
1709 res_argv_lens[res_argc] = idp_len;
1710 res_argv_types[res_argc] = res_argc + 3;
1713 if (!silc_client_on_channel(channel, client_entry)) {
1714 chu = silc_calloc(1, sizeof(*chu));
1715 chu->client = client_entry;
1716 chu->channel = channel;
1717 silc_hash_table_add(channel->user_list, client_entry, chu);
1718 silc_hash_table_add(client_entry->channels, channel, chu);
1722 silc_free(client_id);
1723 silc_buffer_pull(client_id_list, idp_len);
1724 silc_buffer_pull(client_mode_list, 4);
1727 /* Query the client information from server if the list included clients
1728 that we don't know about. */
1732 /* Send the WHOIS command to server */
1733 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1734 silc_client_command_reply_whois_i, 0,
1736 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1737 res_argc, res_argv, res_argv_lens,
1738 res_argv_types, conn->cmd_ident);
1739 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1740 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1743 /* Register pending command callback. After we've received the WHOIS
1744 command reply we will reprocess this command reply by re-calling this
1745 USERS command reply callback. */
1746 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1747 silc_client_command_reply_users, cmd);
1749 silc_buffer_free(res_cmd);
1750 silc_free(channel_id);
1751 silc_free(res_argv);
1752 silc_free(res_argv_lens);
1753 silc_free(res_argv_types);
1755 silc_buffer_free(client_id_list);
1756 if (client_mode_list)
1757 silc_buffer_free(client_mode_list);
1761 silc_buffer_push(client_id_list, (client_id_list->data -
1762 client_id_list->head));
1763 silc_buffer_push(client_mode_list, (client_mode_list->data -
1764 client_mode_list->head));
1766 /* Notify application */
1767 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1770 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1771 silc_client_command_reply_free(cmd);
1772 silc_free(channel_id);
1774 silc_buffer_free(client_id_list);
1775 if (client_mode_list)
1776 silc_buffer_free(client_mode_list);
1779 /* Received command reply to GETKEY command. WE've received the remote
1780 client's public key. */
1782 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1784 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1785 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1786 SilcCommandStatus status;
1787 SilcIDCacheEntry id_cache;
1788 SilcIDPayload idp = NULL;
1789 SilcClientID *client_id = NULL;
1790 SilcClientEntry client_entry;
1791 SilcServerID *server_id = NULL;
1792 SilcServerEntry server_entry;
1794 unsigned char *tmp, *pk;
1798 SilcPublicKey public_key = NULL;
1800 SILC_LOG_DEBUG(("Start"));
1802 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1803 SILC_GET16_MSB(status, tmp);
1804 if (status != SILC_STATUS_OK) {
1805 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1806 "%s", silc_client_command_status_message(status));
1807 COMMAND_REPLY_ERROR;
1811 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1813 COMMAND_REPLY_ERROR;
1816 idp = silc_id_payload_parse(tmp, len);
1818 COMMAND_REPLY_ERROR;
1822 /* Get the public key payload */
1823 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1825 /* Decode the public key */
1826 SILC_GET16_MSB(pk_len, tmp);
1827 SILC_GET16_MSB(type, tmp + 2);
1830 if (type == SILC_SKE_PK_TYPE_SILC)
1831 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1835 id_type = silc_id_payload_get_type(idp);
1836 if (id_type == SILC_ID_CLIENT) {
1837 /* Received client's public key */
1838 client_id = silc_id_payload_get_id(idp);
1839 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1840 if (!client_entry) {
1841 COMMAND_REPLY_ERROR;
1845 /* Notify application */
1846 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1847 } else if (id_type == SILC_ID_SERVER) {
1848 /* Received server's public key */
1849 server_id = silc_id_payload_get_id(idp);
1850 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1852 COMMAND_REPLY_ERROR;
1856 server_entry = (SilcServerEntry)id_cache->context;
1858 /* Notify application */
1859 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1863 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1865 silc_id_payload_free(idp);
1867 silc_pkcs_public_key_free(public_key);
1868 silc_free(client_id);
1869 silc_free(server_id);
1870 silc_client_command_reply_free(cmd);
1873 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1875 silc_client_command_reply_free(context);
1879 /******************************************************************************
1881 Internal command reply functions
1883 ******************************************************************************/
1885 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1887 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1888 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1889 SilcCommandStatus status;
1891 SILC_LOG_DEBUG(("Start"));
1893 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1894 if (status != SILC_STATUS_OK &&
1895 status != SILC_STATUS_LIST_START &&
1896 status != SILC_STATUS_LIST_ITEM &&
1897 status != SILC_STATUS_LIST_END)
1900 /* Save WHOIS info */
1901 silc_client_command_reply_whois_save(cmd, status, FALSE);
1903 /* Pending callbacks are not executed if this was an list entry */
1904 if (status != SILC_STATUS_OK &&
1905 status != SILC_STATUS_LIST_END) {
1906 silc_client_command_reply_free(cmd);
1911 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1913 /* If we received notify for invalid ID we'll remove the ID if we
1915 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1916 SilcClientEntry client_entry;
1918 unsigned char *tmp =
1919 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1922 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1924 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1927 silc_client_del_client(cmd->client, conn, client_entry);
1928 silc_free(client_id);
1933 /* Unregister this command reply */
1934 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1935 NULL, silc_client_command_reply_whois_i,
1938 silc_client_command_reply_free(cmd);
1941 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1943 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1944 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1945 SilcCommandStatus status;
1947 SILC_LOG_DEBUG(("Start"));
1949 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1950 if (status != SILC_STATUS_OK &&
1951 status != SILC_STATUS_LIST_START &&
1952 status != SILC_STATUS_LIST_ITEM &&
1953 status != SILC_STATUS_LIST_END)
1956 /* Save IDENTIFY info */
1957 silc_client_command_reply_identify_save(cmd, status, FALSE);
1959 /* Pending callbacks are not executed if this was an list entry */
1960 if (status != SILC_STATUS_OK &&
1961 status != SILC_STATUS_LIST_END) {
1962 silc_client_command_reply_free(cmd);
1967 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1969 /* If we received notify for invalid ID we'll remove the ID if we
1971 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1972 SilcClientEntry client_entry;
1974 unsigned char *tmp =
1975 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1978 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1980 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1983 silc_client_del_client(cmd->client, conn, client_entry);
1984 silc_free(client_id);
1989 /* Unregister this command reply */
1990 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1991 NULL, silc_client_command_reply_identify_i,
1994 silc_client_command_reply_free(cmd);
1997 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1999 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2000 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2001 SilcCommandStatus status;
2003 SilcIDCacheEntry id_cache;
2004 SilcServerEntry server;
2005 SilcServerID *server_id = NULL;
2006 char *server_name, *server_info;
2009 SILC_LOG_DEBUG(("Start"));
2011 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
2012 SILC_GET16_MSB(status, tmp);
2013 if (status != SILC_STATUS_OK)
2017 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2021 server_id = silc_id_payload_parse_id(tmp, len);
2025 /* Get server name */
2026 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2030 /* Get server info */
2031 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2035 /* See whether we have this server cached. If not create it. */
2036 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
2038 SILC_LOG_DEBUG(("New server entry"));
2039 server = silc_calloc(1, sizeof(*server));
2040 server->server_name = strdup(server_name);
2041 server->server_info = strdup(server_info);
2042 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
2044 /* Add it to the cache */
2045 silc_idcache_add(conn->server_cache, server->server_name,
2046 server->server_id, (void *)server, 0, NULL);
2050 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2051 silc_free(server_id);
2052 silc_client_command_reply_free(cmd);