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