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 SilcIDCacheEntry id_cache = NULL;
215 SilcClientEntry client_entry = NULL;
218 unsigned char *id_data, *tmp;
219 char *nickname = NULL, *username = NULL;
220 char *realname = NULL;
221 uint32 idle = 0, mode = 0;
222 SilcBuffer channels = NULL;
223 unsigned char *fingerprint;
224 uint32 fingerprint_len;
226 argc = silc_argument_get_arg_num(cmd->args);
228 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
235 client_id = silc_id_payload_parse_id(id_data, len);
242 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
243 username = silc_argument_get_arg_type(cmd->args, 4, &len);
244 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
245 if (!nickname || !username || !realname) {
251 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
253 channels = silc_buffer_alloc(len);
254 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
255 silc_buffer_put(channels, tmp, len);
258 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
260 SILC_GET32_MSB(mode, tmp);
262 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
264 SILC_GET32_MSB(idle, tmp);
266 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
268 /* Check if we have this client cached already. */
269 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
271 silc_hash_client_id_compare, NULL,
273 SILC_LOG_DEBUG(("Adding new client entry"));
275 silc_client_add_client(cmd->client, conn, nickname, username, realname,
278 client_entry = (SilcClientEntry)id_cache->context;
279 silc_client_update_client(cmd->client, conn, client_entry,
280 nickname, username, realname, mode);
281 silc_free(client_id);
284 if (fingerprint && !client_entry->fingerprint) {
285 client_entry->fingerprint =
286 silc_calloc(fingerprint_len,
287 sizeof(*client_entry->fingerprint));
288 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
289 client_entry->fingerprint_len = fingerprint_len;
292 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
293 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
295 /* Notify application */
296 if (!cmd->callback && notify)
297 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
298 channels, mode, idle, fingerprint));
301 silc_buffer_free(channels);
304 /* Received reply for WHOIS command. This maybe called several times
305 for one WHOIS command as server may reply with list of results. */
307 SILC_CLIENT_CMD_REPLY_FUNC(whois)
309 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
310 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
311 SilcCommandStatus status;
313 COMMAND_CHECK_STATUS_LIST;
315 /* Save WHOIS info */
316 silc_client_command_reply_whois_save(cmd, status, TRUE);
318 /* Pending callbacks are not executed if this was an list entry */
319 if (status != SILC_STATUS_OK &&
320 status != SILC_STATUS_LIST_END) {
321 silc_client_command_reply_free(cmd);
326 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
328 /* If we received notify for invalid ID we'll remove the ID if we
330 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
331 SilcClientEntry client_entry;
334 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
337 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
339 client_entry = silc_client_get_client_by_id(cmd->client, conn,
342 silc_client_del_client(cmd->client, conn, client_entry);
343 silc_free(client_id);
348 silc_client_command_reply_free(cmd);
351 /* Received reply for WHOWAS command. */
353 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
355 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
356 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
357 SilcCommandStatus status;
358 SilcClientID *client_id;
359 SilcIDCacheEntry id_cache = NULL;
360 SilcClientEntry client_entry = NULL;
362 unsigned char *id_data;
363 char *nickname, *username;
364 char *realname = NULL;
366 COMMAND_CHECK_STATUS_LIST;
368 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
374 client_id = silc_id_payload_parse_id(id_data, len);
380 /* Get the client entry, if exists */
381 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
383 silc_hash_client_id_compare, NULL,
385 client_entry = (SilcClientEntry)id_cache->context;
386 silc_free(client_id);
388 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
389 username = silc_argument_get_arg_type(cmd->args, 4, &len);
390 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
391 if (!nickname || !username) {
396 /* Notify application. We don't save any history information to any
397 cache. Just pass the data to the application for displaying on
399 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
401 /* Pending callbacks are not executed if this was an list entry */
402 if (status != SILC_STATUS_OK &&
403 status != SILC_STATUS_LIST_END) {
404 silc_client_command_reply_free(cmd);
409 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
410 silc_client_command_reply_free(cmd);
414 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
415 SilcCommandStatus status,
418 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
419 SilcClient client = cmd->client;
420 SilcClientID *client_id = NULL;
421 SilcServerID *server_id = NULL;
422 SilcChannelID *channel_id = NULL;
423 SilcIDCacheEntry id_cache = NULL;
424 SilcClientEntry client_entry;
425 SilcServerEntry server_entry;
426 SilcChannelEntry channel_entry;
429 unsigned char *id_data;
430 char *name = NULL, *info = NULL;
431 SilcIDPayload idp = NULL;
434 argc = silc_argument_get_arg_num(cmd->args);
436 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
442 idp = silc_id_payload_parse(id_data, len);
449 name = silc_argument_get_arg_type(cmd->args, 3, &len);
450 info = silc_argument_get_arg_type(cmd->args, 4, &len);
452 id_type = silc_id_payload_get_type(idp);
456 client_id = silc_id_payload_get_id(idp);
458 SILC_LOG_DEBUG(("Received client information"));
460 /* Check if we have this client cached already. */
461 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
464 silc_hash_client_id_compare, NULL,
466 SILC_LOG_DEBUG(("Adding new client entry"));
468 silc_client_add_client(cmd->client, conn, name, info, NULL,
469 silc_id_dup(client_id, id_type), 0);
471 client_entry = (SilcClientEntry)id_cache->context;
472 silc_client_update_client(cmd->client, conn, client_entry,
473 name, info, NULL, 0);
476 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
477 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
479 /* Notify application */
481 COMMAND_REPLY((ARGS, client_entry, name, info));
485 server_id = silc_id_payload_get_id(idp);
487 SILC_LOG_DEBUG(("Received server information"));
489 /* Check if we have this server cached already. */
490 if (!silc_idcache_find_by_id_one(conn->server_cache,
491 (void *)server_id, &id_cache)) {
492 SILC_LOG_DEBUG(("Adding new server entry"));
494 server_entry = silc_calloc(1, sizeof(*server_entry));
495 server_entry->server_id = silc_id_dup(server_id, id_type);
497 server_entry->server_name = strdup(name);
499 server_entry->server_info = strdup(info);
501 /* Add server to cache */
502 silc_idcache_add(conn->server_cache, server_entry->server_name,
503 server_entry->server_id, (void *)server_entry,
506 server_entry = (SilcServerEntry)id_cache->context;
509 /* Notify application */
511 COMMAND_REPLY((ARGS, server_entry, name, info));
514 case SILC_ID_CHANNEL:
515 channel_id = silc_id_payload_get_id(idp);
517 SILC_LOG_DEBUG(("Received channel information"));
519 /* Check if we have this channel cached already. */
520 if (!silc_idcache_find_by_id_one(conn->channel_cache,
521 (void *)channel_id, &id_cache)) {
525 SILC_LOG_DEBUG(("Adding new channel entry"));
526 channel_entry = silc_client_new_channel_id(client, conn->sock,
527 strdup(name), 0, idp);
529 channel_entry = (SilcChannelEntry)id_cache->context;
532 /* Notify application */
534 COMMAND_REPLY((ARGS, channel_entry, name, info));
538 silc_id_payload_free(idp);
539 silc_free(client_id);
540 silc_free(server_id);
541 silc_free(channel_id);
544 /* Received reply for IDENTIFY command. This maybe called several times
545 for one IDENTIFY command as server may reply with list of results.
546 This is totally silent and does not print anything on screen. */
548 SILC_CLIENT_CMD_REPLY_FUNC(identify)
550 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
551 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
552 SilcCommandStatus status;
554 COMMAND_CHECK_STATUS_LIST;
556 /* Save IDENTIFY info */
557 silc_client_command_reply_identify_save(cmd, status, TRUE);
559 /* Pending callbacks are not executed if this was an list entry */
560 if (status != SILC_STATUS_OK &&
561 status != SILC_STATUS_LIST_END) {
562 silc_client_command_reply_free(cmd);
567 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
569 /* If we received notify for invalid ID we'll remove the ID if we
571 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
572 SilcClientEntry client_entry;
575 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
578 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
580 client_entry = silc_client_get_client_by_id(cmd->client, conn,
583 silc_client_del_client(cmd->client, conn, client_entry);
584 silc_free(client_id);
589 silc_client_command_reply_free(cmd);
592 /* Received reply for command NICK. If everything went without errors
593 we just received our new Client ID. */
595 SILC_CLIENT_CMD_REPLY_FUNC(nick)
597 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
598 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
599 SilcCommandStatus status;
604 SILC_LOG_DEBUG(("Start"));
606 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
607 if (status != SILC_STATUS_OK) {
608 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
609 "Cannot set nickname: %s", silc_client_command_status_message(status));
614 argc = silc_argument_get_arg_num(cmd->args);
615 if (argc < 2 || argc > 2) {
616 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
617 "Cannot set nickname: bad reply to command");
622 /* Take received Client ID */
623 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
624 idp = silc_id_payload_parse(tmp, len);
629 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
631 /* Notify application */
632 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
633 COMMAND_REPLY((ARGS, conn->local_entry));
634 silc_client_command_reply_free(cmd);
638 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
639 silc_client_command_reply_free(cmd);
642 /* Received reply to the LIST command. */
644 SILC_CLIENT_CMD_REPLY_FUNC(list)
646 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
647 SilcCommandStatus status;
648 unsigned char *tmp, *name, *topic;
649 uint32 usercount = 0;
651 COMMAND_CHECK_STATUS_LIST;
653 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
654 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
655 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
657 SILC_GET32_MSB(usercount, tmp);
659 /* Notify application */
660 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
662 /* Pending callbacks are not executed if this was an list entry */
663 if (status != SILC_STATUS_OK &&
664 status != SILC_STATUS_LIST_END) {
665 silc_client_command_reply_free(cmd);
670 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
671 silc_client_command_reply_free(cmd);
674 /* Received reply to topic command. */
676 SILC_CLIENT_CMD_REPLY_FUNC(topic)
678 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
679 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
680 SilcCommandStatus status;
681 SilcChannelEntry channel;
682 SilcChannelID *channel_id = NULL;
683 SilcIDCacheEntry id_cache = NULL;
688 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
689 if (status != SILC_STATUS_OK) {
690 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
691 "%s", silc_client_command_status_message(status));
696 argc = silc_argument_get_arg_num(cmd->args);
697 if (argc < 1 || argc > 3) {
702 /* Take Channel ID */
703 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
708 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
712 channel_id = silc_id_payload_parse_id(tmp, len);
716 /* Get the channel entry */
717 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
719 silc_free(channel_id);
724 channel = (SilcChannelEntry)id_cache->context;
726 /* Notify application */
727 COMMAND_REPLY((ARGS, channel, topic));
730 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
731 silc_client_command_reply_free(cmd);
734 /* Received reply to invite command. */
736 SILC_CLIENT_CMD_REPLY_FUNC(invite)
738 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
739 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
740 SilcCommandStatus status;
741 SilcChannelEntry channel;
742 SilcChannelID *channel_id;
743 SilcIDCacheEntry id_cache;
747 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
748 SILC_GET16_MSB(status, tmp);
749 if (status != SILC_STATUS_OK) {
750 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
751 "%s", silc_client_command_status_message(status));
756 /* Take Channel ID */
757 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
761 channel_id = silc_id_payload_parse_id(tmp, len);
765 /* Get the channel entry */
766 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
768 silc_free(channel_id);
773 channel = (SilcChannelEntry)id_cache->context;
775 /* Get the invite list */
776 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
778 /* Notify application */
779 COMMAND_REPLY((ARGS, channel, tmp));
782 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
783 silc_client_command_reply_free(cmd);
786 /* Received reply to the KILL command. */
788 SILC_CLIENT_CMD_REPLY_FUNC(kill)
790 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
791 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
792 SilcCommandStatus status;
794 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
795 if (status != SILC_STATUS_OK) {
796 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
797 "%s", silc_client_command_status_message(status));
802 /* Notify application */
803 COMMAND_REPLY((ARGS));
806 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
807 silc_client_command_reply_free(cmd);
810 /* Received reply to INFO command. We receive the server ID and some
811 information about the server user requested. */
813 SILC_CLIENT_CMD_REPLY_FUNC(info)
815 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
816 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
817 SilcCommandStatus status;
819 SilcIDCacheEntry id_cache;
820 SilcServerEntry server;
821 SilcServerID *server_id = NULL;
822 char *server_name, *server_info;
825 SILC_LOG_DEBUG(("Start"));
827 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
828 SILC_GET16_MSB(status, tmp);
829 if (status != SILC_STATUS_OK) {
830 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
831 silc_client_command_status_message(status));
837 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
841 server_id = silc_id_payload_parse_id(tmp, len);
845 /* Get server name */
846 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
850 /* Get server info */
851 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
855 /* See whether we have this server cached. If not create it. */
856 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
858 SILC_LOG_DEBUG(("New server entry"));
860 server = silc_calloc(1, sizeof(*server));
861 server->server_name = strdup(server_name);
862 server->server_info = strdup(server_info);
863 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
865 /* Add it to the cache */
866 silc_idcache_add(conn->server_cache, server->server_name,
867 server->server_id, (void *)server, 0, NULL);
869 server = (SilcServerEntry)id_cache->context;
872 /* Notify application */
873 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
876 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
877 silc_free(server_id);
878 silc_client_command_reply_free(cmd);
881 /* Received reply to PING command. The reply time is shown to user. */
883 SILC_CLIENT_CMD_REPLY_FUNC(ping)
885 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
886 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
887 SilcCommandStatus status;
890 time_t diff, curtime;
892 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
893 if (status != SILC_STATUS_OK) {
894 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
895 "%s", silc_client_command_status_message(status));
900 curtime = time(NULL);
901 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
902 cmd->packet->src_id_type);
903 if (!id || !conn->ping) {
908 for (i = 0; i < conn->ping_count; i++) {
909 if (!conn->ping[i].dest_id)
911 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
912 diff = curtime - conn->ping[i].start_time;
913 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
914 "Ping reply from %s: %d second%s",
915 conn->ping[i].dest_name, diff,
916 diff == 1 ? "" : "s");
918 conn->ping[i].start_time = 0;
919 silc_free(conn->ping[i].dest_id);
920 conn->ping[i].dest_id = NULL;
921 silc_free(conn->ping[i].dest_name);
922 conn->ping[i].dest_name = NULL;
929 /* Notify application */
930 COMMAND_REPLY((ARGS));
933 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
934 silc_client_command_reply_free(cmd);
937 /* Received reply for JOIN command. */
939 SILC_CLIENT_CMD_REPLY_FUNC(join)
941 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
942 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
943 SilcCommandStatus status;
944 SilcIDPayload idp = NULL;
945 SilcChannelEntry channel;
946 SilcIDCacheEntry id_cache = NULL;
948 uint32 argc, mode, len, list_count;
949 char *topic, *tmp, *channel_name = NULL, *hmac;
950 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
953 SILC_LOG_DEBUG(("Start"));
955 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
956 if (status != SILC_STATUS_OK) {
957 if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
958 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
959 "%s", silc_client_command_status_message(status));
964 argc = silc_argument_get_arg_num(cmd->args);
965 if (argc < 7 || argc > 14) {
966 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
967 "Cannot join channel: Bad reply packet");
972 /* Get channel name */
973 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
975 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
976 "Cannot join channel: Bad reply packet");
980 channel_name = strdup(tmp);
983 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
985 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
986 "Cannot join channel: Bad reply packet");
988 silc_free(channel_name);
991 idp = silc_id_payload_parse(tmp, len);
994 silc_free(channel_name);
998 /* Get channel mode */
999 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1001 SILC_GET32_MSB(mode, tmp);
1005 /* Get channel key */
1006 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1008 keyp = silc_buffer_alloc(len);
1009 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1010 silc_buffer_put(keyp, tmp, len);
1014 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1016 /* If we have the channel entry, remove it and create a new one */
1017 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1019 silc_client_del_channel(cmd->client, conn, channel);
1021 /* Save received Channel ID. This actually creates the channel */
1022 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
1024 silc_id_payload_free(idp);
1026 conn->current_channel = channel;
1029 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1031 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1032 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1033 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1034 COMMAND_REPLY_ERROR;
1035 silc_free(channel_name);
1040 /* Get the list count */
1041 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1044 SILC_GET32_MSB(list_count, tmp);
1046 /* Get Client ID list */
1047 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1051 client_id_list = silc_buffer_alloc(len);
1052 silc_buffer_pull_tail(client_id_list, len);
1053 silc_buffer_put(client_id_list, tmp, len);
1055 /* Get client mode list */
1056 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1060 client_mode_list = silc_buffer_alloc(len);
1061 silc_buffer_pull_tail(client_mode_list, len);
1062 silc_buffer_put(client_mode_list, tmp, len);
1064 /* Add clients we received in the reply to the channel */
1065 for (i = 0; i < list_count; i++) {
1068 SilcClientID *client_id;
1069 SilcClientEntry client_entry;
1072 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1074 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1079 SILC_GET32_MSB(mode, client_mode_list->data);
1081 /* Check if we have this client cached already. */
1082 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1085 silc_hash_client_id_compare, NULL,
1087 /* No, we don't have it, add entry for it. */
1089 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1090 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1092 /* Yes, we have it already */
1093 client_entry = (SilcClientEntry)id_cache->context;
1096 /* Join the client to the channel */
1097 chu = silc_calloc(1, sizeof(*chu));
1098 chu->client = client_entry;
1100 silc_list_add(channel->clients, chu);
1101 silc_free(client_id);
1103 silc_buffer_pull(client_id_list, idp_len);
1104 silc_buffer_pull(client_mode_list, 4);
1106 silc_buffer_push(client_id_list, client_id_list->data -
1107 client_id_list->head);
1108 silc_buffer_push(client_mode_list, client_mode_list->data -
1109 client_mode_list->head);
1111 /* Save channel key */
1112 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1113 silc_client_save_channel_key(conn, keyp, channel);
1115 /* Client is now joined to the channel */
1116 channel->on_channel = TRUE;
1118 /* Notify application */
1119 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1120 keyp ? keyp->head : NULL, NULL,
1121 NULL, topic, hmac, list_count, client_id_list,
1125 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1126 silc_client_command_reply_free(cmd);
1129 silc_buffer_free(keyp);
1131 silc_buffer_free(client_id_list);
1132 if (client_mode_list)
1133 silc_buffer_free(client_mode_list);
1136 /* Received reply for MOTD command */
1138 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1140 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1141 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1142 SilcCommandStatus status;
1145 char *motd = NULL, *cp, line[256];
1147 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1148 SILC_GET16_MSB(status, tmp);
1149 if (status != SILC_STATUS_OK) {
1150 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1151 "%s", silc_client_command_status_message(status));
1152 COMMAND_REPLY_ERROR;
1156 argc = silc_argument_get_arg_num(cmd->args);
1158 COMMAND_REPLY_ERROR;
1163 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1165 COMMAND_REPLY_ERROR;
1172 if (cp[i++] == '\n') {
1173 memset(line, 0, sizeof(line));
1174 strncat(line, cp, i - 1);
1180 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1189 /* Notify application */
1190 COMMAND_REPLY((ARGS, motd));
1193 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1194 silc_client_command_reply_free(cmd);
1197 /* Received reply tot he UMODE command. Save the current user mode */
1199 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1201 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1202 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1203 SilcCommandStatus status;
1207 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1208 SILC_GET16_MSB(status, tmp);
1209 if (status != SILC_STATUS_OK) {
1210 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1211 "%s", silc_client_command_status_message(status));
1212 COMMAND_REPLY_ERROR;
1216 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1218 COMMAND_REPLY_ERROR;
1222 SILC_GET32_MSB(mode, tmp);
1223 conn->local_entry->mode = mode;
1225 /* Notify application */
1226 COMMAND_REPLY((ARGS, mode));
1229 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1230 silc_client_command_reply_free(cmd);
1233 /* Received reply for CMODE command. */
1235 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1237 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1238 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1239 SilcCommandStatus status;
1242 SilcIDCacheEntry id_cache;
1243 SilcChannelID *channel_id;
1244 SilcChannelEntry channel;
1247 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1248 if (status != SILC_STATUS_OK) {
1249 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1250 "%s", silc_client_command_status_message(status));
1251 COMMAND_REPLY_ERROR;
1255 /* Take Channel ID */
1256 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1259 channel_id = silc_id_payload_parse_id(tmp, len);
1263 /* Get the channel entry */
1264 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1266 silc_free(channel_id);
1267 COMMAND_REPLY_ERROR;
1271 channel = (SilcChannelEntry)id_cache->context;
1273 /* Get channel mode */
1274 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1276 silc_free(channel_id);
1277 COMMAND_REPLY_ERROR;
1282 SILC_GET32_MSB(mode, tmp);
1283 channel->mode = mode;
1285 /* Notify application */
1286 COMMAND_REPLY((ARGS, channel, mode));
1288 silc_free(channel_id);
1291 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1292 silc_client_command_reply_free(cmd);
1295 /* Received reply for CUMODE command */
1297 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1299 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1300 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1301 SilcCommandStatus status;
1302 SilcIDCacheEntry id_cache = NULL;
1303 SilcClientID *client_id;
1304 SilcChannelID *channel_id;
1305 SilcClientEntry client_entry;
1306 SilcChannelEntry channel;
1307 SilcChannelUser chu;
1308 unsigned char *modev, *tmp, *id;
1311 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1312 if (status != SILC_STATUS_OK) {
1313 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1314 "%s", silc_client_command_status_message(status));
1315 COMMAND_REPLY_ERROR;
1319 /* Get channel mode */
1320 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1322 COMMAND_REPLY_ERROR;
1326 /* Take Channel ID */
1327 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1330 channel_id = silc_id_payload_parse_id(tmp, len);
1334 /* Get the channel entry */
1335 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1337 silc_free(channel_id);
1338 COMMAND_REPLY_ERROR;
1342 channel = (SilcChannelEntry)id_cache->context;
1345 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1347 silc_free(channel_id);
1348 COMMAND_REPLY_ERROR;
1351 client_id = silc_id_payload_parse_id(id, len);
1353 silc_free(channel_id);
1354 COMMAND_REPLY_ERROR;
1358 /* Get client entry */
1359 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1361 silc_hash_client_id_compare, NULL,
1363 silc_free(channel_id);
1364 silc_free(client_id);
1365 COMMAND_REPLY_ERROR;
1369 client_entry = (SilcClientEntry)id_cache->context;
1372 SILC_GET32_MSB(mode, modev);
1373 silc_list_start(channel->clients);
1374 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1375 if (chu->client == client_entry) {
1381 /* Notify application */
1382 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1383 silc_free(client_id);
1384 silc_free(channel_id);
1387 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1388 silc_client_command_reply_free(cmd);
1391 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1393 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1394 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1395 SilcCommandStatus status;
1398 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1399 SILC_GET16_MSB(status, tmp);
1400 if (status != SILC_STATUS_OK) {
1401 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1402 "%s", silc_client_command_status_message(status));
1403 COMMAND_REPLY_ERROR;
1407 /* Notify application */
1408 COMMAND_REPLY((ARGS));
1411 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1412 silc_client_command_reply_free(cmd);
1415 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1417 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1418 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1419 SilcCommandStatus status;
1422 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1423 SILC_GET16_MSB(status, tmp);
1424 if (status != SILC_STATUS_OK) {
1425 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1426 "%s", silc_client_command_status_message(status));
1427 COMMAND_REPLY_ERROR;
1431 /* Notify application */
1432 COMMAND_REPLY((ARGS));
1435 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1436 silc_client_command_reply_free(cmd);
1439 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1441 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1442 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1443 SilcCommandStatus status;
1446 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1447 SILC_GET16_MSB(status, tmp);
1448 if (status != SILC_STATUS_OK) {
1449 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1450 "%s", silc_client_command_status_message(status));
1451 COMMAND_REPLY_ERROR;
1455 /* Notify application */
1456 COMMAND_REPLY((ARGS));
1459 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1460 silc_client_command_reply_free(cmd);
1463 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1465 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1466 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1467 SilcCommandStatus status;
1470 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1471 SILC_GET16_MSB(status, tmp);
1472 if (status != SILC_STATUS_OK) {
1473 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1474 "%s", silc_client_command_status_message(status));
1475 COMMAND_REPLY_ERROR;
1479 /* Notify application */
1480 COMMAND_REPLY((ARGS));
1483 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1484 silc_client_command_reply_free(cmd);
1487 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1489 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1490 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1491 SilcCommandStatus status;
1492 SilcIDCacheEntry id_cache = NULL;
1493 SilcChannelEntry channel;
1494 SilcChannelID *channel_id;
1498 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1499 SILC_GET16_MSB(status, tmp);
1500 if (status != SILC_STATUS_OK) {
1501 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1502 "%s", silc_client_command_status_message(status));
1503 COMMAND_REPLY_ERROR;
1507 /* Take Channel ID */
1508 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1512 channel_id = silc_id_payload_parse_id(tmp, len);
1516 /* Get the channel entry */
1517 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1519 silc_free(channel_id);
1520 COMMAND_REPLY_ERROR;
1524 channel = (SilcChannelEntry)id_cache->context;
1526 /* Get the ban list */
1527 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1529 /* Notify application */
1530 COMMAND_REPLY((ARGS, channel, tmp));
1533 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1534 silc_client_command_reply_free(cmd);
1537 SILC_CLIENT_CMD_REPLY_FUNC(close)
1539 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1540 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1541 SilcCommandStatus status;
1544 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1545 SILC_GET16_MSB(status, tmp);
1546 if (status != SILC_STATUS_OK) {
1547 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1548 "%s", silc_client_command_status_message(status));
1549 COMMAND_REPLY_ERROR;
1553 /* Notify application */
1554 COMMAND_REPLY((ARGS));
1557 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1558 silc_client_command_reply_free(cmd);
1561 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1563 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1564 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1565 SilcCommandStatus status;
1568 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1569 SILC_GET16_MSB(status, tmp);
1570 if (status != SILC_STATUS_OK) {
1571 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1572 "%s", silc_client_command_status_message(status));
1573 COMMAND_REPLY_ERROR;
1577 /* Notify application */
1578 COMMAND_REPLY((ARGS));
1581 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1582 silc_client_command_reply_free(cmd);
1585 /* Reply to LEAVE command. */
1587 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1589 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1590 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1591 SilcCommandStatus status;
1594 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1595 SILC_GET16_MSB(status, tmp);
1596 if (status != SILC_STATUS_OK) {
1597 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1598 "%s", silc_client_command_status_message(status));
1599 COMMAND_REPLY_ERROR;
1603 /* Notify application */
1604 COMMAND_REPLY((ARGS));
1607 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1608 silc_client_command_reply_free(cmd);
1611 /* Reply to USERS command. Received list of client ID's and theirs modes
1612 on the channel we requested. */
1614 SILC_CLIENT_CMD_REPLY_FUNC(users)
1616 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1617 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1618 SilcCommandStatus status;
1619 SilcIDCacheEntry id_cache = NULL;
1620 SilcChannelEntry channel;
1621 SilcChannelUser chu;
1622 SilcChannelID *channel_id = NULL;
1623 SilcBuffer client_id_list = NULL;
1624 SilcBuffer client_mode_list = NULL;
1626 uint32 tmp_len, list_count;
1628 unsigned char **res_argv = NULL;
1629 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1631 SILC_LOG_DEBUG(("Start"));
1633 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1634 SILC_GET16_MSB(status, tmp);
1635 if (status != SILC_STATUS_OK) {
1636 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1637 "%s", silc_client_command_status_message(status));
1638 COMMAND_REPLY_ERROR;
1642 /* Get channel ID */
1643 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1645 COMMAND_REPLY_ERROR;
1648 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1650 COMMAND_REPLY_ERROR;
1654 /* Get the list count */
1655 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1657 COMMAND_REPLY_ERROR;
1660 SILC_GET32_MSB(list_count, tmp);
1662 /* Get Client ID list */
1663 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1665 COMMAND_REPLY_ERROR;
1669 client_id_list = silc_buffer_alloc(tmp_len);
1670 silc_buffer_pull_tail(client_id_list, tmp_len);
1671 silc_buffer_put(client_id_list, tmp, tmp_len);
1673 /* Get client mode list */
1674 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1676 COMMAND_REPLY_ERROR;
1680 client_mode_list = silc_buffer_alloc(tmp_len);
1681 silc_buffer_pull_tail(client_mode_list, tmp_len);
1682 silc_buffer_put(client_mode_list, tmp, tmp_len);
1684 /* Get channel entry */
1685 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1687 /* Resolve the channel from server */
1688 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1690 /* Register pending command callback. After we've received the channel
1691 information we will reprocess this command reply by re-calling this
1692 USERS command reply callback. */
1693 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1694 silc_client_command_reply_users, cmd);
1697 channel = (SilcChannelEntry)id_cache->context;
1700 /* Remove old client list from channel. */
1701 silc_list_start(channel->clients);
1702 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1703 silc_list_del(channel->clients, chu);
1707 /* Cache the received Client ID's and modes. */
1708 for (i = 0; i < list_count; i++) {
1711 SilcClientID *client_id;
1712 SilcClientEntry client;
1715 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1717 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1722 SILC_GET32_MSB(mode, client_mode_list->data);
1724 /* Check if we have this client cached already. */
1726 silc_idcache_find_by_id_one_ext(conn->client_cache,
1729 silc_hash_client_id_compare, NULL,
1732 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1733 !((SilcClientEntry)id_cache->context)->realname) {
1735 if (id_cache && id_cache->context) {
1736 SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
1737 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1738 silc_buffer_pull(client_id_list, idp_len);
1739 silc_buffer_pull(client_mode_list, 4);
1742 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1745 /* No we don't have it (or it is incomplete in information), query
1746 it from the server. Assemble argument table that will be sent
1747 for the WHOIS command later. */
1748 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1750 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1752 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1754 res_argv[res_argc] = client_id_list->data;
1755 res_argv_lens[res_argc] = idp_len;
1756 res_argv_types[res_argc] = res_argc + 3;
1759 /* Found the client, join it to the channel */
1760 client = (SilcClientEntry)id_cache->context;
1761 chu = silc_calloc(1, sizeof(*chu));
1762 chu->client = client;
1764 silc_list_add(channel->clients, chu);
1766 silc_free(client_id);
1770 silc_buffer_pull(client_id_list, idp_len);
1771 silc_buffer_pull(client_mode_list, 4);
1774 /* Query the client information from server if the list included clients
1775 that we don't know about. */
1779 /* Send the WHOIS command to server */
1780 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1781 silc_client_command_reply_whois_i, 0,
1783 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1784 res_argc, res_argv, res_argv_lens,
1785 res_argv_types, conn->cmd_ident);
1786 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1787 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1790 /* Register pending command callback. After we've received the WHOIS
1791 command reply we will reprocess this command reply by re-calling this
1792 USERS command reply callback. */
1793 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1794 silc_client_command_reply_users, cmd);
1796 silc_buffer_free(res_cmd);
1798 silc_free(channel_id);
1800 silc_free(res_argv);
1801 silc_free(res_argv_lens);
1802 silc_free(res_argv_types);
1806 /* Notify application */
1807 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1810 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1811 silc_client_command_reply_free(cmd);
1812 silc_free(channel_id);
1814 silc_buffer_free(client_id_list);
1815 if (client_mode_list)
1816 silc_buffer_free(client_mode_list);
1819 /* Received command reply to GETKEY command. WE've received the remote
1820 client's public key. */
1822 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1824 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1825 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1826 SilcCommandStatus status;
1827 SilcIDCacheEntry id_cache;
1828 SilcIDPayload idp = NULL;
1829 SilcClientID *client_id = NULL;
1830 SilcClientEntry client_entry;
1831 SilcServerID *server_id = NULL;
1832 SilcServerEntry server_entry;
1834 unsigned char *tmp, *pk;
1838 SilcPublicKey public_key = NULL;
1840 SILC_LOG_DEBUG(("Start"));
1842 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1843 SILC_GET16_MSB(status, tmp);
1844 if (status != SILC_STATUS_OK) {
1845 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1846 "%s", silc_client_command_status_message(status));
1847 COMMAND_REPLY_ERROR;
1851 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1853 COMMAND_REPLY_ERROR;
1856 idp = silc_id_payload_parse(tmp, len);
1858 COMMAND_REPLY_ERROR;
1862 /* Get the public key payload */
1863 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1865 /* Decode the public key */
1866 SILC_GET16_MSB(pk_len, tmp);
1867 SILC_GET16_MSB(type, tmp + 2);
1870 if (type == SILC_SKE_PK_TYPE_SILC)
1871 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1875 id_type = silc_id_payload_get_type(idp);
1876 if (id_type == SILC_ID_CLIENT) {
1877 /* Received client's public key */
1878 client_id = silc_id_payload_get_id(idp);
1879 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1882 silc_hash_client_id_compare, NULL,
1884 COMMAND_REPLY_ERROR;
1888 client_entry = (SilcClientEntry)id_cache->context;
1890 /* Notify application */
1891 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1892 } else if (id_type == SILC_ID_SERVER) {
1893 /* Received server's public key */
1894 server_id = silc_id_payload_get_id(idp);
1895 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1897 COMMAND_REPLY_ERROR;
1901 server_entry = (SilcServerEntry)id_cache->context;
1903 /* Notify application */
1904 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1908 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1910 silc_id_payload_free(idp);
1912 silc_pkcs_public_key_free(public_key);
1913 silc_free(client_id);
1914 silc_free(server_id);
1915 silc_client_command_reply_free(cmd);
1918 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1920 silc_client_command_reply_free(context);
1924 /******************************************************************************
1926 Internal command reply functions
1928 ******************************************************************************/
1930 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1932 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1933 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1934 SilcCommandStatus status;
1936 SILC_LOG_DEBUG(("Start"));
1938 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1939 if (status != SILC_STATUS_OK &&
1940 status != SILC_STATUS_LIST_START &&
1941 status != SILC_STATUS_LIST_ITEM &&
1942 status != SILC_STATUS_LIST_END)
1945 /* Save WHOIS info */
1946 silc_client_command_reply_whois_save(cmd, status, FALSE);
1948 /* Pending callbacks are not executed if this was an list entry */
1949 if (status != SILC_STATUS_OK &&
1950 status != SILC_STATUS_LIST_END) {
1951 silc_client_command_reply_free(cmd);
1956 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1958 /* If we received notify for invalid ID we'll remove the ID if we
1960 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1961 SilcClientEntry client_entry;
1963 unsigned char *tmp =
1964 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1967 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
1969 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1972 silc_client_del_client(cmd->client, conn, client_entry);
1973 silc_free(client_id);
1978 /* Unregister this command reply */
1979 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1980 NULL, silc_client_command_reply_whois_i,
1983 silc_client_command_reply_free(cmd);
1986 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1988 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1989 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1990 SilcCommandStatus status;
1992 SILC_LOG_DEBUG(("Start"));
1994 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1995 if (status != SILC_STATUS_OK &&
1996 status != SILC_STATUS_LIST_START &&
1997 status != SILC_STATUS_LIST_ITEM &&
1998 status != SILC_STATUS_LIST_END)
2001 /* Save IDENTIFY info */
2002 silc_client_command_reply_identify_save(cmd, status, FALSE);
2004 /* Pending callbacks are not executed if this was an list entry */
2005 if (status != SILC_STATUS_OK &&
2006 status != SILC_STATUS_LIST_END) {
2007 silc_client_command_reply_free(cmd);
2012 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2014 /* If we received notify for invalid ID we'll remove the ID if we
2016 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2017 SilcClientEntry client_entry;
2019 unsigned char *tmp =
2020 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2023 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
2025 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2028 silc_client_del_client(cmd->client, conn, client_entry);
2029 silc_free(client_id);
2034 /* Unregister this command reply */
2035 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2036 NULL, silc_client_command_reply_identify_i,
2039 silc_client_command_reply_free(cmd);
2042 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2044 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2045 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2046 SilcCommandStatus status;
2048 SilcIDCacheEntry id_cache;
2049 SilcServerEntry server;
2050 SilcServerID *server_id = NULL;
2051 char *server_name, *server_info;
2054 SILC_LOG_DEBUG(("Start"));
2056 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
2057 SILC_GET16_MSB(status, tmp);
2058 if (status != SILC_STATUS_OK)
2062 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2066 server_id = silc_id_payload_parse_id(tmp, len);
2070 /* Get server name */
2071 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2075 /* Get server info */
2076 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2080 /* See whether we have this server cached. If not create it. */
2081 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
2083 SILC_LOG_DEBUG(("New server entry"));
2084 server = silc_calloc(1, sizeof(*server));
2085 server->server_name = strdup(server_name);
2086 server->server_info = strdup(server_info);
2087 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
2089 /* Add it to the cache */
2090 silc_idcache_add(conn->server_cache, server->server_name,
2091 server->server_id, (void *)server, 0, NULL);
2095 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2096 silc_free(server_id);
2097 silc_client_command_reply_free(cmd);