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;
747 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
748 SILC_GET16_MSB(status, tmp);
749 if (status != SILC_STATUS_OK) {
750 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
751 "%s", silc_client_command_status_message(status));
756 /* Notify application */
757 COMMAND_REPLY((ARGS));
760 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
761 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
762 silc_client_command_reply_free(cmd);
765 /* Received reply to INFO command. We receive the server ID and some
766 information about the server user requested. */
768 SILC_CLIENT_CMD_REPLY_FUNC(info)
770 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
771 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
772 SilcCommandStatus status;
774 SilcIDCacheEntry id_cache;
775 SilcServerEntry server;
776 SilcServerID *server_id = NULL;
777 char *server_name, *server_info;
780 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
781 SILC_GET16_MSB(status, tmp);
782 if (status != SILC_STATUS_OK) {
783 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
784 "%s", silc_client_command_status_message(status));
790 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
794 server_id = silc_id_payload_parse_id(tmp, len);
798 /* Get server name */
799 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
803 /* Get server info */
804 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
808 /* See whether we have this server cached. If not create it. */
809 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
811 SILC_LOG_DEBUG(("New server entry"));
813 server = silc_calloc(1, sizeof(*server));
814 server->server_name = strdup(server_name);
815 server->server_info = strdup(server_info);
816 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
818 /* Add it to the cache */
819 silc_idcache_add(conn->server_cache, server->server_name,
820 server->server_id, (void *)server, FALSE);
822 server = (SilcServerEntry)id_cache->context;
825 /* Notify application */
826 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
829 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
830 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
831 silc_free(server_id);
832 silc_client_command_reply_free(cmd);
835 /* Received reply to PING command. The reply time is shown to user. */
837 SILC_CLIENT_CMD_REPLY_FUNC(ping)
839 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
840 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
841 SilcCommandStatus status;
844 time_t diff, curtime;
846 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
847 if (status != SILC_STATUS_OK) {
848 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
849 "%s", silc_client_command_status_message(status));
854 curtime = time(NULL);
855 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
856 cmd->packet->src_id_type);
862 for (i = 0; i < conn->ping_count; i++) {
863 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
864 diff = curtime - conn->ping[i].start_time;
865 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
866 "Ping reply from %s: %d second%s",
867 conn->ping[i].dest_name, diff,
868 diff == 1 ? "" : "s");
870 conn->ping[i].start_time = 0;
871 silc_free(conn->ping[i].dest_id);
872 conn->ping[i].dest_id = NULL;
873 silc_free(conn->ping[i].dest_name);
874 conn->ping[i].dest_name = NULL;
881 /* Notify application */
882 COMMAND_REPLY((ARGS));
885 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
886 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
887 silc_client_command_reply_free(cmd);
890 /* Received reply for JOIN command. */
892 SILC_CLIENT_CMD_REPLY_FUNC(join)
894 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
895 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
896 SilcCommandStatus status;
897 SilcIDPayload idp = NULL;
898 SilcChannelEntry channel;
899 SilcIDCacheEntry id_cache = NULL;
901 uint32 argc, mode, len, list_count;
902 char *topic, *tmp, *channel_name = NULL, *hmac;
903 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
906 SILC_LOG_DEBUG(("Start"));
908 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
909 if (status != SILC_STATUS_OK) {
910 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
911 "%s", silc_client_command_status_message(status));
916 argc = silc_argument_get_arg_num(cmd->args);
917 if (argc < 7 || argc > 14) {
918 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
919 "Cannot join channel: Bad reply packet");
924 /* Get channel name */
925 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
927 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
928 "Cannot join channel: Bad reply packet");
932 channel_name = strdup(tmp);
935 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
937 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
938 "Cannot join channel: Bad reply packet");
940 silc_free(channel_name);
943 idp = silc_id_payload_parse_data(tmp, len);
946 silc_free(channel_name);
950 /* Get channel mode */
951 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
953 SILC_GET32_MSB(mode, tmp);
957 /* Get channel key */
958 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
960 keyp = silc_buffer_alloc(len);
961 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
962 silc_buffer_put(keyp, tmp, len);
966 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
968 /* Save received Channel ID. This actually creates the channel */
969 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
971 silc_id_payload_free(idp);
973 conn->current_channel = channel;
976 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
978 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
979 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
980 "Cannot join channel: Unsupported HMAC `%s'",
983 silc_free(channel_name);
988 /* Get the list count */
989 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
992 SILC_GET32_MSB(list_count, tmp);
994 /* Get Client ID list */
995 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
999 client_id_list = silc_buffer_alloc(len);
1000 silc_buffer_pull_tail(client_id_list, len);
1001 silc_buffer_put(client_id_list, tmp, len);
1003 /* Get client mode list */
1004 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1008 client_mode_list = silc_buffer_alloc(len);
1009 silc_buffer_pull_tail(client_mode_list, len);
1010 silc_buffer_put(client_mode_list, tmp, len);
1012 /* Add clients we received in the reply to the channel */
1013 for (i = 0; i < list_count; i++) {
1016 SilcClientID *client_id;
1017 SilcClientEntry client_entry;
1020 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1022 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1027 SILC_GET32_MSB(mode, client_mode_list->data);
1029 /* Check if we have this client cached already. */
1030 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1033 silc_hash_client_id_compare, NULL,
1035 /* No, we don't have it, add entry for it. */
1037 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1038 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1040 /* Yes, we have it already */
1041 client_entry = (SilcClientEntry)id_cache->context;
1044 /* Join the client to the channel */
1045 chu = silc_calloc(1, sizeof(*chu));
1046 chu->client = client_entry;
1048 silc_list_add(channel->clients, chu);
1049 silc_free(client_id);
1051 silc_buffer_pull(client_id_list, idp_len);
1052 silc_buffer_pull(client_mode_list, 4);
1054 silc_buffer_push(client_id_list, client_id_list->data -
1055 client_id_list->head);
1056 silc_buffer_push(client_mode_list, client_mode_list->data -
1057 client_mode_list->head);
1059 /* Save channel key */
1060 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1061 silc_client_save_channel_key(conn, keyp, channel);
1063 /* Client is now joined to the channel */
1064 channel->on_channel = TRUE;
1066 /* Notify application */
1067 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1068 keyp ? keyp->head : NULL, NULL,
1069 NULL, topic, hmac, list_count, client_id_list,
1073 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1074 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1075 silc_client_command_reply_free(cmd);
1078 silc_buffer_free(keyp);
1080 silc_buffer_free(client_id_list);
1081 if (client_mode_list)
1082 silc_buffer_free(client_mode_list);
1085 /* Received reply for MOTD command */
1087 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1089 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1090 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1091 SilcCommandStatus status;
1094 char *motd = NULL, *cp, line[256];
1096 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1097 SILC_GET16_MSB(status, tmp);
1098 if (status != SILC_STATUS_OK) {
1099 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1100 "%s", silc_client_command_status_message(status));
1101 COMMAND_REPLY_ERROR;
1105 argc = silc_argument_get_arg_num(cmd->args);
1107 COMMAND_REPLY_ERROR;
1112 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1114 COMMAND_REPLY_ERROR;
1121 if (cp[i++] == '\n') {
1122 memset(line, 0, sizeof(line));
1123 strncat(line, cp, i - 1);
1129 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1139 /* Notify application */
1140 COMMAND_REPLY((ARGS, motd));
1143 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1144 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1145 silc_client_command_reply_free(cmd);
1148 /* Received reply tot he UMODE command. Save the current user mode */
1150 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1152 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1153 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1154 SilcCommandStatus status;
1158 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1159 SILC_GET16_MSB(status, tmp);
1160 if (status != SILC_STATUS_OK) {
1161 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1162 "%s", silc_client_command_status_message(status));
1163 COMMAND_REPLY_ERROR;
1167 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1169 COMMAND_REPLY_ERROR;
1173 SILC_GET32_MSB(mode, tmp);
1174 conn->local_entry->mode = mode;
1176 /* Notify application */
1177 COMMAND_REPLY((ARGS, mode));
1180 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1181 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1182 silc_client_command_reply_free(cmd);
1185 /* Received reply for CMODE command. */
1187 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1189 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1190 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1191 SilcCommandStatus status;
1194 SilcIDCacheEntry id_cache;
1195 SilcChannelID *channel_id;
1196 SilcChannelEntry channel;
1199 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1200 if (status != SILC_STATUS_OK) {
1201 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1202 "%s", silc_client_command_status_message(status));
1203 COMMAND_REPLY_ERROR;
1207 /* Take Channel ID */
1208 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1211 channel_id = silc_id_payload_parse_id(tmp, len);
1215 /* Get the channel entry */
1216 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1218 silc_free(channel_id);
1219 COMMAND_REPLY_ERROR;
1223 channel = (SilcChannelEntry)id_cache->context;
1225 /* Get channel mode */
1226 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1228 silc_free(channel_id);
1229 COMMAND_REPLY_ERROR;
1234 SILC_GET32_MSB(mode, tmp);
1235 channel->mode = mode;
1237 /* Notify application */
1238 COMMAND_REPLY((ARGS, channel, mode));
1240 silc_free(channel_id);
1243 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1244 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1245 silc_client_command_reply_free(cmd);
1248 /* Received reply for CUMODE command */
1250 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1252 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1253 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1254 SilcCommandStatus status;
1255 SilcIDCacheEntry id_cache = NULL;
1256 SilcClientID *client_id;
1257 SilcChannelID *channel_id;
1258 SilcClientEntry client_entry;
1259 SilcChannelEntry channel;
1260 SilcChannelUser chu;
1261 unsigned char *tmp, *id;
1264 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1265 if (status != SILC_STATUS_OK) {
1266 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1267 "%s", silc_client_command_status_message(status));
1268 COMMAND_REPLY_ERROR;
1272 /* Get channel mode */
1273 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1275 COMMAND_REPLY_ERROR;
1279 /* Take Channel ID */
1280 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1283 channel_id = silc_id_payload_parse_id(tmp, len);
1287 /* Get the channel entry */
1288 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1290 silc_free(channel_id);
1291 COMMAND_REPLY_ERROR;
1295 channel = (SilcChannelEntry)id_cache->context;
1298 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1300 silc_free(channel_id);
1301 COMMAND_REPLY_ERROR;
1304 client_id = silc_id_payload_parse_id(id, len);
1306 silc_free(channel_id);
1307 COMMAND_REPLY_ERROR;
1311 /* Get client entry */
1312 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1314 silc_hash_client_id_compare, NULL,
1316 silc_free(channel_id);
1317 silc_free(client_id);
1318 COMMAND_REPLY_ERROR;
1322 client_entry = (SilcClientEntry)id_cache->context;
1325 SILC_GET32_MSB(mode, tmp);
1326 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1327 if (chu->client == client_entry) {
1333 /* Notify application */
1334 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1335 silc_free(client_id);
1336 silc_free(channel_id);
1339 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1340 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1341 silc_client_command_reply_free(cmd);
1344 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1346 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1347 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1348 SilcCommandStatus status;
1351 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1352 SILC_GET16_MSB(status, tmp);
1353 if (status != SILC_STATUS_OK) {
1354 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1355 "%s", silc_client_command_status_message(status));
1356 COMMAND_REPLY_ERROR;
1360 /* Notify application */
1361 COMMAND_REPLY((ARGS));
1364 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1365 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1366 silc_client_command_reply_free(cmd);
1369 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1371 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1372 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1373 SilcCommandStatus status;
1376 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1377 SILC_GET16_MSB(status, tmp);
1378 if (status != SILC_STATUS_OK) {
1379 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1380 "%s", silc_client_command_status_message(status));
1381 COMMAND_REPLY_ERROR;
1385 /* Notify application */
1386 COMMAND_REPLY((ARGS));
1389 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1390 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1391 silc_client_command_reply_free(cmd);
1394 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1396 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1397 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1398 SilcCommandStatus status;
1401 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1402 SILC_GET16_MSB(status, tmp);
1403 if (status != SILC_STATUS_OK) {
1404 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1405 "%s", silc_client_command_status_message(status));
1406 COMMAND_REPLY_ERROR;
1410 /* Notify application */
1411 COMMAND_REPLY((ARGS));
1414 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1415 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1416 silc_client_command_reply_free(cmd);
1419 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1421 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1422 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1423 SilcCommandStatus status;
1426 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1427 SILC_GET16_MSB(status, tmp);
1428 if (status != SILC_STATUS_OK) {
1429 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1430 "%s", silc_client_command_status_message(status));
1431 COMMAND_REPLY_ERROR;
1435 /* Notify application */
1436 COMMAND_REPLY((ARGS));
1439 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1440 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1441 silc_client_command_reply_free(cmd);
1444 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1446 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1447 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1448 SilcCommandStatus status;
1449 SilcIDCacheEntry id_cache = NULL;
1450 SilcChannelEntry channel;
1451 SilcChannelID *channel_id;
1455 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1456 SILC_GET16_MSB(status, tmp);
1457 if (status != SILC_STATUS_OK) {
1458 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1459 "%s", silc_client_command_status_message(status));
1460 COMMAND_REPLY_ERROR;
1464 /* Take Channel ID */
1465 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1469 channel_id = silc_id_payload_parse_id(tmp, len);
1473 /* Get the channel entry */
1474 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1476 silc_free(channel_id);
1477 COMMAND_REPLY_ERROR;
1481 channel = (SilcChannelEntry)id_cache->context;
1483 /* Get the ban list */
1484 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1486 /* Notify application */
1487 COMMAND_REPLY((ARGS, channel, tmp));
1490 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1491 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1492 silc_client_command_reply_free(cmd);
1495 SILC_CLIENT_CMD_REPLY_FUNC(close)
1497 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1498 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1499 SilcCommandStatus status;
1502 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1503 SILC_GET16_MSB(status, tmp);
1504 if (status != SILC_STATUS_OK) {
1505 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1506 "%s", silc_client_command_status_message(status));
1507 COMMAND_REPLY_ERROR;
1511 /* Notify application */
1512 COMMAND_REPLY((ARGS));
1515 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1516 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1517 silc_client_command_reply_free(cmd);
1520 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1522 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1523 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1524 SilcCommandStatus status;
1527 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1528 SILC_GET16_MSB(status, tmp);
1529 if (status != SILC_STATUS_OK) {
1530 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1531 "%s", silc_client_command_status_message(status));
1532 COMMAND_REPLY_ERROR;
1536 /* Notify application */
1537 COMMAND_REPLY((ARGS));
1540 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1541 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1542 silc_client_command_reply_free(cmd);
1545 /* Reply to LEAVE command. */
1547 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1549 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1550 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1551 SilcCommandStatus status;
1554 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1555 SILC_GET16_MSB(status, tmp);
1556 if (status != SILC_STATUS_OK) {
1557 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1558 "%s", silc_client_command_status_message(status));
1559 COMMAND_REPLY_ERROR;
1563 /* Notify application */
1564 COMMAND_REPLY((ARGS));
1567 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1568 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1569 silc_client_command_reply_free(cmd);
1572 /* Reply to USERS command. Received list of client ID's and theirs modes
1573 on the channel we requested. */
1575 SILC_CLIENT_CMD_REPLY_FUNC(users)
1577 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1578 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1579 SilcCommandStatus status;
1580 SilcIDCacheEntry id_cache = NULL;
1581 SilcChannelEntry channel;
1582 SilcChannelUser chu;
1583 SilcChannelID *channel_id = NULL;
1584 SilcBuffer client_id_list = NULL;
1585 SilcBuffer client_mode_list = NULL;
1587 uint32 tmp_len, list_count;
1589 unsigned char **res_argv = NULL;
1590 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1592 SILC_LOG_DEBUG(("Start"));
1594 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1595 SILC_GET16_MSB(status, tmp);
1596 if (status != SILC_STATUS_OK) {
1597 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1598 "%s", silc_client_command_status_message(status));
1599 COMMAND_REPLY_ERROR;
1603 /* Get channel ID */
1604 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1606 COMMAND_REPLY_ERROR;
1609 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1611 COMMAND_REPLY_ERROR;
1615 /* Get the list count */
1616 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1618 COMMAND_REPLY_ERROR;
1621 SILC_GET32_MSB(list_count, tmp);
1623 /* Get Client ID list */
1624 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1626 COMMAND_REPLY_ERROR;
1630 client_id_list = silc_buffer_alloc(tmp_len);
1631 silc_buffer_pull_tail(client_id_list, tmp_len);
1632 silc_buffer_put(client_id_list, tmp, tmp_len);
1634 /* Get client mode list */
1635 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1637 COMMAND_REPLY_ERROR;
1641 client_mode_list = silc_buffer_alloc(tmp_len);
1642 silc_buffer_pull_tail(client_mode_list, tmp_len);
1643 silc_buffer_put(client_mode_list, tmp, tmp_len);
1645 /* Get channel entry */
1646 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1648 /* Resolve the channel from server */
1649 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1651 /* Register pending command callback. After we've received the channel
1652 information we will reprocess this command reply by re-calling this
1653 USERS command reply callback. */
1654 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1655 NULL, silc_client_command_reply_users, cmd);
1658 channel = (SilcChannelEntry)id_cache->context;
1661 /* Remove old client list from channel. */
1662 silc_list_start(channel->clients);
1663 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1664 silc_list_del(channel->clients, chu);
1668 /* Cache the received Client ID's and modes. */
1669 for (i = 0; i < list_count; i++) {
1672 SilcClientID *client_id;
1673 SilcClientEntry client;
1676 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1678 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1683 SILC_GET32_MSB(mode, client_mode_list->data);
1685 /* Check if we have this client cached already. */
1687 silc_idcache_find_by_id_one_ext(conn->client_cache,
1690 silc_hash_client_id_compare, NULL,
1693 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1694 !((SilcClientEntry)id_cache->context)->realname) {
1695 /* No we don't have it (or it is incomplete in information), query
1696 it from the server. Assemble argument table that will be sent
1697 for the WHOIS command later. */
1698 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1700 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1702 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1704 res_argv[res_argc] = client_id_list->data;
1705 res_argv_lens[res_argc] = idp_len;
1706 res_argv_types[res_argc] = res_argc + 3;
1709 /* Found the client, join it to the channel */
1710 client = (SilcClientEntry)id_cache->context;
1711 chu = silc_calloc(1, sizeof(*chu));
1712 chu->client = client;
1714 silc_list_add(channel->clients, chu);
1716 silc_free(client_id);
1720 silc_buffer_pull(client_id_list, idp_len);
1721 silc_buffer_pull(client_mode_list, 4);
1724 /* Query the client information from server if the list included clients
1725 that we don't know about. */
1729 /* Send the WHOIS command to server */
1730 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1731 res_argc, res_argv, res_argv_lens,
1732 res_argv_types, ++conn->cmd_ident);
1733 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1734 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1737 /* Register pending command callback. After we've received the WHOIS
1738 command reply we will reprocess this command reply by re-calling this
1739 USERS command reply callback. */
1740 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1741 NULL, silc_client_command_reply_users, cmd);
1743 silc_buffer_free(res_cmd);
1745 silc_free(channel_id);
1747 silc_free(res_argv);
1748 silc_free(res_argv_lens);
1749 silc_free(res_argv_types);
1753 /* Notify application */
1754 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1757 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1758 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1759 silc_client_command_reply_free(cmd);
1760 silc_free(channel_id);
1762 silc_buffer_free(client_id_list);
1763 if (client_mode_list)
1764 silc_buffer_free(client_mode_list);
1767 /* Received command reply to GETKEY command. WE've received the remote
1768 client's public key. */
1770 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1772 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1773 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1774 SilcCommandStatus status;
1775 SilcIDCacheEntry id_cache;
1776 SilcIDPayload idp = NULL;
1777 SilcClientID *client_id = NULL;
1778 SilcClientEntry client_entry;
1779 SilcServerID *server_id = NULL;
1780 SilcServerEntry server_entry;
1782 unsigned char *tmp, *pk;
1786 SilcPublicKey public_key = NULL;
1788 SILC_LOG_DEBUG(("Start"));
1790 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1791 SILC_GET16_MSB(status, tmp);
1792 if (status != SILC_STATUS_OK) {
1793 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1794 "%s", silc_client_command_status_message(status));
1795 COMMAND_REPLY_ERROR;
1799 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1801 COMMAND_REPLY_ERROR;
1804 idp = silc_id_payload_parse_data(tmp, len);
1806 COMMAND_REPLY_ERROR;
1810 /* Get the public key payload */
1811 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1813 /* Decode the public key */
1814 SILC_GET16_MSB(pk_len, tmp);
1815 SILC_GET16_MSB(type, tmp + 2);
1818 if (type != SILC_SKE_PK_TYPE_SILC) {
1819 COMMAND_REPLY_ERROR;
1823 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1824 COMMAND_REPLY_ERROR;
1829 id_type = silc_id_payload_get_type(idp);
1830 if (id_type == SILC_ID_CLIENT) {
1831 /* Received client's public key */
1832 client_id = silc_id_payload_get_id(idp);
1833 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1836 silc_hash_client_id_compare, NULL,
1838 COMMAND_REPLY_ERROR;
1842 client_entry = (SilcClientEntry)id_cache->context;
1844 /* Notify application */
1845 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1846 } else if (id_type == SILC_ID_SERVER) {
1847 /* Received server's public key */
1848 server_id = silc_id_payload_get_id(idp);
1849 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1851 COMMAND_REPLY_ERROR;
1855 server_entry = (SilcServerEntry)id_cache->context;
1857 /* Notify application */
1858 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1862 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1863 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1865 silc_id_payload_free(idp);
1867 silc_pkcs_public_key_free(public_key);
1868 silc_free(client_id);
1869 silc_free(server_id);
1870 silc_client_command_reply_free(cmd);