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 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
297 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
299 /* Notify application */
301 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
302 channels, mode, idle));
305 silc_buffer_free(channels);
308 /* Received reply for WHOIS command. This maybe called several times
309 for one WHOIS command as server may reply with list of results. */
311 SILC_CLIENT_CMD_REPLY_FUNC(whois)
313 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
314 SilcCommandStatus status;
316 COMMAND_CHECK_STATUS_LIST;
318 /* Save WHOIS info */
319 silc_client_command_reply_whois_save(cmd, status);
321 /* Pending callbacks are not executed if this was an list entry */
322 if (status != SILC_STATUS_OK &&
323 status != SILC_STATUS_LIST_END) {
324 silc_client_command_reply_free(cmd);
329 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
330 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
331 silc_client_command_reply_free(cmd);
334 /* Received reply for WHOWAS command. */
336 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
338 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
339 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
340 SilcCommandStatus status;
341 SilcClientID *client_id;
342 SilcIDCacheEntry id_cache = NULL;
343 SilcClientEntry client_entry = NULL;
345 unsigned char *id_data;
346 char *nickname, *username;
347 char *realname = NULL;
349 COMMAND_CHECK_STATUS_LIST;
351 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
357 client_id = silc_id_payload_parse_id(id_data, len);
363 /* Get the client entry, if exists */
364 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
366 silc_hash_client_id_compare, NULL,
368 client_entry = (SilcClientEntry)id_cache->context;
369 silc_free(client_id);
371 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
372 username = silc_argument_get_arg_type(cmd->args, 4, &len);
373 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
374 if (!nickname || !username) {
379 /* Notify application. We don't save any history information to any
380 cache. Just pass the data to the application for displaying on
382 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
384 /* Pending callbacks are not executed if this was an list entry */
385 if (status != SILC_STATUS_OK &&
386 status != SILC_STATUS_LIST_END) {
387 silc_client_command_reply_free(cmd);
392 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
393 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS);
394 silc_client_command_reply_free(cmd);
398 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
399 SilcCommandStatus status)
401 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
402 SilcClient client = cmd->client;
403 SilcClientID *client_id = NULL;
404 SilcServerID *server_id = NULL;
405 SilcChannelID *channel_id = NULL;
406 SilcIDCacheEntry id_cache = NULL;
407 SilcClientEntry client_entry;
408 SilcServerEntry server_entry;
409 SilcChannelEntry channel_entry;
412 unsigned char *id_data;
413 char *name = NULL, *info = NULL;
414 SilcIDPayload idp = NULL;
417 argc = silc_argument_get_arg_num(cmd->args);
419 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
424 idp = silc_id_payload_parse_data(id_data, len);
430 name = silc_argument_get_arg_type(cmd->args, 3, &len);
431 info = silc_argument_get_arg_type(cmd->args, 4, &len);
433 id_type = silc_id_payload_get_type(idp);
437 client_id = silc_id_payload_get_id(idp);
439 SILC_LOG_DEBUG(("Received client information"));
441 /* Check if we have this client cached already. */
442 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
445 silc_hash_client_id_compare, NULL,
447 SILC_LOG_DEBUG(("Adding new client entry"));
449 silc_client_add_client(cmd->client, conn, name, info, NULL,
450 silc_id_dup(client_id, id_type), 0);
452 client_entry = (SilcClientEntry)id_cache->context;
453 silc_client_update_client(cmd->client, conn, client_entry,
454 name, info, NULL, 0);
457 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
458 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
460 /* Notify application */
461 COMMAND_REPLY((ARGS, client_entry, name, info));
465 server_id = silc_id_payload_get_id(idp);
467 SILC_LOG_DEBUG(("Received server information"));
469 /* Check if we have this server cached already. */
470 if (!silc_idcache_find_by_id_one(conn->server_cache,
471 (void *)server_id, &id_cache)) {
472 SILC_LOG_DEBUG(("Adding new server entry"));
474 server_entry = silc_calloc(1, sizeof(*server_entry));
475 server_entry->server_id = silc_id_dup(server_id, id_type);
477 server_entry->server_name = strdup(name);
479 server_entry->server_info = strdup(info);
481 /* Add server to cache */
482 silc_idcache_add(conn->server_cache, server_entry->server_name,
483 server_entry->server_id, (void *)server_entry, FALSE);
485 server_entry = (SilcServerEntry)id_cache->context;
488 /* Notify application */
489 COMMAND_REPLY((ARGS, server_entry, name, info));
492 case SILC_ID_CHANNEL:
493 channel_id = silc_id_payload_get_id(idp);
495 SILC_LOG_DEBUG(("Received channel information"));
497 /* Check if we have this channel cached already. */
498 if (!silc_idcache_find_by_id_one(conn->channel_cache,
499 (void *)channel_id, &id_cache)) {
503 SILC_LOG_DEBUG(("Adding new channel entry"));
504 channel_entry = silc_client_new_channel_id(client, conn->sock,
505 strdup(name), 0, idp);
507 channel_entry = (SilcChannelEntry)id_cache->context;
510 /* Notify application */
511 COMMAND_REPLY((ARGS, channel_entry, name, info));
515 silc_id_payload_free(idp);
516 silc_free(client_id);
517 silc_free(server_id);
518 silc_free(channel_id);
521 /* Received reply for IDENTIFY command. This maybe called several times
522 for one IDENTIFY command as server may reply with list of results.
523 This is totally silent and does not print anything on screen. */
525 SILC_CLIENT_CMD_REPLY_FUNC(identify)
527 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
528 SilcCommandStatus status;
530 COMMAND_CHECK_STATUS_LIST;
532 /* Save IDENTIFY info */
533 silc_client_command_reply_identify_save(cmd, status);
535 /* Pending callbacks are not executed if this was an list entry */
536 if (status != SILC_STATUS_OK &&
537 status != SILC_STATUS_LIST_END) {
538 silc_client_command_reply_free(cmd);
543 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
544 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
545 silc_client_command_reply_free(cmd);
548 /* Received reply for command NICK. If everything went without errors
549 we just received our new Client ID. */
551 SILC_CLIENT_CMD_REPLY_FUNC(nick)
553 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
554 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
555 SilcCommandStatus status;
560 SILC_LOG_DEBUG(("Start"));
562 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
563 if (status != SILC_STATUS_OK) {
564 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
565 "Cannot set nickname: %s",
566 silc_client_command_status_message(status));
571 argc = silc_argument_get_arg_num(cmd->args);
572 if (argc < 2 || argc > 2) {
573 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
574 "Cannot set nickname: bad reply to command");
579 /* Take received Client ID */
580 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
581 idp = silc_id_payload_parse_data(tmp, len);
586 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
588 /* Notify application */
589 COMMAND_REPLY((ARGS, conn->local_entry));
592 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
593 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
594 silc_client_command_reply_free(cmd);
597 /* Received reply to the LIST command. */
599 SILC_CLIENT_CMD_REPLY_FUNC(list)
601 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
602 SilcCommandStatus status;
603 unsigned char *tmp, *name, *topic;
604 uint32 usercount = 0;
606 COMMAND_CHECK_STATUS_LIST;
608 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
609 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
610 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
612 SILC_GET32_MSB(usercount, tmp);
614 /* Notify application */
615 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
617 /* Pending callbacks are not executed if this was an list entry */
618 if (status != SILC_STATUS_OK &&
619 status != SILC_STATUS_LIST_END) {
620 silc_client_command_reply_free(cmd);
625 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
626 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
627 silc_client_command_reply_free(cmd);
630 /* Received reply to topic command. */
632 SILC_CLIENT_CMD_REPLY_FUNC(topic)
634 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
635 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
636 SilcCommandStatus status;
637 SilcChannelEntry channel;
638 SilcChannelID *channel_id = NULL;
639 SilcIDCacheEntry id_cache = NULL;
644 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
645 if (status != SILC_STATUS_OK) {
646 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
647 "%s", silc_client_command_status_message(status));
652 argc = silc_argument_get_arg_num(cmd->args);
653 if (argc < 1 || argc > 3) {
658 /* Take Channel ID */
659 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
664 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
668 channel_id = silc_id_payload_parse_id(tmp, len);
672 /* Get the channel entry */
673 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
675 silc_free(channel_id);
680 channel = (SilcChannelEntry)id_cache->context;
682 /* Notify application */
683 COMMAND_REPLY((ARGS, channel, topic));
686 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
687 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
688 silc_client_command_reply_free(cmd);
691 /* Received reply to invite command. */
693 SILC_CLIENT_CMD_REPLY_FUNC(invite)
695 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
696 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
697 SilcCommandStatus status;
698 SilcChannelEntry channel;
699 SilcChannelID *channel_id;
700 SilcIDCacheEntry id_cache;
704 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
705 SILC_GET16_MSB(status, tmp);
706 if (status != SILC_STATUS_OK) {
707 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
708 "%s", silc_client_command_status_message(status));
713 /* Take Channel ID */
714 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
718 channel_id = silc_id_payload_parse_id(tmp, len);
722 /* Get the channel entry */
723 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
725 silc_free(channel_id);
730 channel = (SilcChannelEntry)id_cache->context;
732 /* Get the invite list */
733 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
735 /* Notify application */
736 COMMAND_REPLY((ARGS, channel, tmp));
739 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
740 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
741 silc_client_command_reply_free(cmd);
744 /* Received reply to the KILL command. */
746 SILC_CLIENT_CMD_REPLY_FUNC(kill)
748 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
749 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
750 SilcCommandStatus status;
752 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
753 if (status != SILC_STATUS_OK) {
754 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
755 "%s", silc_client_command_status_message(status));
760 /* Notify application */
761 COMMAND_REPLY((ARGS));
764 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
765 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
766 silc_client_command_reply_free(cmd);
769 /* Received reply to INFO command. We receive the server ID and some
770 information about the server user requested. */
772 SILC_CLIENT_CMD_REPLY_FUNC(info)
774 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
775 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
776 SilcCommandStatus status;
778 SilcIDCacheEntry id_cache;
779 SilcServerEntry server;
780 SilcServerID *server_id = NULL;
781 char *server_name, *server_info;
784 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
785 SILC_GET16_MSB(status, tmp);
786 if (status != SILC_STATUS_OK) {
787 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
788 "%s", silc_client_command_status_message(status));
794 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
798 server_id = silc_id_payload_parse_id(tmp, len);
802 /* Get server name */
803 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
807 /* Get server info */
808 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
812 /* See whether we have this server cached. If not create it. */
813 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
815 SILC_LOG_DEBUG(("New server entry"));
817 server = silc_calloc(1, sizeof(*server));
818 server->server_name = strdup(server_name);
819 server->server_info = strdup(server_info);
820 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
822 /* Add it to the cache */
823 silc_idcache_add(conn->server_cache, server->server_name,
824 server->server_id, (void *)server, FALSE);
826 server = (SilcServerEntry)id_cache->context;
829 /* Notify application */
830 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
833 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
834 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
835 silc_free(server_id);
836 silc_client_command_reply_free(cmd);
839 /* Received reply to PING command. The reply time is shown to user. */
841 SILC_CLIENT_CMD_REPLY_FUNC(ping)
843 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
844 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
845 SilcCommandStatus status;
848 time_t diff, curtime;
850 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
851 if (status != SILC_STATUS_OK) {
852 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
853 "%s", silc_client_command_status_message(status));
858 curtime = time(NULL);
859 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
860 cmd->packet->src_id_type);
866 for (i = 0; i < conn->ping_count; i++) {
867 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
868 diff = curtime - conn->ping[i].start_time;
869 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
870 "Ping reply from %s: %d second%s",
871 conn->ping[i].dest_name, diff,
872 diff == 1 ? "" : "s");
874 conn->ping[i].start_time = 0;
875 silc_free(conn->ping[i].dest_id);
876 conn->ping[i].dest_id = NULL;
877 silc_free(conn->ping[i].dest_name);
878 conn->ping[i].dest_name = NULL;
885 /* Notify application */
886 COMMAND_REPLY((ARGS));
889 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
890 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
891 silc_client_command_reply_free(cmd);
894 /* Received reply for JOIN command. */
896 SILC_CLIENT_CMD_REPLY_FUNC(join)
898 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
899 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
900 SilcCommandStatus status;
901 SilcIDPayload idp = NULL;
902 SilcChannelEntry channel;
903 SilcIDCacheEntry id_cache = NULL;
905 uint32 argc, mode, len, list_count;
906 char *topic, *tmp, *channel_name = NULL, *hmac;
907 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
910 SILC_LOG_DEBUG(("Start"));
912 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
913 if (status != SILC_STATUS_OK) {
914 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
915 "%s", silc_client_command_status_message(status));
920 argc = silc_argument_get_arg_num(cmd->args);
921 if (argc < 7 || argc > 14) {
922 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
923 "Cannot join channel: Bad reply packet");
928 /* Get channel name */
929 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
931 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
932 "Cannot join channel: Bad reply packet");
936 channel_name = strdup(tmp);
939 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
941 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
942 "Cannot join channel: Bad reply packet");
944 silc_free(channel_name);
947 idp = silc_id_payload_parse_data(tmp, len);
950 silc_free(channel_name);
954 /* Get channel mode */
955 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
957 SILC_GET32_MSB(mode, tmp);
961 /* Get channel key */
962 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
964 keyp = silc_buffer_alloc(len);
965 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
966 silc_buffer_put(keyp, tmp, len);
970 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
972 /* If we have the channel entry, remove it and create a new one */
973 channel = silc_client_get_channel(cmd->client, conn, channel_name);
975 silc_client_del_channel(cmd->client, conn, channel);
977 /* Save received Channel ID. This actually creates the channel */
978 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
980 silc_id_payload_free(idp);
982 conn->current_channel = channel;
985 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
987 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
988 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
989 "Cannot join channel: Unsupported HMAC `%s'",
992 silc_free(channel_name);
997 /* Get the list count */
998 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1001 SILC_GET32_MSB(list_count, tmp);
1003 /* Get Client ID list */
1004 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1008 client_id_list = silc_buffer_alloc(len);
1009 silc_buffer_pull_tail(client_id_list, len);
1010 silc_buffer_put(client_id_list, tmp, len);
1012 /* Get client mode list */
1013 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1017 client_mode_list = silc_buffer_alloc(len);
1018 silc_buffer_pull_tail(client_mode_list, len);
1019 silc_buffer_put(client_mode_list, tmp, len);
1021 /* Add clients we received in the reply to the channel */
1022 for (i = 0; i < list_count; i++) {
1025 SilcClientID *client_id;
1026 SilcClientEntry client_entry;
1029 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1031 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1036 SILC_GET32_MSB(mode, client_mode_list->data);
1038 /* Check if we have this client cached already. */
1039 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1042 silc_hash_client_id_compare, NULL,
1044 /* No, we don't have it, add entry for it. */
1046 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1047 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1049 /* Yes, we have it already */
1050 client_entry = (SilcClientEntry)id_cache->context;
1053 /* Join the client to the channel */
1054 chu = silc_calloc(1, sizeof(*chu));
1055 chu->client = client_entry;
1057 silc_list_add(channel->clients, chu);
1058 silc_free(client_id);
1060 silc_buffer_pull(client_id_list, idp_len);
1061 silc_buffer_pull(client_mode_list, 4);
1063 silc_buffer_push(client_id_list, client_id_list->data -
1064 client_id_list->head);
1065 silc_buffer_push(client_mode_list, client_mode_list->data -
1066 client_mode_list->head);
1068 /* Save channel key */
1069 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1070 silc_client_save_channel_key(conn, keyp, channel);
1072 /* Client is now joined to the channel */
1073 channel->on_channel = TRUE;
1075 /* Notify application */
1076 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1077 keyp ? keyp->head : NULL, NULL,
1078 NULL, topic, hmac, list_count, client_id_list,
1082 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1083 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1084 silc_client_command_reply_free(cmd);
1087 silc_buffer_free(keyp);
1089 silc_buffer_free(client_id_list);
1090 if (client_mode_list)
1091 silc_buffer_free(client_mode_list);
1094 /* Received reply for MOTD command */
1096 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1098 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1099 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1100 SilcCommandStatus status;
1103 char *motd = NULL, *cp, line[256];
1105 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1106 SILC_GET16_MSB(status, tmp);
1107 if (status != SILC_STATUS_OK) {
1108 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1109 "%s", silc_client_command_status_message(status));
1110 COMMAND_REPLY_ERROR;
1114 argc = silc_argument_get_arg_num(cmd->args);
1116 COMMAND_REPLY_ERROR;
1121 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1123 COMMAND_REPLY_ERROR;
1130 if (cp[i++] == '\n') {
1131 memset(line, 0, sizeof(line));
1132 strncat(line, cp, i - 1);
1138 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1148 /* Notify application */
1149 COMMAND_REPLY((ARGS, motd));
1152 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1153 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1154 silc_client_command_reply_free(cmd);
1157 /* Received reply tot he UMODE command. Save the current user mode */
1159 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1161 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1162 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1163 SilcCommandStatus status;
1167 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1168 SILC_GET16_MSB(status, tmp);
1169 if (status != SILC_STATUS_OK) {
1170 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1171 "%s", silc_client_command_status_message(status));
1172 COMMAND_REPLY_ERROR;
1176 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1178 COMMAND_REPLY_ERROR;
1182 SILC_GET32_MSB(mode, tmp);
1183 conn->local_entry->mode = mode;
1185 /* Notify application */
1186 COMMAND_REPLY((ARGS, mode));
1189 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1190 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1191 silc_client_command_reply_free(cmd);
1194 /* Received reply for CMODE command. */
1196 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1198 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1199 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1200 SilcCommandStatus status;
1203 SilcIDCacheEntry id_cache;
1204 SilcChannelID *channel_id;
1205 SilcChannelEntry channel;
1208 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1209 if (status != SILC_STATUS_OK) {
1210 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1211 "%s", silc_client_command_status_message(status));
1212 COMMAND_REPLY_ERROR;
1216 /* Take Channel ID */
1217 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1220 channel_id = silc_id_payload_parse_id(tmp, len);
1224 /* Get the channel entry */
1225 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1227 silc_free(channel_id);
1228 COMMAND_REPLY_ERROR;
1232 channel = (SilcChannelEntry)id_cache->context;
1234 /* Get channel mode */
1235 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1237 silc_free(channel_id);
1238 COMMAND_REPLY_ERROR;
1243 SILC_GET32_MSB(mode, tmp);
1244 channel->mode = mode;
1246 /* Notify application */
1247 COMMAND_REPLY((ARGS, channel, mode));
1249 silc_free(channel_id);
1252 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1253 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1254 silc_client_command_reply_free(cmd);
1257 /* Received reply for CUMODE command */
1259 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1261 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1262 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1263 SilcCommandStatus status;
1264 SilcIDCacheEntry id_cache = NULL;
1265 SilcClientID *client_id;
1266 SilcChannelID *channel_id;
1267 SilcClientEntry client_entry;
1268 SilcChannelEntry channel;
1269 SilcChannelUser chu;
1270 unsigned char *modev, *tmp, *id;
1273 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1274 if (status != SILC_STATUS_OK) {
1275 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1276 "%s", silc_client_command_status_message(status));
1277 COMMAND_REPLY_ERROR;
1281 /* Get channel mode */
1282 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1284 COMMAND_REPLY_ERROR;
1288 /* Take Channel ID */
1289 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1292 channel_id = silc_id_payload_parse_id(tmp, len);
1296 /* Get the channel entry */
1297 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1299 silc_free(channel_id);
1300 COMMAND_REPLY_ERROR;
1304 channel = (SilcChannelEntry)id_cache->context;
1307 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1309 silc_free(channel_id);
1310 COMMAND_REPLY_ERROR;
1313 client_id = silc_id_payload_parse_id(id, len);
1315 silc_free(channel_id);
1316 COMMAND_REPLY_ERROR;
1320 /* Get client entry */
1321 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1323 silc_hash_client_id_compare, NULL,
1325 silc_free(channel_id);
1326 silc_free(client_id);
1327 COMMAND_REPLY_ERROR;
1331 client_entry = (SilcClientEntry)id_cache->context;
1334 SILC_GET32_MSB(mode, modev);
1335 silc_list_start(channel->clients);
1336 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1337 if (chu->client == client_entry) {
1343 /* Notify application */
1344 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1345 silc_free(client_id);
1346 silc_free(channel_id);
1349 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1350 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1351 silc_client_command_reply_free(cmd);
1354 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1356 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1357 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1358 SilcCommandStatus status;
1361 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1362 SILC_GET16_MSB(status, tmp);
1363 if (status != SILC_STATUS_OK) {
1364 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1365 "%s", silc_client_command_status_message(status));
1366 COMMAND_REPLY_ERROR;
1370 /* Notify application */
1371 COMMAND_REPLY((ARGS));
1374 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1375 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1376 silc_client_command_reply_free(cmd);
1379 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1381 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1382 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1383 SilcCommandStatus status;
1386 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1387 SILC_GET16_MSB(status, tmp);
1388 if (status != SILC_STATUS_OK) {
1389 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1390 "%s", silc_client_command_status_message(status));
1391 COMMAND_REPLY_ERROR;
1395 /* Notify application */
1396 COMMAND_REPLY((ARGS));
1399 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1400 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1401 silc_client_command_reply_free(cmd);
1404 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1406 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1407 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1408 SilcCommandStatus status;
1411 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1412 SILC_GET16_MSB(status, tmp);
1413 if (status != SILC_STATUS_OK) {
1414 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1415 "%s", silc_client_command_status_message(status));
1416 COMMAND_REPLY_ERROR;
1420 /* Notify application */
1421 COMMAND_REPLY((ARGS));
1424 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1425 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1426 silc_client_command_reply_free(cmd);
1429 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1431 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1432 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1433 SilcCommandStatus status;
1436 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1437 SILC_GET16_MSB(status, tmp);
1438 if (status != SILC_STATUS_OK) {
1439 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1440 "%s", silc_client_command_status_message(status));
1441 COMMAND_REPLY_ERROR;
1445 /* Notify application */
1446 COMMAND_REPLY((ARGS));
1449 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1450 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1451 silc_client_command_reply_free(cmd);
1454 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1456 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1457 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1458 SilcCommandStatus status;
1459 SilcIDCacheEntry id_cache = NULL;
1460 SilcChannelEntry channel;
1461 SilcChannelID *channel_id;
1465 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1466 SILC_GET16_MSB(status, tmp);
1467 if (status != SILC_STATUS_OK) {
1468 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1469 "%s", silc_client_command_status_message(status));
1470 COMMAND_REPLY_ERROR;
1474 /* Take Channel ID */
1475 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1479 channel_id = silc_id_payload_parse_id(tmp, len);
1483 /* Get the channel entry */
1484 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1486 silc_free(channel_id);
1487 COMMAND_REPLY_ERROR;
1491 channel = (SilcChannelEntry)id_cache->context;
1493 /* Get the ban list */
1494 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1496 /* Notify application */
1497 COMMAND_REPLY((ARGS, channel, tmp));
1500 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1501 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1502 silc_client_command_reply_free(cmd);
1505 SILC_CLIENT_CMD_REPLY_FUNC(close)
1507 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1508 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1509 SilcCommandStatus status;
1512 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1513 SILC_GET16_MSB(status, tmp);
1514 if (status != SILC_STATUS_OK) {
1515 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1516 "%s", silc_client_command_status_message(status));
1517 COMMAND_REPLY_ERROR;
1521 /* Notify application */
1522 COMMAND_REPLY((ARGS));
1525 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1526 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1527 silc_client_command_reply_free(cmd);
1530 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1532 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1533 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1534 SilcCommandStatus status;
1537 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1538 SILC_GET16_MSB(status, tmp);
1539 if (status != SILC_STATUS_OK) {
1540 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1541 "%s", silc_client_command_status_message(status));
1542 COMMAND_REPLY_ERROR;
1546 /* Notify application */
1547 COMMAND_REPLY((ARGS));
1550 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1551 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1552 silc_client_command_reply_free(cmd);
1555 /* Reply to LEAVE command. */
1557 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1559 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1560 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1561 SilcCommandStatus status;
1564 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1565 SILC_GET16_MSB(status, tmp);
1566 if (status != SILC_STATUS_OK) {
1567 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1568 "%s", silc_client_command_status_message(status));
1569 COMMAND_REPLY_ERROR;
1573 /* Notify application */
1574 COMMAND_REPLY((ARGS));
1577 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1578 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1579 silc_client_command_reply_free(cmd);
1582 /* Reply to USERS command. Received list of client ID's and theirs modes
1583 on the channel we requested. */
1585 SILC_CLIENT_CMD_REPLY_FUNC(users)
1587 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1588 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1589 SilcCommandStatus status;
1590 SilcIDCacheEntry id_cache = NULL;
1591 SilcChannelEntry channel;
1592 SilcChannelUser chu;
1593 SilcChannelID *channel_id = NULL;
1594 SilcBuffer client_id_list = NULL;
1595 SilcBuffer client_mode_list = NULL;
1597 uint32 tmp_len, list_count;
1599 unsigned char **res_argv = NULL;
1600 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1602 SILC_LOG_DEBUG(("Start"));
1604 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1605 SILC_GET16_MSB(status, tmp);
1606 if (status != SILC_STATUS_OK) {
1607 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1608 "%s", silc_client_command_status_message(status));
1609 COMMAND_REPLY_ERROR;
1613 /* Get channel ID */
1614 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1616 COMMAND_REPLY_ERROR;
1619 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1621 COMMAND_REPLY_ERROR;
1625 /* Get the list count */
1626 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1628 COMMAND_REPLY_ERROR;
1631 SILC_GET32_MSB(list_count, tmp);
1633 /* Get Client ID list */
1634 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1636 COMMAND_REPLY_ERROR;
1640 client_id_list = silc_buffer_alloc(tmp_len);
1641 silc_buffer_pull_tail(client_id_list, tmp_len);
1642 silc_buffer_put(client_id_list, tmp, tmp_len);
1644 /* Get client mode list */
1645 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1647 COMMAND_REPLY_ERROR;
1651 client_mode_list = silc_buffer_alloc(tmp_len);
1652 silc_buffer_pull_tail(client_mode_list, tmp_len);
1653 silc_buffer_put(client_mode_list, tmp, tmp_len);
1655 /* Get channel entry */
1656 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1658 /* Resolve the channel from server */
1659 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1661 /* Register pending command callback. After we've received the channel
1662 information we will reprocess this command reply by re-calling this
1663 USERS command reply callback. */
1664 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1665 NULL, silc_client_command_reply_users, cmd);
1668 channel = (SilcChannelEntry)id_cache->context;
1671 /* Remove old client list from channel. */
1672 silc_list_start(channel->clients);
1673 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1674 silc_list_del(channel->clients, chu);
1678 /* Cache the received Client ID's and modes. */
1679 for (i = 0; i < list_count; i++) {
1682 SilcClientID *client_id;
1683 SilcClientEntry client;
1686 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1688 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1693 SILC_GET32_MSB(mode, client_mode_list->data);
1695 /* Check if we have this client cached already. */
1697 silc_idcache_find_by_id_one_ext(conn->client_cache,
1700 silc_hash_client_id_compare, NULL,
1703 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1704 !((SilcClientEntry)id_cache->context)->realname) {
1706 if (id_cache && id_cache->context) {
1707 SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
1708 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1709 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
1710 silc_buffer_pull(client_id_list, idp_len);
1711 silc_buffer_pull(client_mode_list, 4);
1714 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1717 /* No we don't have it (or it is incomplete in information), query
1718 it from the server. Assemble argument table that will be sent
1719 for the WHOIS command later. */
1720 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1722 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1724 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1726 res_argv[res_argc] = client_id_list->data;
1727 res_argv_lens[res_argc] = idp_len;
1728 res_argv_types[res_argc] = res_argc + 3;
1731 /* Found the client, join it to the channel */
1732 client = (SilcClientEntry)id_cache->context;
1733 chu = silc_calloc(1, sizeof(*chu));
1734 chu->client = client;
1736 silc_list_add(channel->clients, chu);
1738 silc_free(client_id);
1742 silc_buffer_pull(client_id_list, idp_len);
1743 silc_buffer_pull(client_mode_list, 4);
1746 /* Query the client information from server if the list included clients
1747 that we don't know about. */
1751 /* Send the WHOIS command to server */
1752 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1753 res_argc, res_argv, res_argv_lens,
1754 res_argv_types, ++conn->cmd_ident);
1755 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1756 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1759 /* Register pending command callback. After we've received the WHOIS
1760 command reply we will reprocess this command reply by re-calling this
1761 USERS command reply callback. */
1762 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1763 NULL, silc_client_command_reply_users, cmd);
1765 silc_buffer_free(res_cmd);
1767 silc_free(channel_id);
1769 silc_free(res_argv);
1770 silc_free(res_argv_lens);
1771 silc_free(res_argv_types);
1775 /* Notify application */
1776 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1779 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1780 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1781 silc_client_command_reply_free(cmd);
1782 silc_free(channel_id);
1784 silc_buffer_free(client_id_list);
1785 if (client_mode_list)
1786 silc_buffer_free(client_mode_list);
1789 /* Received command reply to GETKEY command. WE've received the remote
1790 client's public key. */
1792 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1794 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1795 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1796 SilcCommandStatus status;
1797 SilcIDCacheEntry id_cache;
1798 SilcIDPayload idp = NULL;
1799 SilcClientID *client_id = NULL;
1800 SilcClientEntry client_entry;
1801 SilcServerID *server_id = NULL;
1802 SilcServerEntry server_entry;
1804 unsigned char *tmp, *pk;
1808 SilcPublicKey public_key = NULL;
1810 SILC_LOG_DEBUG(("Start"));
1812 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1813 SILC_GET16_MSB(status, tmp);
1814 if (status != SILC_STATUS_OK) {
1815 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1816 "%s", silc_client_command_status_message(status));
1817 COMMAND_REPLY_ERROR;
1821 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1823 COMMAND_REPLY_ERROR;
1826 idp = silc_id_payload_parse_data(tmp, len);
1828 COMMAND_REPLY_ERROR;
1832 /* Get the public key payload */
1833 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1835 /* Decode the public key */
1836 SILC_GET16_MSB(pk_len, tmp);
1837 SILC_GET16_MSB(type, tmp + 2);
1840 if (type != SILC_SKE_PK_TYPE_SILC) {
1841 COMMAND_REPLY_ERROR;
1845 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1846 COMMAND_REPLY_ERROR;
1851 id_type = silc_id_payload_get_type(idp);
1852 if (id_type == SILC_ID_CLIENT) {
1853 /* Received client's public key */
1854 client_id = silc_id_payload_get_id(idp);
1855 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1858 silc_hash_client_id_compare, NULL,
1860 COMMAND_REPLY_ERROR;
1864 client_entry = (SilcClientEntry)id_cache->context;
1866 /* Notify application */
1867 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1868 } else if (id_type == SILC_ID_SERVER) {
1869 /* Received server's public key */
1870 server_id = silc_id_payload_get_id(idp);
1871 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1873 COMMAND_REPLY_ERROR;
1877 server_entry = (SilcServerEntry)id_cache->context;
1879 /* Notify application */
1880 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1884 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1885 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1887 silc_id_payload_free(idp);
1889 silc_pkcs_public_key_free(public_key);
1890 silc_free(client_id);
1891 silc_free(server_id);
1892 silc_client_command_reply_free(cmd);