5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 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.
36 #include "clientlibincludes.h"
37 #include "client_internal.h"
39 /* Client command reply list. */
40 SilcClientCommandReply silc_command_reply_list[] =
42 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
43 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
44 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
45 SILC_CLIENT_CMD_REPLY(nick, NICK),
46 SILC_CLIENT_CMD_REPLY(list, LIST),
47 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
48 SILC_CLIENT_CMD_REPLY(invite, INVITE),
49 SILC_CLIENT_CMD_REPLY(kill, KILL),
50 SILC_CLIENT_CMD_REPLY(info, INFO),
51 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
52 SILC_CLIENT_CMD_REPLY(ping, PING),
53 SILC_CLIENT_CMD_REPLY(oper, OPER),
54 SILC_CLIENT_CMD_REPLY(join, JOIN),
55 SILC_CLIENT_CMD_REPLY(motd, MOTD),
56 SILC_CLIENT_CMD_REPLY(umode, UMODE),
57 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
58 SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
59 SILC_CLIENT_CMD_REPLY(kick, KICK),
60 SILC_CLIENT_CMD_REPLY(ban, BAN),
61 SILC_CLIENT_CMD_REPLY(close, CLOSE),
62 SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN),
63 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
64 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
65 SILC_CLIENT_CMD_REPLY(users, USERS),
66 SILC_CLIENT_CMD_REPLY(getkey, GETKEY),
71 const SilcCommandStatusMessage silc_command_status_messages[] = {
73 { STAT(NO_SUCH_NICK), "There was no such nickname" },
74 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
75 { STAT(NO_SUCH_SERVER), "No such server" },
76 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
77 { STAT(NO_RECIPIENT), "No recipient given" },
78 { STAT(UNKNOWN_COMMAND), "Unknown command" },
79 { STAT(WILDCARDS), "Unknown command" },
80 { STAT(NO_CLIENT_ID), "No Client ID given" },
81 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
82 { STAT(NO_SERVER_ID), "No Server ID given" },
83 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
84 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
85 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
86 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
87 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
88 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
89 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
90 { STAT(USER_ON_CHANNEL), "User already on the channel" },
91 { STAT(NOT_REGISTERED), "You have not registered" },
92 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
93 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
94 { STAT(PERM_DENIED), "Permission denied" },
95 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
96 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
97 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
98 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
99 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
100 { STAT(UNKNOWN_MODE), "Unknown mode" },
101 { STAT(NOT_YOU), "Cannot change mode for other users" },
102 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
103 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
104 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
105 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
106 { STAT(BAD_NICKNAME), "Bad nickname" },
107 { STAT(BAD_CHANNEL), "Bad channel name" },
108 { STAT(AUTH_FAILED), "Authentication failed" },
109 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
110 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
114 /* Command reply operation that is called at the end of all command replys.
115 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
116 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
117 #define ARGS cmd->client, cmd->sock->user_data, \
118 cmd->payload, TRUE, silc_command_get(cmd->payload), status
120 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
121 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
122 cmd->sock->user_data, cmd->payload, FALSE, \
123 silc_command_get(cmd->payload), status)
125 /* All functions that call the COMMAND_CHECK_STATUS or the
126 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
128 #define COMMAND_CHECK_STATUS \
130 SILC_LOG_DEBUG(("Start")); \
131 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
132 if (status != SILC_STATUS_OK) { \
133 COMMAND_REPLY_ERROR; \
138 #define COMMAND_CHECK_STATUS_LIST \
140 SILC_LOG_DEBUG(("Start")); \
141 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
142 if (status != SILC_STATUS_OK && \
143 status != SILC_STATUS_LIST_START && \
144 status != SILC_STATUS_LIST_ITEM && \
145 status != SILC_STATUS_LIST_END) { \
146 COMMAND_REPLY_ERROR; \
151 /* Process received command reply. */
153 void silc_client_command_reply_process(SilcClient client,
154 SilcSocketConnection sock,
155 SilcPacketContext *packet)
157 SilcBuffer buffer = packet->buffer;
158 SilcClientCommandReply *cmd;
159 SilcClientCommandReplyContext ctx;
160 SilcCommandPayload payload;
164 /* Get command reply payload from packet */
165 payload = silc_command_payload_parse(buffer);
167 /* Silently ignore bad reply packet */
168 SILC_LOG_DEBUG(("Bad command reply packet"));
172 /* Allocate command reply context. This must be free'd by the
173 command reply routine receiving it. */
174 ctx = silc_calloc(1, sizeof(*ctx));
175 ctx->client = client;
177 ctx->payload = payload;
178 ctx->args = silc_command_get_args(ctx->payload);
179 ctx->packet = packet;
180 ident = silc_command_get_ident(ctx->payload);
182 /* Check for pending commands and mark to be exeucted */
183 silc_client_command_pending_check(sock->user_data, ctx,
184 silc_command_get(ctx->payload), ident);
186 /* Execute command reply */
187 command = silc_command_get(ctx->payload);
188 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
189 if (cmd->cmd == command)
192 if (cmd == NULL || !cmd->cb) {
200 /* Returns status message string */
202 char *silc_client_command_status_message(SilcCommandStatus status)
206 for (i = 0; silc_command_status_messages[i].message; i++) {
207 if (silc_command_status_messages[i].status == status)
211 if (silc_command_status_messages[i].message == NULL)
214 return silc_command_status_messages[i].message;
217 /* Free command reply context and its internals. */
219 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
222 silc_command_payload_free(cmd->payload);
228 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
229 SilcCommandStatus status)
231 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
232 SilcClientID *client_id;
233 SilcIDCacheEntry id_cache = NULL;
234 SilcClientEntry client_entry = NULL;
237 unsigned char *id_data, *tmp;
238 char *nickname = NULL, *username = NULL;
239 char *realname = NULL;
240 uint32 idle = 0, mode = 0;
241 SilcBuffer channels = NULL;
243 argc = silc_argument_get_arg_num(cmd->args);
245 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
251 client_id = silc_id_payload_parse_id(id_data, len);
257 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
258 username = silc_argument_get_arg_type(cmd->args, 4, &len);
259 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
260 if (!nickname || !username || !realname) {
265 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
267 channels = silc_buffer_alloc(len);
268 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
269 silc_buffer_put(channels, tmp, len);
272 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
274 SILC_GET32_MSB(mode, tmp);
276 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
278 SILC_GET32_MSB(idle, tmp);
280 /* Check if we have this client cached already. */
281 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
283 silc_hash_client_id_compare, NULL,
285 SILC_LOG_DEBUG(("Adding new client entry"));
287 silc_client_add_client(cmd->client, conn, nickname, username, realname,
290 client_entry = (SilcClientEntry)id_cache->context;
291 silc_client_update_client(cmd->client, conn, client_entry,
292 nickname, username, realname, mode);
293 silc_free(client_id);
296 /* Notify application */
298 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
299 channels, mode, idle));
302 silc_buffer_free(channels);
305 /* Received reply for WHOIS command. This maybe called several times
306 for one WHOIS command as server may reply with list of results. */
308 SILC_CLIENT_CMD_REPLY_FUNC(whois)
310 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
311 SilcCommandStatus status;
313 COMMAND_CHECK_STATUS_LIST;
315 /* Save WHOIS info */
316 silc_client_command_reply_whois_save(cmd, status);
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);
327 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
328 silc_client_command_reply_free(cmd);
331 /* Received reply for WHOWAS command. */
333 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
335 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
336 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
337 SilcCommandStatus status;
338 SilcClientID *client_id;
339 SilcIDCacheEntry id_cache = NULL;
340 SilcClientEntry client_entry = NULL;
342 unsigned char *id_data;
343 char *nickname, *username;
344 char *realname = NULL;
346 COMMAND_CHECK_STATUS_LIST;
348 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
354 client_id = silc_id_payload_parse_id(id_data, len);
360 /* Get the client entry, if exists */
361 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
363 silc_hash_client_id_compare, NULL,
365 client_entry = (SilcClientEntry)id_cache->context;
366 silc_free(client_id);
368 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
369 username = silc_argument_get_arg_type(cmd->args, 4, &len);
370 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
371 if (!nickname || !username) {
376 /* Notify application. We don't save any history information to any
377 cache. Just pass the data to the application for displaying on
379 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
381 /* Pending callbacks are not executed if this was an list entry */
382 if (status != SILC_STATUS_OK &&
383 status != SILC_STATUS_LIST_END) {
384 silc_client_command_reply_free(cmd);
389 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
390 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
391 silc_client_command_reply_free(cmd);
395 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
396 SilcCommandStatus status)
398 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
399 SilcClient client = cmd->client;
400 SilcClientID *client_id = NULL;
401 SilcServerID *server_id = NULL;
402 SilcChannelID *channel_id = NULL;
403 SilcIDCacheEntry id_cache = NULL;
404 SilcClientEntry client_entry;
405 SilcServerEntry server_entry;
406 SilcChannelEntry channel_entry;
409 unsigned char *id_data;
410 char *name = NULL, *info = NULL;
411 SilcIDPayload idp = NULL;
414 argc = silc_argument_get_arg_num(cmd->args);
416 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
421 idp = silc_id_payload_parse_data(id_data, len);
427 name = silc_argument_get_arg_type(cmd->args, 3, &len);
428 info = silc_argument_get_arg_type(cmd->args, 4, &len);
430 id_type = silc_id_payload_get_type(idp);
434 client_id = silc_id_payload_get_id(idp);
436 SILC_LOG_DEBUG(("Received client information"));
438 /* Check if we have this client cached already. */
439 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
442 silc_hash_client_id_compare, NULL,
444 SILC_LOG_DEBUG(("Adding new client entry"));
446 silc_client_add_client(cmd->client, conn, name, info, NULL,
447 silc_id_dup(client_id, id_type), 0);
449 client_entry = (SilcClientEntry)id_cache->context;
450 silc_client_update_client(cmd->client, conn, client_entry,
451 name, info, NULL, 0);
454 /* Notify application */
455 COMMAND_REPLY((ARGS, client_entry, name, info));
459 server_id = silc_id_payload_get_id(idp);
461 SILC_LOG_DEBUG(("Received server information"));
463 /* Check if we have this server cached already. */
464 if (!silc_idcache_find_by_id_one(conn->server_cache,
465 (void *)server_id, &id_cache)) {
466 SILC_LOG_DEBUG(("Adding new server entry"));
468 server_entry = silc_calloc(1, sizeof(*server_entry));
469 server_entry->server_id = silc_id_dup(server_id, id_type);
471 server_entry->server_name = strdup(name);
473 server_entry->server_info = strdup(info);
475 /* Add server to cache */
476 silc_idcache_add(conn->server_cache, server_entry->server_name,
477 server_entry->server_id, (void *)server_entry, FALSE);
479 server_entry = (SilcServerEntry)id_cache->context;
482 /* Notify application */
483 COMMAND_REPLY((ARGS, server_entry, name, info));
486 case SILC_ID_CHANNEL:
487 channel_id = silc_id_payload_get_id(idp);
489 SILC_LOG_DEBUG(("Received channel information"));
491 /* Check if we have this channel cached already. */
492 if (!silc_idcache_find_by_id_one(conn->channel_cache,
493 (void *)channel_id, &id_cache)) {
497 SILC_LOG_DEBUG(("Adding new channel entry"));
498 channel_entry = silc_client_new_channel_id(client, conn->sock,
499 strdup(name), 0, idp);
501 channel_entry = (SilcChannelEntry)id_cache->context;
504 /* Notify application */
505 COMMAND_REPLY((ARGS, channel_entry, name, info));
509 silc_id_payload_free(idp);
510 silc_free(client_id);
511 silc_free(server_id);
512 silc_free(channel_id);
515 /* Received reply for IDENTIFY command. This maybe called several times
516 for one IDENTIFY command as server may reply with list of results.
517 This is totally silent and does not print anything on screen. */
519 SILC_CLIENT_CMD_REPLY_FUNC(identify)
521 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
522 SilcCommandStatus status;
524 COMMAND_CHECK_STATUS_LIST;
526 /* Save IDENTIFY info */
527 silc_client_command_reply_identify_save(cmd, status);
529 /* Pending callbacks are not executed if this was an list entry */
530 if (status != SILC_STATUS_OK &&
531 status != SILC_STATUS_LIST_END) {
532 silc_client_command_reply_free(cmd);
537 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
538 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
539 silc_client_command_reply_free(cmd);
542 /* Received reply for command NICK. If everything went without errors
543 we just received our new Client ID. */
545 SILC_CLIENT_CMD_REPLY_FUNC(nick)
547 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
548 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
549 SilcCommandStatus status;
554 SILC_LOG_DEBUG(("Start"));
556 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
557 if (status != SILC_STATUS_OK) {
558 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
559 "Cannot set nickname: %s",
560 silc_client_command_status_message(status));
565 argc = silc_argument_get_arg_num(cmd->args);
566 if (argc < 2 || argc > 2) {
567 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
568 "Cannot set nickname: bad reply to command");
573 /* Take received Client ID */
574 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
575 idp = silc_id_payload_parse_data(tmp, len);
580 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
582 /* Notify application */
583 COMMAND_REPLY((ARGS, conn->local_entry));
586 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
587 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
588 silc_client_command_reply_free(cmd);
591 /* Received reply to the LIST command. */
593 SILC_CLIENT_CMD_REPLY_FUNC(list)
595 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
596 SilcCommandStatus status;
597 unsigned char *tmp, *name, *topic;
598 uint32 usercount = 0;
600 COMMAND_CHECK_STATUS_LIST;
602 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
603 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
604 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
606 SILC_GET32_MSB(usercount, tmp);
608 /* Notify application */
609 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
611 /* Pending callbacks are not executed if this was an list entry */
612 if (status != SILC_STATUS_OK &&
613 status != SILC_STATUS_LIST_END) {
614 silc_client_command_reply_free(cmd);
619 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
620 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
621 silc_client_command_reply_free(cmd);
624 /* Received reply to topic command. */
626 SILC_CLIENT_CMD_REPLY_FUNC(topic)
628 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
629 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
630 SilcCommandStatus status;
631 SilcChannelEntry channel;
632 SilcChannelID *channel_id = NULL;
633 SilcIDCacheEntry id_cache = NULL;
638 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
639 if (status != SILC_STATUS_OK) {
640 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
641 "%s", silc_client_command_status_message(status));
646 argc = silc_argument_get_arg_num(cmd->args);
647 if (argc < 1 || argc > 3) {
652 /* Take Channel ID */
653 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
658 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
662 channel_id = silc_id_payload_parse_id(tmp, len);
666 /* Get the channel entry */
667 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
669 silc_free(channel_id);
674 channel = (SilcChannelEntry)id_cache->context;
676 /* Notify application */
677 COMMAND_REPLY((ARGS, channel, topic));
680 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
681 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
682 silc_client_command_reply_free(cmd);
685 /* Received reply to invite command. */
687 SILC_CLIENT_CMD_REPLY_FUNC(invite)
689 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
690 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
691 SilcCommandStatus status;
692 SilcChannelEntry channel;
693 SilcChannelID *channel_id;
694 SilcIDCacheEntry id_cache;
698 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
699 SILC_GET16_MSB(status, tmp);
700 if (status != SILC_STATUS_OK) {
701 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
702 "%s", silc_client_command_status_message(status));
707 /* Take Channel ID */
708 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
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 /* Get the invite list */
727 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
729 /* Notify application */
730 COMMAND_REPLY((ARGS, channel, tmp));
733 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
734 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
735 silc_client_command_reply_free(cmd);
738 /* Received reply to the KILL command. */
740 SILC_CLIENT_CMD_REPLY_FUNC(kill)
742 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
743 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
744 SilcCommandStatus status;
746 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
747 if (status != SILC_STATUS_OK) {
748 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
749 "%s", silc_client_command_status_message(status));
754 /* Notify application */
755 COMMAND_REPLY((ARGS));
758 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
759 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
760 silc_client_command_reply_free(cmd);
763 /* Received reply to INFO command. We receive the server ID and some
764 information about the server user requested. */
766 SILC_CLIENT_CMD_REPLY_FUNC(info)
768 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
769 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
770 SilcCommandStatus status;
772 SilcIDCacheEntry id_cache;
773 SilcServerEntry server;
774 SilcServerID *server_id = NULL;
775 char *server_name, *server_info;
778 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
779 SILC_GET16_MSB(status, tmp);
780 if (status != SILC_STATUS_OK) {
781 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
782 "%s", silc_client_command_status_message(status));
788 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
792 server_id = silc_id_payload_parse_id(tmp, len);
796 /* Get server name */
797 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
801 /* Get server info */
802 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
806 /* See whether we have this server cached. If not create it. */
807 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
809 SILC_LOG_DEBUG(("New server entry"));
811 server = silc_calloc(1, sizeof(*server));
812 server->server_name = strdup(server_name);
813 server->server_info = strdup(server_info);
814 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
816 /* Add it to the cache */
817 silc_idcache_add(conn->server_cache, server->server_name,
818 server->server_id, (void *)server, FALSE);
820 server = (SilcServerEntry)id_cache->context;
823 /* Notify application */
824 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
827 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
828 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
829 silc_free(server_id);
830 silc_client_command_reply_free(cmd);
833 /* Received reply to PING command. The reply time is shown to user. */
835 SILC_CLIENT_CMD_REPLY_FUNC(ping)
837 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
838 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
839 SilcCommandStatus status;
842 time_t diff, curtime;
844 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
845 if (status != SILC_STATUS_OK) {
846 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
847 "%s", silc_client_command_status_message(status));
852 curtime = time(NULL);
853 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
854 cmd->packet->src_id_type);
860 for (i = 0; i < conn->ping_count; i++) {
861 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
862 diff = curtime - conn->ping[i].start_time;
863 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
864 "Ping reply from %s: %d second%s",
865 conn->ping[i].dest_name, diff,
866 diff == 1 ? "" : "s");
868 conn->ping[i].start_time = 0;
869 silc_free(conn->ping[i].dest_id);
870 conn->ping[i].dest_id = NULL;
871 silc_free(conn->ping[i].dest_name);
872 conn->ping[i].dest_name = NULL;
879 /* Notify application */
880 COMMAND_REPLY((ARGS));
883 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
884 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
885 silc_client_command_reply_free(cmd);
888 /* Received reply for JOIN command. */
890 SILC_CLIENT_CMD_REPLY_FUNC(join)
892 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
893 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
894 SilcCommandStatus status;
895 SilcIDPayload idp = NULL;
896 SilcChannelEntry channel;
897 SilcIDCacheEntry id_cache = NULL;
899 uint32 argc, mode, len, list_count;
900 char *topic, *tmp, *channel_name = NULL, *hmac;
901 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
904 SILC_LOG_DEBUG(("Start"));
906 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
907 if (status != SILC_STATUS_OK) {
908 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
909 "%s", silc_client_command_status_message(status));
914 argc = silc_argument_get_arg_num(cmd->args);
915 if (argc < 7 || argc > 14) {
916 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
917 "Cannot join channel: Bad reply packet");
922 /* Get channel name */
923 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
925 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
926 "Cannot join channel: Bad reply packet");
930 channel_name = strdup(tmp);
933 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
935 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
936 "Cannot join channel: Bad reply packet");
938 silc_free(channel_name);
941 idp = silc_id_payload_parse_data(tmp, len);
944 silc_free(channel_name);
948 /* Get channel mode */
949 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
951 SILC_GET32_MSB(mode, tmp);
955 /* Get channel key */
956 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
958 keyp = silc_buffer_alloc(len);
959 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
960 silc_buffer_put(keyp, tmp, len);
964 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
966 /* If we have the channel entry, remove it and create a new one */
967 channel = silc_client_get_channel(cmd->client, conn, channel_name);
969 silc_client_del_channel(cmd->client, conn, channel);
971 /* Save received Channel ID. This actually creates the channel */
972 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
974 silc_id_payload_free(idp);
976 conn->current_channel = channel;
979 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
981 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
982 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
983 "Cannot join channel: Unsupported HMAC `%s'",
986 silc_free(channel_name);
991 /* Get the list count */
992 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
995 SILC_GET32_MSB(list_count, tmp);
997 /* Get Client ID list */
998 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1002 client_id_list = silc_buffer_alloc(len);
1003 silc_buffer_pull_tail(client_id_list, len);
1004 silc_buffer_put(client_id_list, tmp, len);
1006 /* Get client mode list */
1007 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1011 client_mode_list = silc_buffer_alloc(len);
1012 silc_buffer_pull_tail(client_mode_list, len);
1013 silc_buffer_put(client_mode_list, tmp, len);
1015 /* Add clients we received in the reply to the channel */
1016 for (i = 0; i < list_count; i++) {
1019 SilcClientID *client_id;
1020 SilcClientEntry client_entry;
1023 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1025 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1030 SILC_GET32_MSB(mode, client_mode_list->data);
1032 /* Check if we have this client cached already. */
1033 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1036 silc_hash_client_id_compare, NULL,
1038 /* No, we don't have it, add entry for it. */
1040 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1041 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1043 /* Yes, we have it already */
1044 client_entry = (SilcClientEntry)id_cache->context;
1047 /* Join the client to the channel */
1048 chu = silc_calloc(1, sizeof(*chu));
1049 chu->client = client_entry;
1051 silc_list_add(channel->clients, chu);
1052 silc_free(client_id);
1054 silc_buffer_pull(client_id_list, idp_len);
1055 silc_buffer_pull(client_mode_list, 4);
1057 silc_buffer_push(client_id_list, client_id_list->data -
1058 client_id_list->head);
1059 silc_buffer_push(client_mode_list, client_mode_list->data -
1060 client_mode_list->head);
1062 /* Save channel key */
1063 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1064 silc_client_save_channel_key(conn, keyp, channel);
1066 /* Client is now joined to the channel */
1067 channel->on_channel = TRUE;
1069 /* Notify application */
1070 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1071 keyp ? keyp->head : NULL, NULL,
1072 NULL, topic, hmac, list_count, client_id_list,
1076 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1077 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1078 silc_client_command_reply_free(cmd);
1081 silc_buffer_free(keyp);
1083 silc_buffer_free(client_id_list);
1084 if (client_mode_list)
1085 silc_buffer_free(client_mode_list);
1088 /* Received reply for MOTD command */
1090 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1092 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1093 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1094 SilcCommandStatus status;
1097 char *motd = NULL, *cp, line[256];
1099 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1100 SILC_GET16_MSB(status, tmp);
1101 if (status != SILC_STATUS_OK) {
1102 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1103 "%s", silc_client_command_status_message(status));
1104 COMMAND_REPLY_ERROR;
1108 argc = silc_argument_get_arg_num(cmd->args);
1110 COMMAND_REPLY_ERROR;
1115 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1117 COMMAND_REPLY_ERROR;
1124 if (cp[i++] == '\n') {
1125 memset(line, 0, sizeof(line));
1126 strncat(line, cp, i - 1);
1132 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1142 /* Notify application */
1143 COMMAND_REPLY((ARGS, motd));
1146 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1147 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1148 silc_client_command_reply_free(cmd);
1151 /* Received reply tot he UMODE command. Save the current user mode */
1153 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1155 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1156 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1157 SilcCommandStatus status;
1161 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1162 SILC_GET16_MSB(status, tmp);
1163 if (status != SILC_STATUS_OK) {
1164 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1165 "%s", silc_client_command_status_message(status));
1166 COMMAND_REPLY_ERROR;
1170 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1172 COMMAND_REPLY_ERROR;
1176 SILC_GET32_MSB(mode, tmp);
1177 conn->local_entry->mode = mode;
1179 /* Notify application */
1180 COMMAND_REPLY((ARGS, mode));
1183 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1184 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1185 silc_client_command_reply_free(cmd);
1188 /* Received reply for CMODE command. */
1190 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1192 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1193 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1194 SilcCommandStatus status;
1197 SilcIDCacheEntry id_cache;
1198 SilcChannelID *channel_id;
1199 SilcChannelEntry channel;
1202 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1203 if (status != SILC_STATUS_OK) {
1204 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1205 "%s", silc_client_command_status_message(status));
1206 COMMAND_REPLY_ERROR;
1210 /* Take Channel ID */
1211 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1214 channel_id = silc_id_payload_parse_id(tmp, len);
1218 /* Get the channel entry */
1219 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1221 silc_free(channel_id);
1222 COMMAND_REPLY_ERROR;
1226 channel = (SilcChannelEntry)id_cache->context;
1228 /* Get channel mode */
1229 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1231 silc_free(channel_id);
1232 COMMAND_REPLY_ERROR;
1237 SILC_GET32_MSB(mode, tmp);
1238 channel->mode = mode;
1240 /* Notify application */
1241 COMMAND_REPLY((ARGS, channel, mode));
1243 silc_free(channel_id);
1246 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1247 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1248 silc_client_command_reply_free(cmd);
1251 /* Received reply for CUMODE command */
1253 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1255 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1256 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1257 SilcCommandStatus status;
1258 SilcIDCacheEntry id_cache = NULL;
1259 SilcClientID *client_id;
1260 SilcChannelID *channel_id;
1261 SilcClientEntry client_entry;
1262 SilcChannelEntry channel;
1263 SilcChannelUser chu;
1264 unsigned char *modev, *tmp, *id;
1267 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1268 if (status != SILC_STATUS_OK) {
1269 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1270 "%s", silc_client_command_status_message(status));
1271 COMMAND_REPLY_ERROR;
1275 /* Get channel mode */
1276 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1278 COMMAND_REPLY_ERROR;
1282 /* Take Channel ID */
1283 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1286 channel_id = silc_id_payload_parse_id(tmp, len);
1290 /* Get the channel entry */
1291 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1293 silc_free(channel_id);
1294 COMMAND_REPLY_ERROR;
1298 channel = (SilcChannelEntry)id_cache->context;
1301 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1303 silc_free(channel_id);
1304 COMMAND_REPLY_ERROR;
1307 client_id = silc_id_payload_parse_id(id, len);
1309 silc_free(channel_id);
1310 COMMAND_REPLY_ERROR;
1314 /* Get client entry */
1315 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1317 silc_hash_client_id_compare, NULL,
1319 silc_free(channel_id);
1320 silc_free(client_id);
1321 COMMAND_REPLY_ERROR;
1325 client_entry = (SilcClientEntry)id_cache->context;
1328 SILC_GET32_MSB(mode, modev);
1329 silc_list_start(channel->clients);
1330 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1331 if (chu->client == client_entry) {
1337 /* Notify application */
1338 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1339 silc_free(client_id);
1340 silc_free(channel_id);
1343 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1344 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1345 silc_client_command_reply_free(cmd);
1348 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1350 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1351 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1352 SilcCommandStatus status;
1355 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1356 SILC_GET16_MSB(status, tmp);
1357 if (status != SILC_STATUS_OK) {
1358 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1359 "%s", silc_client_command_status_message(status));
1360 COMMAND_REPLY_ERROR;
1364 /* Notify application */
1365 COMMAND_REPLY((ARGS));
1368 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1369 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1370 silc_client_command_reply_free(cmd);
1373 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1375 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1376 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1377 SilcCommandStatus status;
1380 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1381 SILC_GET16_MSB(status, tmp);
1382 if (status != SILC_STATUS_OK) {
1383 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1384 "%s", silc_client_command_status_message(status));
1385 COMMAND_REPLY_ERROR;
1389 /* Notify application */
1390 COMMAND_REPLY((ARGS));
1393 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1394 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1395 silc_client_command_reply_free(cmd);
1398 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1400 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1401 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1402 SilcCommandStatus status;
1405 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1406 SILC_GET16_MSB(status, tmp);
1407 if (status != SILC_STATUS_OK) {
1408 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1409 "%s", silc_client_command_status_message(status));
1410 COMMAND_REPLY_ERROR;
1414 /* Notify application */
1415 COMMAND_REPLY((ARGS));
1418 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1419 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1420 silc_client_command_reply_free(cmd);
1423 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1425 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1426 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1427 SilcCommandStatus status;
1430 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1431 SILC_GET16_MSB(status, tmp);
1432 if (status != SILC_STATUS_OK) {
1433 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1434 "%s", silc_client_command_status_message(status));
1435 COMMAND_REPLY_ERROR;
1439 /* Notify application */
1440 COMMAND_REPLY((ARGS));
1443 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1444 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1445 silc_client_command_reply_free(cmd);
1448 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1450 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1451 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1452 SilcCommandStatus status;
1453 SilcIDCacheEntry id_cache = NULL;
1454 SilcChannelEntry channel;
1455 SilcChannelID *channel_id;
1459 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1460 SILC_GET16_MSB(status, tmp);
1461 if (status != SILC_STATUS_OK) {
1462 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1463 "%s", silc_client_command_status_message(status));
1464 COMMAND_REPLY_ERROR;
1468 /* Take Channel ID */
1469 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1473 channel_id = silc_id_payload_parse_id(tmp, len);
1477 /* Get the channel entry */
1478 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1480 silc_free(channel_id);
1481 COMMAND_REPLY_ERROR;
1485 channel = (SilcChannelEntry)id_cache->context;
1487 /* Get the ban list */
1488 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1490 /* Notify application */
1491 COMMAND_REPLY((ARGS, channel, tmp));
1494 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1495 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1496 silc_client_command_reply_free(cmd);
1499 SILC_CLIENT_CMD_REPLY_FUNC(close)
1501 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1502 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1503 SilcCommandStatus status;
1506 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1507 SILC_GET16_MSB(status, tmp);
1508 if (status != SILC_STATUS_OK) {
1509 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1510 "%s", silc_client_command_status_message(status));
1511 COMMAND_REPLY_ERROR;
1515 /* Notify application */
1516 COMMAND_REPLY((ARGS));
1519 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1520 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1521 silc_client_command_reply_free(cmd);
1524 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1526 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1527 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1528 SilcCommandStatus status;
1531 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1532 SILC_GET16_MSB(status, tmp);
1533 if (status != SILC_STATUS_OK) {
1534 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1535 "%s", silc_client_command_status_message(status));
1536 COMMAND_REPLY_ERROR;
1540 /* Notify application */
1541 COMMAND_REPLY((ARGS));
1544 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1545 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1546 silc_client_command_reply_free(cmd);
1549 /* Reply to LEAVE command. */
1551 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1553 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1554 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1555 SilcCommandStatus status;
1558 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1559 SILC_GET16_MSB(status, tmp);
1560 if (status != SILC_STATUS_OK) {
1561 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1562 "%s", silc_client_command_status_message(status));
1563 COMMAND_REPLY_ERROR;
1567 /* Notify application */
1568 COMMAND_REPLY((ARGS));
1571 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1572 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1573 silc_client_command_reply_free(cmd);
1576 /* Reply to USERS command. Received list of client ID's and theirs modes
1577 on the channel we requested. */
1579 SILC_CLIENT_CMD_REPLY_FUNC(users)
1581 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1582 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1583 SilcCommandStatus status;
1584 SilcIDCacheEntry id_cache = NULL;
1585 SilcChannelEntry channel;
1586 SilcChannelUser chu;
1587 SilcChannelID *channel_id = NULL;
1588 SilcBuffer client_id_list = NULL;
1589 SilcBuffer client_mode_list = NULL;
1591 uint32 tmp_len, list_count;
1593 unsigned char **res_argv = NULL;
1594 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1596 SILC_LOG_DEBUG(("Start"));
1598 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1599 SILC_GET16_MSB(status, tmp);
1600 if (status != SILC_STATUS_OK) {
1601 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1602 "%s", silc_client_command_status_message(status));
1603 COMMAND_REPLY_ERROR;
1607 /* Get channel ID */
1608 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1610 COMMAND_REPLY_ERROR;
1613 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1615 COMMAND_REPLY_ERROR;
1619 /* Get the list count */
1620 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1622 COMMAND_REPLY_ERROR;
1625 SILC_GET32_MSB(list_count, tmp);
1627 /* Get Client ID list */
1628 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1630 COMMAND_REPLY_ERROR;
1634 client_id_list = silc_buffer_alloc(tmp_len);
1635 silc_buffer_pull_tail(client_id_list, tmp_len);
1636 silc_buffer_put(client_id_list, tmp, tmp_len);
1638 /* Get client mode list */
1639 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1641 COMMAND_REPLY_ERROR;
1645 client_mode_list = silc_buffer_alloc(tmp_len);
1646 silc_buffer_pull_tail(client_mode_list, tmp_len);
1647 silc_buffer_put(client_mode_list, tmp, tmp_len);
1649 /* Get channel entry */
1650 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1652 /* Resolve the channel from server */
1653 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1655 /* Register pending command callback. After we've received the channel
1656 information we will reprocess this command reply by re-calling this
1657 USERS command reply callback. */
1658 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1659 NULL, silc_client_command_reply_users, cmd);
1662 channel = (SilcChannelEntry)id_cache->context;
1665 /* Remove old client list from channel. */
1666 silc_list_start(channel->clients);
1667 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1668 silc_list_del(channel->clients, chu);
1672 /* Cache the received Client ID's and modes. */
1673 for (i = 0; i < list_count; i++) {
1676 SilcClientID *client_id;
1677 SilcClientEntry client;
1680 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1682 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1687 SILC_GET32_MSB(mode, client_mode_list->data);
1689 /* Check if we have this client cached already. */
1691 silc_idcache_find_by_id_one_ext(conn->client_cache,
1694 silc_hash_client_id_compare, NULL,
1697 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1698 !((SilcClientEntry)id_cache->context)->realname) {
1699 /* No we don't have it (or it is incomplete in information), query
1700 it from the server. Assemble argument table that will be sent
1701 for the WHOIS command later. */
1702 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1704 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1706 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1708 res_argv[res_argc] = client_id_list->data;
1709 res_argv_lens[res_argc] = idp_len;
1710 res_argv_types[res_argc] = res_argc + 3;
1713 /* Found the client, join it to the channel */
1714 client = (SilcClientEntry)id_cache->context;
1715 chu = silc_calloc(1, sizeof(*chu));
1716 chu->client = client;
1718 silc_list_add(channel->clients, chu);
1720 silc_free(client_id);
1724 silc_buffer_pull(client_id_list, idp_len);
1725 silc_buffer_pull(client_mode_list, 4);
1728 /* Query the client information from server if the list included clients
1729 that we don't know about. */
1733 /* Send the WHOIS command to server */
1734 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1735 res_argc, res_argv, res_argv_lens,
1736 res_argv_types, ++conn->cmd_ident);
1737 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1738 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1741 /* Register pending command callback. After we've received the WHOIS
1742 command reply we will reprocess this command reply by re-calling this
1743 USERS command reply callback. */
1744 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1745 NULL, silc_client_command_reply_users, cmd);
1747 silc_buffer_free(res_cmd);
1749 silc_free(channel_id);
1751 silc_free(res_argv);
1752 silc_free(res_argv_lens);
1753 silc_free(res_argv_types);
1757 /* Notify application */
1758 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1761 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1762 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1763 silc_client_command_reply_free(cmd);
1764 silc_free(channel_id);
1766 silc_buffer_free(client_id_list);
1767 if (client_mode_list)
1768 silc_buffer_free(client_mode_list);
1771 /* Received command reply to GETKEY command. WE've received the remote
1772 client's public key. */
1774 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1776 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1777 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1778 SilcCommandStatus status;
1779 SilcIDCacheEntry id_cache;
1780 SilcIDPayload idp = NULL;
1781 SilcClientID *client_id = NULL;
1782 SilcClientEntry client_entry;
1783 SilcServerID *server_id = NULL;
1784 SilcServerEntry server_entry;
1786 unsigned char *tmp, *pk;
1790 SilcPublicKey public_key = NULL;
1792 SILC_LOG_DEBUG(("Start"));
1794 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1795 SILC_GET16_MSB(status, tmp);
1796 if (status != SILC_STATUS_OK) {
1797 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1798 "%s", silc_client_command_status_message(status));
1799 COMMAND_REPLY_ERROR;
1803 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1805 COMMAND_REPLY_ERROR;
1808 idp = silc_id_payload_parse_data(tmp, len);
1810 COMMAND_REPLY_ERROR;
1814 /* Get the public key payload */
1815 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1817 /* Decode the public key */
1818 SILC_GET16_MSB(pk_len, tmp);
1819 SILC_GET16_MSB(type, tmp + 2);
1822 if (type != SILC_SKE_PK_TYPE_SILC) {
1823 COMMAND_REPLY_ERROR;
1827 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1828 COMMAND_REPLY_ERROR;
1833 id_type = silc_id_payload_get_type(idp);
1834 if (id_type == SILC_ID_CLIENT) {
1835 /* Received client's public key */
1836 client_id = silc_id_payload_get_id(idp);
1837 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1840 silc_hash_client_id_compare, NULL,
1842 COMMAND_REPLY_ERROR;
1846 client_entry = (SilcClientEntry)id_cache->context;
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);
1867 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1869 silc_id_payload_free(idp);
1871 silc_pkcs_public_key_free(public_key);
1872 silc_free(client_id);
1873 silc_free(server_id);
1874 silc_client_command_reply_free(cmd);