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 /* Save received Channel ID. This actually creates the channel */
967 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
969 silc_id_payload_free(idp);
971 conn->current_channel = channel;
974 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
976 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
977 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
978 "Cannot join channel: Unsupported HMAC `%s'",
981 silc_free(channel_name);
986 /* Get the list count */
987 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
990 SILC_GET32_MSB(list_count, tmp);
992 /* Get Client ID list */
993 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
997 client_id_list = silc_buffer_alloc(len);
998 silc_buffer_pull_tail(client_id_list, len);
999 silc_buffer_put(client_id_list, tmp, len);
1001 /* Get client mode list */
1002 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1006 client_mode_list = silc_buffer_alloc(len);
1007 silc_buffer_pull_tail(client_mode_list, len);
1008 silc_buffer_put(client_mode_list, tmp, len);
1010 /* Add clients we received in the reply to the channel */
1011 for (i = 0; i < list_count; i++) {
1014 SilcClientID *client_id;
1015 SilcClientEntry client_entry;
1018 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1020 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1025 SILC_GET32_MSB(mode, client_mode_list->data);
1027 /* Check if we have this client cached already. */
1028 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1031 silc_hash_client_id_compare, NULL,
1033 /* No, we don't have it, add entry for it. */
1035 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1036 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1038 /* Yes, we have it already */
1039 client_entry = (SilcClientEntry)id_cache->context;
1042 /* Join the client to the channel */
1043 chu = silc_calloc(1, sizeof(*chu));
1044 chu->client = client_entry;
1046 silc_list_add(channel->clients, chu);
1047 silc_free(client_id);
1049 silc_buffer_pull(client_id_list, idp_len);
1050 silc_buffer_pull(client_mode_list, 4);
1052 silc_buffer_push(client_id_list, client_id_list->data -
1053 client_id_list->head);
1054 silc_buffer_push(client_mode_list, client_mode_list->data -
1055 client_mode_list->head);
1057 /* Save channel key */
1058 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1059 silc_client_save_channel_key(conn, keyp, channel);
1061 /* Client is now joined to the channel */
1062 channel->on_channel = TRUE;
1064 /* Notify application */
1065 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1066 keyp ? keyp->head : NULL, NULL,
1067 NULL, topic, hmac, list_count, client_id_list,
1071 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1072 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1073 silc_client_command_reply_free(cmd);
1076 silc_buffer_free(keyp);
1078 silc_buffer_free(client_id_list);
1079 if (client_mode_list)
1080 silc_buffer_free(client_mode_list);
1083 /* Received reply for MOTD command */
1085 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1087 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1088 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1089 SilcCommandStatus status;
1092 char *motd = NULL, *cp, line[256];
1094 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1095 SILC_GET16_MSB(status, tmp);
1096 if (status != SILC_STATUS_OK) {
1097 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1098 "%s", silc_client_command_status_message(status));
1099 COMMAND_REPLY_ERROR;
1103 argc = silc_argument_get_arg_num(cmd->args);
1105 COMMAND_REPLY_ERROR;
1110 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1112 COMMAND_REPLY_ERROR;
1119 if (cp[i++] == '\n') {
1120 memset(line, 0, sizeof(line));
1121 strncat(line, cp, i - 1);
1127 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1137 /* Notify application */
1138 COMMAND_REPLY((ARGS, motd));
1141 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1142 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1143 silc_client_command_reply_free(cmd);
1146 /* Received reply tot he UMODE command. Save the current user mode */
1148 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1150 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1151 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1152 SilcCommandStatus status;
1156 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1157 SILC_GET16_MSB(status, tmp);
1158 if (status != SILC_STATUS_OK) {
1159 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1160 "%s", silc_client_command_status_message(status));
1161 COMMAND_REPLY_ERROR;
1165 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1167 COMMAND_REPLY_ERROR;
1171 SILC_GET32_MSB(mode, tmp);
1172 conn->local_entry->mode = mode;
1174 /* Notify application */
1175 COMMAND_REPLY((ARGS, mode));
1178 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1179 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1180 silc_client_command_reply_free(cmd);
1183 /* Received reply for CMODE command. */
1185 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1187 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1188 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1189 SilcCommandStatus status;
1192 SilcIDCacheEntry id_cache;
1193 SilcChannelID *channel_id;
1194 SilcChannelEntry channel;
1197 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1198 if (status != SILC_STATUS_OK) {
1199 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1200 "%s", silc_client_command_status_message(status));
1201 COMMAND_REPLY_ERROR;
1205 /* Take Channel ID */
1206 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1209 channel_id = silc_id_payload_parse_id(tmp, len);
1213 /* Get the channel entry */
1214 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1216 silc_free(channel_id);
1217 COMMAND_REPLY_ERROR;
1221 channel = (SilcChannelEntry)id_cache->context;
1223 /* Get channel mode */
1224 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1226 silc_free(channel_id);
1227 COMMAND_REPLY_ERROR;
1232 SILC_GET32_MSB(mode, tmp);
1233 channel->mode = mode;
1235 /* Notify application */
1236 COMMAND_REPLY((ARGS, channel, mode));
1238 silc_free(channel_id);
1241 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1242 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1243 silc_client_command_reply_free(cmd);
1246 /* Received reply for CUMODE command */
1248 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1250 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1251 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1252 SilcCommandStatus status;
1253 SilcIDCacheEntry id_cache = NULL;
1254 SilcClientID *client_id;
1255 SilcChannelID *channel_id;
1256 SilcClientEntry client_entry;
1257 SilcChannelEntry channel;
1258 SilcChannelUser chu;
1259 unsigned char *tmp, *id;
1262 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1263 if (status != SILC_STATUS_OK) {
1264 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1265 "%s", silc_client_command_status_message(status));
1266 COMMAND_REPLY_ERROR;
1270 /* Get channel mode */
1271 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1273 COMMAND_REPLY_ERROR;
1277 /* Take Channel ID */
1278 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1281 channel_id = silc_id_payload_parse_id(tmp, len);
1285 /* Get the channel entry */
1286 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1288 silc_free(channel_id);
1289 COMMAND_REPLY_ERROR;
1293 channel = (SilcChannelEntry)id_cache->context;
1296 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1298 silc_free(channel_id);
1299 COMMAND_REPLY_ERROR;
1302 client_id = silc_id_payload_parse_id(id, len);
1304 silc_free(channel_id);
1305 COMMAND_REPLY_ERROR;
1309 /* Get client entry */
1310 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1312 silc_hash_client_id_compare, NULL,
1314 silc_free(channel_id);
1315 silc_free(client_id);
1316 COMMAND_REPLY_ERROR;
1320 client_entry = (SilcClientEntry)id_cache->context;
1323 SILC_GET32_MSB(mode, tmp);
1324 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1325 if (chu->client == client_entry) {
1331 /* Notify application */
1332 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1333 silc_free(client_id);
1334 silc_free(channel_id);
1337 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1338 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1339 silc_client_command_reply_free(cmd);
1342 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1344 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1345 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1346 SilcCommandStatus status;
1349 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1350 SILC_GET16_MSB(status, tmp);
1351 if (status != SILC_STATUS_OK) {
1352 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1353 "%s", silc_client_command_status_message(status));
1354 COMMAND_REPLY_ERROR;
1358 /* Notify application */
1359 COMMAND_REPLY((ARGS));
1362 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1363 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1364 silc_client_command_reply_free(cmd);
1367 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1369 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1370 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1371 SilcCommandStatus status;
1374 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1375 SILC_GET16_MSB(status, tmp);
1376 if (status != SILC_STATUS_OK) {
1377 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1378 "%s", silc_client_command_status_message(status));
1379 COMMAND_REPLY_ERROR;
1383 /* Notify application */
1384 COMMAND_REPLY((ARGS));
1387 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1388 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1389 silc_client_command_reply_free(cmd);
1392 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1394 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1395 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1396 SilcCommandStatus status;
1399 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1400 SILC_GET16_MSB(status, tmp);
1401 if (status != SILC_STATUS_OK) {
1402 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1403 "%s", silc_client_command_status_message(status));
1404 COMMAND_REPLY_ERROR;
1408 /* Notify application */
1409 COMMAND_REPLY((ARGS));
1412 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1413 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1414 silc_client_command_reply_free(cmd);
1417 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1419 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1420 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1421 SilcCommandStatus status;
1424 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1425 SILC_GET16_MSB(status, tmp);
1426 if (status != SILC_STATUS_OK) {
1427 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1428 "%s", silc_client_command_status_message(status));
1429 COMMAND_REPLY_ERROR;
1433 /* Notify application */
1434 COMMAND_REPLY((ARGS));
1437 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1438 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1439 silc_client_command_reply_free(cmd);
1442 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1444 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1445 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1446 SilcCommandStatus status;
1447 SilcIDCacheEntry id_cache = NULL;
1448 SilcChannelEntry channel;
1449 SilcChannelID *channel_id;
1453 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1454 SILC_GET16_MSB(status, tmp);
1455 if (status != SILC_STATUS_OK) {
1456 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1457 "%s", silc_client_command_status_message(status));
1458 COMMAND_REPLY_ERROR;
1462 /* Take Channel ID */
1463 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1467 channel_id = silc_id_payload_parse_id(tmp, len);
1471 /* Get the channel entry */
1472 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1474 silc_free(channel_id);
1475 COMMAND_REPLY_ERROR;
1479 channel = (SilcChannelEntry)id_cache->context;
1481 /* Get the ban list */
1482 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1484 /* Notify application */
1485 COMMAND_REPLY((ARGS, channel, tmp));
1488 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1489 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1490 silc_client_command_reply_free(cmd);
1493 SILC_CLIENT_CMD_REPLY_FUNC(close)
1495 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1496 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1497 SilcCommandStatus status;
1500 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1501 SILC_GET16_MSB(status, tmp);
1502 if (status != SILC_STATUS_OK) {
1503 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1504 "%s", silc_client_command_status_message(status));
1505 COMMAND_REPLY_ERROR;
1509 /* Notify application */
1510 COMMAND_REPLY((ARGS));
1513 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1514 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1515 silc_client_command_reply_free(cmd);
1518 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1520 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1521 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1522 SilcCommandStatus status;
1525 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1526 SILC_GET16_MSB(status, tmp);
1527 if (status != SILC_STATUS_OK) {
1528 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1529 "%s", silc_client_command_status_message(status));
1530 COMMAND_REPLY_ERROR;
1534 /* Notify application */
1535 COMMAND_REPLY((ARGS));
1538 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1539 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1540 silc_client_command_reply_free(cmd);
1543 /* Reply to LEAVE command. */
1545 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1547 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1548 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1549 SilcCommandStatus status;
1552 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1553 SILC_GET16_MSB(status, tmp);
1554 if (status != SILC_STATUS_OK) {
1555 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1556 "%s", silc_client_command_status_message(status));
1557 COMMAND_REPLY_ERROR;
1561 /* Notify application */
1562 COMMAND_REPLY((ARGS));
1565 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1566 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1567 silc_client_command_reply_free(cmd);
1570 /* Reply to USERS command. Received list of client ID's and theirs modes
1571 on the channel we requested. */
1573 SILC_CLIENT_CMD_REPLY_FUNC(users)
1575 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1576 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1577 SilcCommandStatus status;
1578 SilcIDCacheEntry id_cache = NULL;
1579 SilcChannelEntry channel;
1580 SilcChannelUser chu;
1581 SilcChannelID *channel_id = NULL;
1582 SilcBuffer client_id_list = NULL;
1583 SilcBuffer client_mode_list = NULL;
1585 uint32 tmp_len, list_count;
1587 unsigned char **res_argv = NULL;
1588 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1590 SILC_LOG_DEBUG(("Start"));
1592 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1593 SILC_GET16_MSB(status, tmp);
1594 if (status != SILC_STATUS_OK) {
1595 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1596 "%s", silc_client_command_status_message(status));
1597 COMMAND_REPLY_ERROR;
1601 /* Get channel ID */
1602 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1604 COMMAND_REPLY_ERROR;
1607 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1609 COMMAND_REPLY_ERROR;
1613 /* Get the list count */
1614 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1616 COMMAND_REPLY_ERROR;
1619 SILC_GET32_MSB(list_count, tmp);
1621 /* Get Client ID list */
1622 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1624 COMMAND_REPLY_ERROR;
1628 client_id_list = silc_buffer_alloc(tmp_len);
1629 silc_buffer_pull_tail(client_id_list, tmp_len);
1630 silc_buffer_put(client_id_list, tmp, tmp_len);
1632 /* Get client mode list */
1633 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1635 COMMAND_REPLY_ERROR;
1639 client_mode_list = silc_buffer_alloc(tmp_len);
1640 silc_buffer_pull_tail(client_mode_list, tmp_len);
1641 silc_buffer_put(client_mode_list, tmp, tmp_len);
1643 /* Get channel entry */
1644 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1646 /* Resolve the channel from server */
1647 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1649 /* Register pending command callback. After we've received the channel
1650 information we will reprocess this command reply by re-calling this
1651 USERS command reply callback. */
1652 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1653 NULL, silc_client_command_reply_users, cmd);
1656 channel = (SilcChannelEntry)id_cache->context;
1659 /* Remove old client list from channel. */
1660 silc_list_start(channel->clients);
1661 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1662 silc_list_del(channel->clients, chu);
1666 /* Cache the received Client ID's and modes. */
1667 for (i = 0; i < list_count; i++) {
1670 SilcClientID *client_id;
1671 SilcClientEntry client;
1674 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1676 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1681 SILC_GET32_MSB(mode, client_mode_list->data);
1683 /* Check if we have this client cached already. */
1685 silc_idcache_find_by_id_one_ext(conn->client_cache,
1688 silc_hash_client_id_compare, NULL,
1691 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1692 !((SilcClientEntry)id_cache->context)->realname) {
1693 /* No we don't have it (or it is incomplete in information), query
1694 it from the server. Assemble argument table that will be sent
1695 for the WHOIS command later. */
1696 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1698 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1700 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1702 res_argv[res_argc] = client_id_list->data;
1703 res_argv_lens[res_argc] = idp_len;
1704 res_argv_types[res_argc] = res_argc + 3;
1707 /* Found the client, join it to the channel */
1708 client = (SilcClientEntry)id_cache->context;
1709 chu = silc_calloc(1, sizeof(*chu));
1710 chu->client = client;
1712 silc_list_add(channel->clients, chu);
1714 silc_free(client_id);
1718 silc_buffer_pull(client_id_list, idp_len);
1719 silc_buffer_pull(client_mode_list, 4);
1722 /* Query the client information from server if the list included clients
1723 that we don't know about. */
1727 /* Send the WHOIS command to server */
1728 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1729 res_argc, res_argv, res_argv_lens,
1730 res_argv_types, ++conn->cmd_ident);
1731 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1732 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1735 /* Register pending command callback. After we've received the WHOIS
1736 command reply we will reprocess this command reply by re-calling this
1737 USERS command reply callback. */
1738 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1739 NULL, silc_client_command_reply_users, cmd);
1741 silc_buffer_free(res_cmd);
1743 silc_free(channel_id);
1745 silc_free(res_argv);
1746 silc_free(res_argv_lens);
1747 silc_free(res_argv_types);
1751 /* Notify application */
1752 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1755 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1756 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1757 silc_client_command_reply_free(cmd);
1758 silc_free(channel_id);
1760 silc_buffer_free(client_id_list);
1761 if (client_mode_list)
1762 silc_buffer_free(client_mode_list);
1765 /* Received command reply to GETKEY command. WE've received the remote
1766 client's public key. */
1768 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1770 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1771 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1772 SilcCommandStatus status;
1773 SilcIDCacheEntry id_cache;
1774 SilcIDPayload idp = NULL;
1775 SilcClientID *client_id = NULL;
1776 SilcClientEntry client_entry;
1777 SilcServerID *server_id = NULL;
1778 SilcServerEntry server_entry;
1780 unsigned char *tmp, *pk;
1784 SilcPublicKey public_key = NULL;
1786 SILC_LOG_DEBUG(("Start"));
1788 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1789 SILC_GET16_MSB(status, tmp);
1790 if (status != SILC_STATUS_OK) {
1791 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1792 "%s", silc_client_command_status_message(status));
1793 COMMAND_REPLY_ERROR;
1797 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1799 COMMAND_REPLY_ERROR;
1802 idp = silc_id_payload_parse_data(tmp, len);
1804 COMMAND_REPLY_ERROR;
1808 /* Get the public key payload */
1809 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1811 /* Decode the public key */
1812 SILC_GET16_MSB(pk_len, tmp);
1813 SILC_GET16_MSB(type, tmp + 2);
1816 if (type != SILC_SKE_PK_TYPE_SILC) {
1817 COMMAND_REPLY_ERROR;
1821 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1822 COMMAND_REPLY_ERROR;
1827 id_type = silc_id_payload_get_type(idp);
1828 if (id_type == SILC_ID_CLIENT) {
1829 /* Received client's public key */
1830 client_id = silc_id_payload_get_id(idp);
1831 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1834 silc_hash_client_id_compare, NULL,
1836 COMMAND_REPLY_ERROR;
1840 client_entry = (SilcClientEntry)id_cache->context;
1842 /* Notify application */
1843 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1844 } else if (id_type == SILC_ID_SERVER) {
1845 /* Received server's public key */
1846 server_id = silc_id_payload_get_id(idp);
1847 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1849 COMMAND_REPLY_ERROR;
1853 server_entry = (SilcServerEntry)id_cache->context;
1855 /* Notify application */
1856 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1860 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1861 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1863 silc_id_payload_free(idp);
1865 silc_pkcs_public_key_free(public_key);
1866 silc_free(client_id);
1867 silc_free(server_id);
1868 silc_client_command_reply_free(cmd);