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 =
282 silc_calloc(fingerprint_len,
283 sizeof(*client_entry->fingerprint));
284 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
285 client_entry->fingerprint_len = fingerprint_len;
288 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
289 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
291 /* Notify application */
292 if (!cmd->callback && notify)
293 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
294 channels, mode, idle, fingerprint));
297 silc_buffer_free(channels);
300 /* Received reply for WHOIS command. This maybe called several times
301 for one WHOIS command as server may reply with list of results. */
303 SILC_CLIENT_CMD_REPLY_FUNC(whois)
305 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
306 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
307 SilcCommandStatus status;
309 COMMAND_CHECK_STATUS_LIST;
311 /* Save WHOIS info */
312 silc_client_command_reply_whois_save(cmd, status, TRUE);
314 /* Pending callbacks are not executed if this was an list entry */
315 if (status != SILC_STATUS_OK &&
316 status != SILC_STATUS_LIST_END) {
317 silc_client_command_reply_free(cmd);
322 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
324 /* If we received notify for invalid ID we'll remove the ID if we
326 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
327 SilcClientEntry client_entry;
330 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
333 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
335 client_entry = silc_client_get_client_by_id(cmd->client, conn,
338 silc_client_del_client(cmd->client, conn, client_entry);
339 silc_free(client_id);
344 silc_client_command_reply_free(cmd);
347 /* Received reply for WHOWAS command. */
349 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
351 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
352 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
353 SilcCommandStatus status;
354 SilcClientID *client_id;
355 SilcClientEntry client_entry = NULL;
357 unsigned char *id_data;
358 char *nickname, *username;
359 char *realname = NULL;
361 COMMAND_CHECK_STATUS_LIST;
363 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
369 client_id = silc_id_payload_parse_id(id_data, len);
375 /* Get the client entry, if exists */
376 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
377 silc_free(client_id);
379 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
380 username = silc_argument_get_arg_type(cmd->args, 4, &len);
381 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
382 if (!nickname || !username) {
387 /* Notify application. We don't save any history information to any
388 cache. Just pass the data to the application for displaying on
390 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
392 /* Pending callbacks are not executed if this was an list entry */
393 if (status != SILC_STATUS_OK &&
394 status != SILC_STATUS_LIST_END) {
395 silc_client_command_reply_free(cmd);
400 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
401 silc_client_command_reply_free(cmd);
405 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
406 SilcCommandStatus status,
409 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
410 SilcClient client = cmd->client;
411 SilcClientID *client_id = NULL;
412 SilcServerID *server_id = NULL;
413 SilcChannelID *channel_id = NULL;
414 SilcIDCacheEntry id_cache = NULL;
415 SilcClientEntry client_entry;
416 SilcServerEntry server_entry;
417 SilcChannelEntry channel_entry;
420 unsigned char *id_data;
421 char *name = NULL, *info = NULL;
422 SilcIDPayload idp = NULL;
425 argc = silc_argument_get_arg_num(cmd->args);
427 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
433 idp = silc_id_payload_parse(id_data, len);
440 name = silc_argument_get_arg_type(cmd->args, 3, &len);
441 info = silc_argument_get_arg_type(cmd->args, 4, &len);
443 id_type = silc_id_payload_get_type(idp);
447 client_id = silc_id_payload_get_id(idp);
449 SILC_LOG_DEBUG(("Received client information"));
451 /* Check if we have this client cached already. */
452 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
454 SILC_LOG_DEBUG(("Adding new client entry"));
456 silc_client_add_client(cmd->client, conn, name, info, NULL,
457 silc_id_dup(client_id, id_type), 0);
459 silc_client_update_client(cmd->client, conn, client_entry,
460 name, info, NULL, 0);
463 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
464 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
466 /* Notify application */
468 COMMAND_REPLY((ARGS, client_entry, name, info));
472 server_id = silc_id_payload_get_id(idp);
474 SILC_LOG_DEBUG(("Received server information"));
476 /* Check if we have this server cached already. */
477 if (!silc_idcache_find_by_id_one(conn->server_cache,
478 (void *)server_id, &id_cache)) {
479 SILC_LOG_DEBUG(("Adding new server entry"));
481 server_entry = silc_calloc(1, sizeof(*server_entry));
482 server_entry->server_id = silc_id_dup(server_id, id_type);
484 server_entry->server_name = strdup(name);
486 server_entry->server_info = strdup(info);
488 /* Add server to cache */
489 silc_idcache_add(conn->server_cache, server_entry->server_name,
490 server_entry->server_id, (void *)server_entry,
493 server_entry = (SilcServerEntry)id_cache->context;
496 /* Notify application */
498 COMMAND_REPLY((ARGS, server_entry, name, info));
501 case SILC_ID_CHANNEL:
502 channel_id = silc_id_payload_get_id(idp);
504 SILC_LOG_DEBUG(("Received channel information"));
506 /* Check if we have this channel cached already. */
507 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
508 if (!channel_entry) {
512 /* Add new channel entry */
513 channel_entry = silc_client_add_channel(client, conn, name, 0,
518 /* Notify application */
520 COMMAND_REPLY((ARGS, channel_entry, name, info));
524 silc_id_payload_free(idp);
525 silc_free(client_id);
526 silc_free(server_id);
527 silc_free(channel_id);
530 /* Received reply for IDENTIFY command. This maybe called several times
531 for one IDENTIFY command as server may reply with list of results.
532 This is totally silent and does not print anything on screen. */
534 SILC_CLIENT_CMD_REPLY_FUNC(identify)
536 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
537 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
538 SilcCommandStatus status;
540 COMMAND_CHECK_STATUS_LIST;
542 /* Save IDENTIFY info */
543 silc_client_command_reply_identify_save(cmd, status, TRUE);
545 /* Pending callbacks are not executed if this was an list entry */
546 if (status != SILC_STATUS_OK &&
547 status != SILC_STATUS_LIST_END) {
548 silc_client_command_reply_free(cmd);
553 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
555 /* If we received notify for invalid ID we'll remove the ID if we
557 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
558 SilcClientEntry client_entry;
561 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
564 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
566 client_entry = silc_client_get_client_by_id(cmd->client, conn,
569 silc_client_del_client(cmd->client, conn, client_entry);
570 silc_free(client_id);
575 silc_client_command_reply_free(cmd);
578 /* Received reply for command NICK. If everything went without errors
579 we just received our new Client ID. */
581 SILC_CLIENT_CMD_REPLY_FUNC(nick)
583 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
584 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
585 SilcCommandStatus status;
590 SILC_LOG_DEBUG(("Start"));
592 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
593 if (status != SILC_STATUS_OK) {
594 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
595 "Cannot set nickname: %s", silc_client_command_status_message(status));
600 argc = silc_argument_get_arg_num(cmd->args);
601 if (argc < 2 || argc > 2) {
602 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
603 "Cannot set nickname: bad reply to command");
608 /* Take received Client ID */
609 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
610 idp = silc_id_payload_parse(tmp, len);
615 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
617 /* Notify application */
618 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
619 COMMAND_REPLY((ARGS, conn->local_entry));
620 silc_client_command_reply_free(cmd);
624 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
625 silc_client_command_reply_free(cmd);
628 /* Received reply to the LIST command. */
630 SILC_CLIENT_CMD_REPLY_FUNC(list)
632 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
633 SilcCommandStatus status;
634 unsigned char *tmp, *name, *topic;
635 uint32 usercount = 0;
637 COMMAND_CHECK_STATUS_LIST;
639 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
640 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
641 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
643 SILC_GET32_MSB(usercount, tmp);
645 /* Notify application */
646 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
648 /* Pending callbacks are not executed if this was an list entry */
649 if (status != SILC_STATUS_OK &&
650 status != SILC_STATUS_LIST_END) {
651 silc_client_command_reply_free(cmd);
656 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
657 silc_client_command_reply_free(cmd);
660 /* Received reply to topic command. */
662 SILC_CLIENT_CMD_REPLY_FUNC(topic)
664 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
665 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
666 SilcCommandStatus status;
667 SilcChannelEntry channel;
668 SilcChannelID *channel_id = NULL;
673 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
674 if (status != SILC_STATUS_OK) {
675 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
676 "%s", silc_client_command_status_message(status));
681 argc = silc_argument_get_arg_num(cmd->args);
682 if (argc < 1 || argc > 3) {
687 /* Take Channel ID */
688 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
693 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
697 channel_id = silc_id_payload_parse_id(tmp, len);
701 /* Get the channel entry */
702 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
704 silc_free(channel_id);
709 /* Notify application */
710 COMMAND_REPLY((ARGS, channel, topic));
713 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
714 silc_client_command_reply_free(cmd);
717 /* Received reply to invite command. */
719 SILC_CLIENT_CMD_REPLY_FUNC(invite)
721 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
722 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
723 SilcCommandStatus status;
724 SilcChannelEntry channel;
725 SilcChannelID *channel_id;
729 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
730 SILC_GET16_MSB(status, tmp);
731 if (status != SILC_STATUS_OK) {
732 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
733 "%s", silc_client_command_status_message(status));
738 /* Take Channel ID */
739 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
743 channel_id = silc_id_payload_parse_id(tmp, len);
747 /* Get the channel entry */
748 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
750 silc_free(channel_id);
755 /* Get the invite list */
756 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
758 /* Notify application */
759 COMMAND_REPLY((ARGS, channel, tmp));
762 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
763 silc_client_command_reply_free(cmd);
766 /* Received reply to the KILL command. */
768 SILC_CLIENT_CMD_REPLY_FUNC(kill)
770 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
771 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
772 SilcCommandStatus status;
774 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
775 if (status != SILC_STATUS_OK) {
776 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
777 "%s", silc_client_command_status_message(status));
782 /* Notify application */
783 COMMAND_REPLY((ARGS));
786 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
787 silc_client_command_reply_free(cmd);
790 /* Received reply to INFO command. We receive the server ID and some
791 information about the server user requested. */
793 SILC_CLIENT_CMD_REPLY_FUNC(info)
795 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
796 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
797 SilcCommandStatus status;
799 SilcIDCacheEntry id_cache;
800 SilcServerEntry server;
801 SilcServerID *server_id = NULL;
802 char *server_name, *server_info;
805 SILC_LOG_DEBUG(("Start"));
807 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
808 SILC_GET16_MSB(status, tmp);
809 if (status != SILC_STATUS_OK) {
810 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
811 silc_client_command_status_message(status));
817 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
821 server_id = silc_id_payload_parse_id(tmp, len);
825 /* Get server name */
826 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
830 /* Get server info */
831 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
835 /* See whether we have this server cached. If not create it. */
836 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
838 SILC_LOG_DEBUG(("New server entry"));
840 server = silc_calloc(1, sizeof(*server));
841 server->server_name = strdup(server_name);
842 server->server_info = strdup(server_info);
843 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
845 /* Add it to the cache */
846 silc_idcache_add(conn->server_cache, server->server_name,
847 server->server_id, (void *)server, 0, NULL);
849 server = (SilcServerEntry)id_cache->context;
852 /* Notify application */
853 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
856 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
857 silc_free(server_id);
858 silc_client_command_reply_free(cmd);
861 /* Received reply to PING command. The reply time is shown to user. */
863 SILC_CLIENT_CMD_REPLY_FUNC(ping)
865 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
866 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
867 SilcCommandStatus status;
870 time_t diff, curtime;
872 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
873 if (status != SILC_STATUS_OK) {
874 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
875 "%s", silc_client_command_status_message(status));
880 curtime = time(NULL);
881 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
882 cmd->packet->src_id_type);
883 if (!id || !conn->ping) {
888 for (i = 0; i < conn->ping_count; i++) {
889 if (!conn->ping[i].dest_id)
891 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
892 diff = curtime - conn->ping[i].start_time;
893 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
894 "Ping reply from %s: %d second%s",
895 conn->ping[i].dest_name, diff,
896 diff == 1 ? "" : "s");
898 conn->ping[i].start_time = 0;
899 silc_free(conn->ping[i].dest_id);
900 conn->ping[i].dest_id = NULL;
901 silc_free(conn->ping[i].dest_name);
902 conn->ping[i].dest_name = NULL;
909 /* Notify application */
910 COMMAND_REPLY((ARGS));
913 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
914 silc_client_command_reply_free(cmd);
917 /* Received reply for JOIN command. */
919 SILC_CLIENT_CMD_REPLY_FUNC(join)
921 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
922 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
923 SilcCommandStatus status;
924 SilcChannelEntry channel;
926 SilcChannelID *channel_id;
927 uint32 argc, mode = 0, len, list_count;
928 char *topic, *tmp, *channel_name = NULL, *hmac;
929 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
932 SILC_LOG_DEBUG(("Start"));
934 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
935 if (status != SILC_STATUS_OK) {
936 if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
937 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
938 "%s", silc_client_command_status_message(status));
943 argc = silc_argument_get_arg_num(cmd->args);
944 if (argc < 7 || argc > 14) {
945 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
946 "Cannot join channel: Bad reply packet");
951 /* Get channel name */
952 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
954 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
955 "Cannot join channel: Bad reply packet");
962 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
964 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
965 "Cannot join channel: Bad reply packet");
969 channel_id = silc_id_payload_parse_id(tmp, len);
975 /* Get channel mode */
976 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
978 SILC_GET32_MSB(mode, tmp);
980 /* Get channel key */
981 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
983 keyp = silc_buffer_alloc(len);
984 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
985 silc_buffer_put(keyp, tmp, len);
989 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
991 /* Check whether we have this channel entry already. */
992 channel = silc_client_get_channel(cmd->client, conn, channel_name);
994 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
995 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
997 /* Create new channel entry */
998 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1002 conn->current_channel = channel;
1005 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1007 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1008 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1009 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1010 COMMAND_REPLY_ERROR;
1015 /* Get the list count */
1016 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1019 SILC_GET32_MSB(list_count, tmp);
1021 /* Get Client ID list */
1022 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1026 client_id_list = silc_buffer_alloc(len);
1027 silc_buffer_pull_tail(client_id_list, len);
1028 silc_buffer_put(client_id_list, tmp, len);
1030 /* Get client mode list */
1031 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1035 client_mode_list = silc_buffer_alloc(len);
1036 silc_buffer_pull_tail(client_mode_list, len);
1037 silc_buffer_put(client_mode_list, tmp, len);
1039 /* Add clients we received in the reply to the channel */
1040 for (i = 0; i < list_count; i++) {
1043 SilcClientID *client_id;
1044 SilcClientEntry client_entry;
1047 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1049 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1054 SILC_GET32_MSB(mode, client_mode_list->data);
1056 /* Check if we have this client cached already. */
1057 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1058 if (!client_entry) {
1059 /* No, we don't have it, add entry for it. */
1061 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1062 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1065 /* Join client to the channel */
1066 chu = silc_calloc(1, sizeof(*chu));
1067 chu->client = client_entry;
1068 chu->channel = channel;
1070 silc_hash_table_add(channel->user_list, client_entry, chu);
1071 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;
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 uint32 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 uint32 tmp_len, list_count;
1603 unsigned char **res_argv = NULL;
1604 uint32 *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;
1719 chu->channel = channel;
1720 silc_hash_table_add(channel->user_list, client_entry, chu);
1721 silc_hash_table_add(client_entry->channels, channel, chu);
1725 silc_free(client_id);
1726 silc_buffer_pull(client_id_list, idp_len);
1727 silc_buffer_pull(client_mode_list, 4);
1730 /* Query the client information from server if the list included clients
1731 that we don't know about. */
1735 /* Send the WHOIS command to server */
1736 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1737 silc_client_command_reply_whois_i, 0,
1739 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1740 res_argc, res_argv, res_argv_lens,
1741 res_argv_types, conn->cmd_ident);
1742 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1743 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1746 /* Register pending command callback. After we've received the WHOIS
1747 command reply we will reprocess this command reply by re-calling this
1748 USERS command reply callback. */
1749 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1750 silc_client_command_reply_users, cmd);
1752 silc_buffer_free(res_cmd);
1753 silc_free(channel_id);
1754 silc_free(res_argv);
1755 silc_free(res_argv_lens);
1756 silc_free(res_argv_types);
1758 silc_buffer_free(client_id_list);
1759 if (client_mode_list)
1760 silc_buffer_free(client_mode_list);
1764 silc_buffer_push(client_id_list, (client_id_list->data -
1765 client_id_list->head));
1766 silc_buffer_push(client_mode_list, (client_mode_list->data -
1767 client_mode_list->head));
1769 /* Notify application */
1770 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1773 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1774 silc_client_command_reply_free(cmd);
1775 silc_free(channel_id);
1777 silc_buffer_free(client_id_list);
1778 if (client_mode_list)
1779 silc_buffer_free(client_mode_list);
1782 /* Received command reply to GETKEY command. WE've received the remote
1783 client's public key. */
1785 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1787 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1788 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1789 SilcCommandStatus status;
1790 SilcIDCacheEntry id_cache;
1791 SilcIDPayload idp = NULL;
1792 SilcClientID *client_id = NULL;
1793 SilcClientEntry client_entry;
1794 SilcServerID *server_id = NULL;
1795 SilcServerEntry server_entry;
1797 unsigned char *tmp, *pk;
1801 SilcPublicKey public_key = NULL;
1803 SILC_LOG_DEBUG(("Start"));
1805 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1806 SILC_GET16_MSB(status, tmp);
1807 if (status != SILC_STATUS_OK) {
1808 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1809 "%s", silc_client_command_status_message(status));
1810 COMMAND_REPLY_ERROR;
1814 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1816 COMMAND_REPLY_ERROR;
1819 idp = silc_id_payload_parse(tmp, len);
1821 COMMAND_REPLY_ERROR;
1825 /* Get the public key payload */
1826 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1828 /* Decode the public key */
1829 SILC_GET16_MSB(pk_len, tmp);
1830 SILC_GET16_MSB(type, tmp + 2);
1833 if (type == SILC_SKE_PK_TYPE_SILC)
1834 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1838 id_type = silc_id_payload_get_type(idp);
1839 if (id_type == SILC_ID_CLIENT) {
1840 /* Received client's public key */
1841 client_id = silc_id_payload_get_id(idp);
1842 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1843 if (!client_entry) {
1844 COMMAND_REPLY_ERROR;
1848 /* Notify application */
1849 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1850 } else if (id_type == SILC_ID_SERVER) {
1851 /* Received server's public key */
1852 server_id = silc_id_payload_get_id(idp);
1853 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1855 COMMAND_REPLY_ERROR;
1859 server_entry = (SilcServerEntry)id_cache->context;
1861 /* Notify application */
1862 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1866 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1868 silc_id_payload_free(idp);
1870 silc_pkcs_public_key_free(public_key);
1871 silc_free(client_id);
1872 silc_free(server_id);
1873 silc_client_command_reply_free(cmd);
1876 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1878 silc_client_command_reply_free(context);
1882 /******************************************************************************
1884 Internal command reply functions
1886 ******************************************************************************/
1888 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1890 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1891 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1892 SilcCommandStatus status;
1894 SILC_LOG_DEBUG(("Start"));
1896 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1897 if (status != SILC_STATUS_OK &&
1898 status != SILC_STATUS_LIST_START &&
1899 status != SILC_STATUS_LIST_ITEM &&
1900 status != SILC_STATUS_LIST_END)
1903 /* Save WHOIS info */
1904 silc_client_command_reply_whois_save(cmd, status, FALSE);
1906 /* Pending callbacks are not executed if this was an list entry */
1907 if (status != SILC_STATUS_OK &&
1908 status != SILC_STATUS_LIST_END) {
1909 silc_client_command_reply_free(cmd);
1914 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1916 /* If we received notify for invalid ID we'll remove the ID if we
1918 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1919 SilcClientEntry client_entry;
1921 unsigned char *tmp =
1922 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1925 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1927 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1930 silc_client_del_client(cmd->client, conn, client_entry);
1931 silc_free(client_id);
1936 /* Unregister this command reply */
1937 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1938 NULL, silc_client_command_reply_whois_i,
1941 silc_client_command_reply_free(cmd);
1944 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1946 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1947 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1948 SilcCommandStatus status;
1950 SILC_LOG_DEBUG(("Start"));
1952 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1953 if (status != SILC_STATUS_OK &&
1954 status != SILC_STATUS_LIST_START &&
1955 status != SILC_STATUS_LIST_ITEM &&
1956 status != SILC_STATUS_LIST_END)
1959 /* Save IDENTIFY info */
1960 silc_client_command_reply_identify_save(cmd, status, FALSE);
1962 /* Pending callbacks are not executed if this was an list entry */
1963 if (status != SILC_STATUS_OK &&
1964 status != SILC_STATUS_LIST_END) {
1965 silc_client_command_reply_free(cmd);
1970 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1972 /* If we received notify for invalid ID we'll remove the ID if we
1974 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1975 SilcClientEntry client_entry;
1977 unsigned char *tmp =
1978 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1981 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1983 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1986 silc_client_del_client(cmd->client, conn, client_entry);
1987 silc_free(client_id);
1992 /* Unregister this command reply */
1993 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1994 NULL, silc_client_command_reply_identify_i,
1997 silc_client_command_reply_free(cmd);
2000 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2002 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2003 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2004 SilcCommandStatus status;
2006 SilcIDCacheEntry id_cache;
2007 SilcServerEntry server;
2008 SilcServerID *server_id = NULL;
2009 char *server_name, *server_info;
2012 SILC_LOG_DEBUG(("Start"));
2014 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
2015 SILC_GET16_MSB(status, tmp);
2016 if (status != SILC_STATUS_OK)
2020 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2024 server_id = silc_id_payload_parse_id(tmp, len);
2028 /* Get server name */
2029 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2033 /* Get server info */
2034 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2038 /* See whether we have this server cached. If not create it. */
2039 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
2041 SILC_LOG_DEBUG(("New server entry"));
2042 server = silc_calloc(1, sizeof(*server));
2043 server->server_name = strdup(server_name);
2044 server->server_info = strdup(server_info);
2045 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
2047 /* Add it to the cache */
2048 silc_idcache_add(conn->server_cache, server->server_name,
2049 server->server_id, (void *)server, 0, NULL);
2053 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2054 silc_free(server_id);
2055 silc_client_command_reply_free(cmd);