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(restart, RESTART),
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),
70 const SilcCommandStatusMessage silc_command_status_messages[] = {
72 { STAT(NO_SUCH_NICK), "There was no such nickname" },
73 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
74 { STAT(NO_SUCH_SERVER), "No such server" },
75 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
76 { STAT(NO_RECIPIENT), "No recipient given" },
77 { STAT(UNKNOWN_COMMAND), "Unknown command" },
78 { STAT(WILDCARDS), "Unknown command" },
79 { STAT(NO_CLIENT_ID), "No Client ID given" },
80 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
81 { STAT(NO_SERVER_ID), "No Server ID given" },
82 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
83 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
84 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
85 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
86 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
87 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
88 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
89 { STAT(USER_ON_CHANNEL), "User already on the channel" },
90 { STAT(NOT_REGISTERED), "You have not registered" },
91 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
92 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
93 { STAT(PERM_DENIED), "Permission denied" },
94 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
95 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
96 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
97 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
98 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
99 { STAT(UNKNOWN_MODE), "Unknown mode" },
100 { STAT(NOT_YOU), "Cannot change mode for other users" },
101 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
102 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
103 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
104 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
105 { STAT(BAD_NICKNAME), "Bad nickname" },
106 { STAT(BAD_CHANNEL), "Bad channel name" },
107 { STAT(AUTH_FAILED), "Authentication failed" },
108 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
112 /* Command reply operation that is called at the end of all command replys.
113 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
114 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
115 #define ARGS cmd->client, cmd->sock->user_data, \
116 cmd->payload, TRUE, silc_command_get(cmd->payload), status
118 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
119 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
120 cmd->sock->user_data, cmd->payload, FALSE, \
121 silc_command_get(cmd->payload), status)
123 /* Process received command reply. */
125 void silc_client_command_reply_process(SilcClient client,
126 SilcSocketConnection sock,
127 SilcPacketContext *packet)
129 SilcBuffer buffer = packet->buffer;
130 SilcClientCommandReply *cmd;
131 SilcClientCommandReplyContext ctx;
132 SilcCommandPayload payload;
134 unsigned short ident;
136 /* Get command reply payload from packet */
137 payload = silc_command_payload_parse(buffer);
139 /* Silently ignore bad reply packet */
140 SILC_LOG_DEBUG(("Bad command reply packet"));
144 /* Allocate command reply context. This must be free'd by the
145 command reply routine receiving it. */
146 ctx = silc_calloc(1, sizeof(*ctx));
147 ctx->client = client;
149 ctx->payload = payload;
150 ctx->args = silc_command_get_args(ctx->payload);
151 ctx->packet = packet;
152 ident = silc_command_get_ident(ctx->payload);
154 /* Check for pending commands and mark to be exeucted */
155 silc_client_command_pending_check(sock->user_data, ctx,
156 silc_command_get(ctx->payload), ident);
158 /* Execute command reply */
159 command = silc_command_get(ctx->payload);
160 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
161 if (cmd->cmd == command)
164 if (cmd == NULL || !cmd->cb) {
172 /* Returns status message string */
174 char *silc_client_command_status_message(SilcCommandStatus status)
178 for (i = 0; silc_command_status_messages[i].message; i++) {
179 if (silc_command_status_messages[i].status == status)
183 if (silc_command_status_messages[i].message == NULL)
186 return silc_command_status_messages[i].message;
189 /* Free command reply context and its internals. */
191 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
194 silc_command_free_payload(cmd->payload);
200 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
201 SilcCommandStatus status)
203 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
204 SilcClientID *client_id;
205 SilcIDCacheEntry id_cache = NULL;
206 SilcClientEntry client_entry = NULL;
208 unsigned char *id_data, *tmp;
209 char *nickname = NULL, *username = NULL;
210 char *realname = NULL;
211 unsigned int idle = 0, mode = 0;
213 argc = silc_argument_get_arg_num(cmd->args);
215 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
221 client_id = silc_id_payload_parse_id(id_data, len);
227 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
228 username = silc_argument_get_arg_type(cmd->args, 4, &len);
229 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
230 if (!nickname || !username || !realname) {
235 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
237 SILC_GET32_MSB(mode, tmp);
240 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
242 SILC_GET32_MSB(idle, tmp);
245 /* Check if we have this client cached already. */
246 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
247 SILC_ID_CLIENT, &id_cache)) {
248 SILC_LOG_DEBUG(("Adding new client entry"));
250 client_entry = silc_calloc(1, sizeof(*client_entry));
251 client_entry->id = client_id;
252 silc_parse_nickname(nickname, &client_entry->nickname,
253 &client_entry->server, &client_entry->num);
254 client_entry->username = strdup(username);
256 client_entry->realname = strdup(realname);
257 client_entry->mode = mode;
259 /* Add client to cache */
260 silc_idcache_add(conn->client_cache, client_entry->nickname,
261 SILC_ID_CLIENT, client_id, (void *)client_entry,
264 client_entry = (SilcClientEntry)id_cache->context;
265 if (client_entry->nickname)
266 silc_free(client_entry->nickname);
267 if (client_entry->server)
268 silc_free(client_entry->server);
269 if (client_entry->username)
270 silc_free(client_entry->username);
271 if (client_entry->realname)
272 silc_free(client_entry->realname);
273 client_entry->mode = mode;
275 SILC_LOG_DEBUG(("Updating client entry"));
277 silc_parse_nickname(nickname, &client_entry->nickname,
278 &client_entry->server, &client_entry->num);
279 client_entry->username = strdup(username);
281 client_entry->realname = strdup(realname);
283 id_cache->data = client_entry->nickname;
284 silc_idcache_sort_by_data(conn->client_cache);
286 silc_free(client_id);
289 /* Notify application */
291 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
295 /* Received reply for WHOIS command. This maybe called several times
296 for one WHOIS command as server may reply with list of results. */
298 SILC_CLIENT_CMD_REPLY_FUNC(whois)
300 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
301 SilcCommandStatus status;
304 SILC_LOG_DEBUG(("Start"));
306 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
307 SILC_GET16_MSB(status, tmp);
308 if (status != SILC_STATUS_OK &&
309 status != SILC_STATUS_LIST_START &&
310 status != SILC_STATUS_LIST_ITEM &&
311 status != SILC_STATUS_LIST_END) {
316 /* Display one whois reply */
317 if (status == SILC_STATUS_OK)
318 silc_client_command_reply_whois_save(cmd, status);
321 if (status == SILC_STATUS_LIST_START ||
322 status == SILC_STATUS_LIST_ITEM ||
323 status == SILC_STATUS_LIST_END)
324 silc_client_command_reply_whois_save(cmd, status);
326 /* Pending callbacks are not executed if this was an list entry */
327 if (status != SILC_STATUS_OK &&
328 status != SILC_STATUS_LIST_END) {
329 silc_client_command_reply_free(cmd);
333 /* Execute any pending command callbacks */
334 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
337 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
338 silc_client_command_reply_free(cmd);
341 /* Received reply for WHOWAS command. */
343 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
345 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
346 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
347 SilcCommandStatus status;
348 SilcClientID *client_id;
349 SilcIDCacheEntry id_cache = NULL;
350 SilcClientEntry client_entry = NULL;
352 unsigned char *id_data, *tmp;
353 char *nickname, *username;
354 char *realname = NULL;
356 SILC_LOG_DEBUG(("Start"));
358 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
359 SILC_GET16_MSB(status, tmp);
360 if (status != SILC_STATUS_OK &&
361 status != SILC_STATUS_LIST_START &&
362 status != SILC_STATUS_LIST_ITEM &&
363 status != SILC_STATUS_LIST_END) {
368 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
374 client_id = silc_id_payload_parse_id(id_data, len);
380 /* Get the client entry, if exists */
381 if (silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
382 SILC_ID_CLIENT, &id_cache))
383 client_entry = (SilcClientEntry)id_cache->context;
384 silc_free(client_id);
386 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
387 username = silc_argument_get_arg_type(cmd->args, 4, &len);
388 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
389 if (!nickname || !username) {
393 /* Notify application. We don't save any history information to any
394 cache. Just pass the data to the application for displaying on
396 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
398 /* Pending callbacks are not executed if this was an list entry */
399 if (status != SILC_STATUS_OK &&
400 status != SILC_STATUS_LIST_END) {
401 silc_client_command_reply_free(cmd);
405 /* Execute any pending command callbacks */
406 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
409 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
410 silc_client_command_reply_free(cmd);
414 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
415 SilcCommandStatus status)
417 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
418 SilcClientID *client_id;
419 SilcIDCacheEntry id_cache = NULL;
420 SilcClientEntry client_entry = NULL;
422 unsigned char *id_data;
423 char *nickname = NULL, *username = NULL;
425 argc = silc_argument_get_arg_num(cmd->args);
427 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
433 client_id = silc_id_payload_parse_id(id_data, len);
439 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
440 username = silc_argument_get_arg_type(cmd->args, 4, &len);
442 /* Check if we have this client cached already. */
443 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
444 SILC_ID_CLIENT, &id_cache)) {
445 SILC_LOG_DEBUG(("Adding new client entry"));
447 client_entry = silc_calloc(1, sizeof(*client_entry));
448 client_entry->id = client_id;
449 silc_parse_nickname(nickname, &client_entry->nickname,
450 &client_entry->server, &client_entry->num);
452 client_entry->username = strdup(username);
454 /* Add client to cache */
455 silc_idcache_add(conn->client_cache, client_entry->nickname,
456 SILC_ID_CLIENT, client_id, (void *)client_entry,
459 client_entry = (SilcClientEntry)id_cache->context;
460 if (client_entry->nickname)
461 silc_free(client_entry->nickname);
462 if (client_entry->server)
463 silc_free(client_entry->server);
464 if (username && client_entry->username)
465 silc_free(client_entry->username);
467 SILC_LOG_DEBUG(("Updating client entry"));
469 silc_parse_nickname(nickname, &client_entry->nickname,
470 &client_entry->server, &client_entry->num);
473 client_entry->username = strdup(username);
475 id_cache->data = client_entry->nickname;
476 silc_idcache_sort_by_data(conn->client_cache);
478 silc_free(client_id);
481 /* Notify application */
482 COMMAND_REPLY((ARGS, client_entry, nickname, username));
485 /* Received reply for IDENTIFY command. This maybe called several times
486 for one IDENTIFY command as server may reply with list of results.
487 This is totally silent and does not print anything on screen. */
489 SILC_CLIENT_CMD_REPLY_FUNC(identify)
491 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
492 SilcCommandStatus status;
495 SILC_LOG_DEBUG(("Start"));
497 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
498 SILC_GET16_MSB(status, tmp);
499 if (status != SILC_STATUS_OK &&
500 status != SILC_STATUS_LIST_START &&
501 status != SILC_STATUS_LIST_ITEM &&
502 status != SILC_STATUS_LIST_END) {
507 /* Save one IDENTIFY entry */
508 if (status == SILC_STATUS_OK)
509 silc_client_command_reply_identify_save(cmd, status);
512 if (status == SILC_STATUS_LIST_START ||
513 status == SILC_STATUS_LIST_ITEM ||
514 status == SILC_STATUS_LIST_END)
515 silc_client_command_reply_identify_save(cmd, status);
517 /* Pending callbacks are not executed if this was an list entry */
518 if (status != SILC_STATUS_OK &&
519 status != SILC_STATUS_LIST_END) {
520 silc_client_command_reply_free(cmd);
524 /* Execute any pending command callbacks */
525 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
528 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
529 silc_client_command_reply_free(cmd);
532 /* Received reply for command NICK. If everything went without errors
533 we just received our new Client ID. */
535 SILC_CLIENT_CMD_REPLY_FUNC(nick)
537 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
538 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
539 SilcCommandStatus status;
542 unsigned int argc, len;
544 SILC_LOG_DEBUG(("Start"));
546 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
547 if (status != SILC_STATUS_OK) {
548 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
549 silc_client_command_status_message(status));
554 argc = silc_argument_get_arg_num(cmd->args);
555 if (argc < 2 || argc > 2) {
556 cmd->client->ops->say(cmd->client, conn,
557 "Cannot set nickname: bad reply to command");
562 /* Take received Client ID */
563 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
564 idp = silc_id_payload_parse_data(tmp, len);
569 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
571 /* Notify application */
572 COMMAND_REPLY((ARGS, conn->local_entry));
574 /* Execute any pending command callbacks */
575 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
578 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
579 silc_client_command_reply_free(cmd);
582 SILC_CLIENT_CMD_REPLY_FUNC(list)
586 /* Received reply to topic command. */
588 SILC_CLIENT_CMD_REPLY_FUNC(topic)
590 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
591 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
592 SilcCommandStatus status;
593 SilcChannelEntry channel;
594 SilcChannelID *channel_id = NULL;
595 SilcIDCacheEntry id_cache = NULL;
598 unsigned int argc, len;
600 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
601 if (status != SILC_STATUS_OK) {
602 cmd->client->ops->say(cmd->client, conn,
603 "%s", silc_client_command_status_message(status));
605 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
606 silc_client_command_reply_free(cmd);
610 argc = silc_argument_get_arg_num(cmd->args);
611 if (argc < 1 || argc > 3) {
616 /* Take Channel ID */
617 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
622 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
626 channel_id = silc_id_payload_parse_id(tmp, len);
630 /* Get the channel name */
631 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
632 SILC_ID_CHANNEL, &id_cache)) {
633 silc_free(channel_id);
638 channel = (SilcChannelEntry)id_cache->context;
640 cmd->client->ops->say(cmd->client, conn,
641 "Topic on channel %s: %s", channel->channel_name,
644 /* Notify application */
645 COMMAND_REPLY((ARGS, channel, topic));
647 /* Execute any pending command callbacks */
648 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
651 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
652 silc_client_command_reply_free(cmd);
655 /* Received reply to invite command. */
657 SILC_CLIENT_CMD_REPLY_FUNC(invite)
659 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
660 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
661 SilcCommandStatus status;
664 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
665 SILC_GET16_MSB(status, tmp);
666 if (status != SILC_STATUS_OK) {
667 cmd->client->ops->say(cmd->client, conn,
668 "%s", silc_client_command_status_message(status));
670 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
671 silc_client_command_reply_free(cmd);
675 /* Notify application */
676 COMMAND_REPLY((ARGS));
678 /* Execute any pending command callbacks */
679 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
681 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
682 silc_client_command_reply_free(cmd);
685 /* Received reply to the KILL command. */
687 SILC_CLIENT_CMD_REPLY_FUNC(kill)
689 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
690 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
691 SilcCommandStatus status;
694 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
695 SILC_GET16_MSB(status, tmp);
696 if (status != SILC_STATUS_OK) {
697 cmd->client->ops->say(cmd->client, conn,
698 "%s", silc_client_command_status_message(status));
703 /* Notify application */
704 COMMAND_REPLY((ARGS));
706 /* Execute any pending command callbacks */
707 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
710 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
711 silc_client_command_reply_free(cmd);
714 /* Received reply to INFO command. We receive the server ID and some
715 information about the server user requested. */
717 SILC_CLIENT_CMD_REPLY_FUNC(info)
719 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
720 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
721 SilcClient client = cmd->client;
722 SilcCommandStatus status;
725 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
726 SILC_GET16_MSB(status, tmp);
727 if (status != SILC_STATUS_OK) {
728 cmd->client->ops->say(cmd->client, conn,
729 "%s", silc_client_command_status_message(status));
731 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
732 silc_client_command_reply_free(cmd);
737 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
741 /* XXX save server id */
743 /* Get server info */
744 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
748 client->ops->say(cmd->client, conn, "Info: %s", tmp);
750 /* Notify application */
751 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
753 /* Execute any pending command callbacks */
754 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
757 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
758 silc_client_command_reply_free(cmd);
761 /* Received reply to PING command. The reply time is shown to user. */
763 SILC_CLIENT_CMD_REPLY_FUNC(ping)
765 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
766 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
767 SilcCommandStatus status;
770 time_t diff, curtime;
772 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
773 if (status != SILC_STATUS_OK) {
774 cmd->client->ops->say(cmd->client, conn,
775 "%s", silc_client_command_status_message(status));
780 curtime = time(NULL);
781 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
782 cmd->packet->src_id_type);
788 for (i = 0; i < conn->ping_count; i++) {
789 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
790 diff = curtime - conn->ping[i].start_time;
791 cmd->client->ops->say(cmd->client, conn,
792 "Ping reply from %s: %d second%s",
793 conn->ping[i].dest_name, diff,
794 diff == 1 ? "" : "s");
796 conn->ping[i].start_time = 0;
797 silc_free(conn->ping[i].dest_id);
798 conn->ping[i].dest_id = NULL;
799 silc_free(conn->ping[i].dest_name);
800 conn->ping[i].dest_name = NULL;
807 /* Notify application */
808 COMMAND_REPLY((ARGS));
810 /* Execute any pending command callbacks */
811 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
814 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
815 silc_client_command_reply_free(cmd);
818 /* Received reply for JOIN command. */
820 SILC_CLIENT_CMD_REPLY_FUNC(join)
822 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
823 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
824 SilcCommandStatus status;
825 SilcIDPayload idp = NULL;
826 SilcChannelEntry channel;
827 SilcIDCacheEntry id_cache = NULL;
829 unsigned int argc, mode, len, list_count;
830 char *topic, *tmp, *channel_name = NULL, *hmac;
831 SilcBuffer keyp, client_id_list, client_mode_list;
834 SILC_LOG_DEBUG(("Start"));
836 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
837 if (status != SILC_STATUS_OK) {
838 cmd->client->ops->say(cmd->client, conn,
839 "%s", silc_client_command_status_message(status));
844 argc = silc_argument_get_arg_num(cmd->args);
845 if (argc < 7 || argc > 14) {
846 cmd->client->ops->say(cmd->client, conn,
847 "Cannot join channel: Bad reply packet");
852 /* Get channel name */
853 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
855 cmd->client->ops->say(cmd->client, conn,
856 "Cannot join channel: Bad reply packet");
860 channel_name = strdup(tmp);
863 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
865 cmd->client->ops->say(cmd->client, conn,
866 "Cannot join channel: Bad reply packet");
868 silc_free(channel_name);
871 idp = silc_id_payload_parse_data(tmp, len);
874 silc_free(channel_name);
878 /* Get channel mode */
879 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
881 SILC_GET32_MSB(mode, tmp);
886 /* Get channel key */
887 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
889 silc_id_payload_free(idp);
890 silc_free(channel_name);
893 keyp = silc_buffer_alloc(len);
894 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
895 silc_buffer_put(keyp, tmp, len);
898 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
900 /* Save received Channel ID. This actually creates the channel */
901 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
903 silc_id_payload_free(idp);
906 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
908 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
909 cmd->client->ops->say(cmd->client, conn,
910 "Cannot join channel: Unsupported HMAC `%s'",
913 silc_free(channel_name);
918 /* Get the list count */
919 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
922 SILC_GET32_MSB(list_count, tmp);
924 /* Get Client ID list */
925 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
929 client_id_list = silc_buffer_alloc(len);
930 silc_buffer_pull_tail(client_id_list, len);
931 silc_buffer_put(client_id_list, tmp, len);
933 /* Get client mode list */
934 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
938 client_mode_list = silc_buffer_alloc(len);
939 silc_buffer_pull_tail(client_mode_list, len);
940 silc_buffer_put(client_mode_list, tmp, len);
942 /* Add clients we received in the reply to the channel */
943 for (i = 0; i < list_count; i++) {
944 unsigned short idp_len;
946 SilcClientID *client_id;
947 SilcClientEntry client_entry;
950 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
952 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
957 SILC_GET32_MSB(mode, client_mode_list->data);
959 /* Check if we have this client cached already. */
960 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
961 SILC_ID_CLIENT, &id_cache)) {
962 /* No, we don't have it, add entry for it. */
963 client_entry = silc_calloc(1, sizeof(*client_entry));
964 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
965 silc_idcache_add(conn->client_cache, NULL, SILC_ID_CLIENT,
966 client_entry->id, (void *)client_entry, FALSE, FALSE);
968 /* Yes, we have it already */
969 client_entry = (SilcClientEntry)id_cache->context;
972 /* Join the client to the channel */
973 chu = silc_calloc(1, sizeof(*chu));
974 chu->client = client_entry;
976 silc_list_add(channel->clients, chu);
977 silc_free(client_id);
979 silc_buffer_pull(client_id_list, idp_len);
980 silc_buffer_pull(client_mode_list, 4);
982 silc_buffer_push(client_id_list, client_id_list->data -
983 client_id_list->head);
984 silc_buffer_push(client_mode_list, client_mode_list->data -
985 client_mode_list->head);
987 /* Save channel key */
988 silc_client_save_channel_key(conn, keyp, channel);
990 /* Notify application */
991 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, keyp->head, NULL,
992 NULL, topic, hmac, list_count, client_id_list,
995 /* Execute any pending command callbacks */
996 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
998 silc_buffer_free(keyp);
999 silc_buffer_free(client_id_list);
1000 silc_buffer_free(client_mode_list);
1003 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1004 silc_client_command_reply_free(cmd);
1007 /* Received reply for MOTD command */
1009 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1011 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1012 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1013 SilcCommandStatus status;
1014 unsigned int argc, i;
1016 char *motd = NULL, *cp, line[256];
1018 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1019 SILC_GET16_MSB(status, tmp);
1020 if (status != SILC_STATUS_OK) {
1021 cmd->client->ops->say(cmd->client, conn,
1022 "%s", silc_client_command_status_message(status));
1023 COMMAND_REPLY_ERROR;
1027 argc = silc_argument_get_arg_num(cmd->args);
1029 COMMAND_REPLY_ERROR;
1034 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
1036 COMMAND_REPLY_ERROR;
1043 if (cp[i++] == '\n') {
1044 memset(line, 0, sizeof(line));
1045 strncat(line, cp, i - 1);
1051 cmd->client->ops->say(cmd->client, conn, "%s", line);
1060 /* Notify application */
1061 COMMAND_REPLY((ARGS, motd));
1063 /* Execute any pending command callbacks */
1064 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1067 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1068 silc_client_command_reply_free(cmd);
1071 /* Received reply tot he UMODE command. Save the current user mode */
1073 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1075 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1076 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1077 SilcCommandStatus status;
1081 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1082 SILC_GET16_MSB(status, tmp);
1083 if (status != SILC_STATUS_OK) {
1084 cmd->client->ops->say(cmd->client, conn,
1085 "%s", silc_client_command_status_message(status));
1086 COMMAND_REPLY_ERROR;
1090 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1092 COMMAND_REPLY_ERROR;
1096 SILC_GET32_MSB(mode, tmp);
1097 conn->local_entry->mode = mode;
1099 /* Notify application */
1100 COMMAND_REPLY((ARGS, mode));
1102 /* Execute any pending command callbacks */
1103 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1106 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1107 silc_client_command_reply_free(cmd);
1110 /* Received reply for CMODE command. */
1112 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1114 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1115 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1116 SilcCommandStatus status;
1119 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1120 if (status != SILC_STATUS_OK) {
1121 cmd->client->ops->say(cmd->client, conn,
1122 "%s", silc_client_command_status_message(status));
1123 COMMAND_REPLY_ERROR;
1127 /* Get channel mode */
1128 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1130 COMMAND_REPLY_ERROR;
1134 /* Notify application */
1135 COMMAND_REPLY((ARGS, tmp));
1137 /* Execute any pending command callbacks */
1138 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1141 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1142 silc_client_command_reply_free(cmd);
1145 /* Received reply for CUMODE command */
1147 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1149 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1150 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1151 SilcCommandStatus status;
1152 SilcIDCacheEntry id_cache = NULL;
1153 SilcClientID *client_id;
1154 unsigned char *tmp, *id;
1157 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1158 if (status != SILC_STATUS_OK) {
1159 cmd->client->ops->say(cmd->client, conn,
1160 "%s", silc_client_command_status_message(status));
1161 COMMAND_REPLY_ERROR;
1165 /* Get channel mode */
1166 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1168 COMMAND_REPLY_ERROR;
1173 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1175 COMMAND_REPLY_ERROR;
1178 client_id = silc_id_payload_parse_id(id, len);
1180 COMMAND_REPLY_ERROR;
1184 /* Get client entry */
1185 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1186 SILC_ID_CLIENT, &id_cache)) {
1187 COMMAND_REPLY_ERROR;
1191 /* Notify application */
1192 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1193 silc_free(client_id);
1195 /* Execute any pending command callbacks */
1196 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1199 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1200 silc_client_command_reply_free(cmd);
1203 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1205 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1206 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1207 SilcCommandStatus status;
1210 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1211 SILC_GET16_MSB(status, tmp);
1212 if (status != SILC_STATUS_OK) {
1213 cmd->client->ops->say(cmd->client, conn,
1214 "%s", silc_client_command_status_message(status));
1215 COMMAND_REPLY_ERROR;
1219 /* Notify application */
1220 COMMAND_REPLY((ARGS));
1222 /* Execute any pending command callbacks */
1223 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1226 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1227 silc_client_command_reply_free(cmd);
1230 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1232 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1233 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1234 SilcCommandStatus status;
1237 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1238 SILC_GET16_MSB(status, tmp);
1239 if (status != SILC_STATUS_OK) {
1240 cmd->client->ops->say(cmd->client, conn,
1241 "%s", silc_client_command_status_message(status));
1242 COMMAND_REPLY_ERROR;
1246 /* Notify application */
1247 COMMAND_REPLY((ARGS));
1249 /* Execute any pending command callbacks */
1250 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1253 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1254 silc_client_command_reply_free(cmd);
1257 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1259 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1260 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1261 SilcCommandStatus status;
1264 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1265 SILC_GET16_MSB(status, tmp);
1266 if (status != SILC_STATUS_OK) {
1267 cmd->client->ops->say(cmd->client, conn,
1268 "%s", silc_client_command_status_message(status));
1269 COMMAND_REPLY_ERROR;
1273 /* Notify application */
1274 COMMAND_REPLY((ARGS));
1276 /* Execute any pending command callbacks */
1277 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1280 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1281 silc_client_command_reply_free(cmd);
1284 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1286 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1287 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1288 SilcCommandStatus status;
1291 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1292 SILC_GET16_MSB(status, tmp);
1293 if (status != SILC_STATUS_OK) {
1294 cmd->client->ops->say(cmd->client, conn,
1295 "%s", silc_client_command_status_message(status));
1296 COMMAND_REPLY_ERROR;
1300 /* Notify application */
1301 COMMAND_REPLY((ARGS));
1303 /* Execute any pending command callbacks */
1304 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1307 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1308 silc_client_command_reply_free(cmd);
1311 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1313 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1314 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1315 SilcCommandStatus status;
1318 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1319 SILC_GET16_MSB(status, tmp);
1320 if (status != SILC_STATUS_OK) {
1321 cmd->client->ops->say(cmd->client, conn,
1322 "%s", silc_client_command_status_message(status));
1323 COMMAND_REPLY_ERROR;
1327 /* Notify application */
1328 COMMAND_REPLY((ARGS));
1330 /* Execute any pending command callbacks */
1331 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1334 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1335 silc_client_command_reply_free(cmd);
1338 SILC_CLIENT_CMD_REPLY_FUNC(close)
1340 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1341 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1342 SilcCommandStatus status;
1345 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1346 SILC_GET16_MSB(status, tmp);
1347 if (status != SILC_STATUS_OK) {
1348 cmd->client->ops->say(cmd->client, conn,
1349 "%s", silc_client_command_status_message(status));
1350 COMMAND_REPLY_ERROR;
1354 /* Notify application */
1355 COMMAND_REPLY((ARGS));
1357 /* Execute any pending command callbacks */
1358 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1361 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1362 silc_client_command_reply_free(cmd);
1365 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1367 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1368 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1369 SilcCommandStatus status;
1372 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1373 SILC_GET16_MSB(status, tmp);
1374 if (status != SILC_STATUS_OK) {
1375 cmd->client->ops->say(cmd->client, conn,
1376 "%s", silc_client_command_status_message(status));
1377 COMMAND_REPLY_ERROR;
1381 /* Notify application */
1382 COMMAND_REPLY((ARGS));
1384 /* Execute any pending command callbacks */
1385 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1388 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1389 silc_client_command_reply_free(cmd);
1392 /* Reply to LEAVE command. */
1394 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1396 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1397 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1398 SilcCommandStatus status;
1401 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1402 SILC_GET16_MSB(status, tmp);
1403 if (status != SILC_STATUS_OK) {
1404 cmd->client->ops->say(cmd->client, conn,
1405 "%s", silc_client_command_status_message(status));
1406 COMMAND_REPLY_ERROR;
1410 /* Notify application */
1411 COMMAND_REPLY((ARGS));
1413 /* Execute any pending command callbacks */
1414 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1417 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1418 silc_client_command_reply_free(cmd);
1421 /* Reply to USERS command. Received list of client ID's and theirs modes
1422 on the channel we requested. */
1424 SILC_CLIENT_CMD_REPLY_FUNC(users)
1426 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1427 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1428 SilcCommandStatus status;
1429 SilcIDCacheEntry id_cache = NULL;
1430 SilcChannelEntry channel;
1431 SilcChannelUser chu;
1432 SilcChannelID *channel_id = NULL;
1433 SilcBuffer client_id_list;
1434 SilcBuffer client_mode_list;
1436 unsigned int tmp_len, list_count;
1438 unsigned char **res_argv = NULL;
1439 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1441 SILC_LOG_DEBUG(("Start"));
1443 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1444 SILC_GET16_MSB(status, tmp);
1445 if (status != SILC_STATUS_OK) {
1446 cmd->client->ops->say(cmd->client, conn,
1447 "%s", silc_client_command_status_message(status));
1448 COMMAND_REPLY_ERROR;
1452 /* Get channel ID */
1453 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1456 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1460 /* Get the list count */
1461 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1464 SILC_GET32_MSB(list_count, tmp);
1466 /* Get Client ID list */
1467 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1471 client_id_list = silc_buffer_alloc(tmp_len);
1472 silc_buffer_pull_tail(client_id_list, tmp_len);
1473 silc_buffer_put(client_id_list, tmp, tmp_len);
1475 /* Get client mode list */
1476 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1480 client_mode_list = silc_buffer_alloc(tmp_len);
1481 silc_buffer_pull_tail(client_mode_list, tmp_len);
1482 silc_buffer_put(client_mode_list, tmp, tmp_len);
1484 /* Get channel entry */
1485 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1486 SILC_ID_CHANNEL, &id_cache)) {
1487 COMMAND_REPLY_ERROR;
1490 channel = (SilcChannelEntry)id_cache->context;
1492 /* Remove old client list from channel. */
1493 silc_list_start(channel->clients);
1494 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1495 silc_list_del(channel->clients, chu);
1499 /* Cache the received Client ID's and modes. This cache expires
1500 whenever server sends notify message to channel. It means two things;
1501 some user has joined or leaved the channel. XXX! */
1502 for (i = 0; i < list_count; i++) {
1503 unsigned short idp_len;
1505 SilcClientID *client_id;
1506 SilcClientEntry client;
1509 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1511 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1516 SILC_GET32_MSB(mode, client_mode_list->data);
1518 /* Check if we have this client cached already. */
1519 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1520 SILC_ID_CLIENT, &id_cache)) {
1521 /* No we don't have it, query it from the server. Assemble argument
1522 table that will be sent fr the IDENTIFY command later. */
1523 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1525 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1527 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1529 res_argv[res_argc] = client_id_list->data;
1530 res_argv_lens[res_argc] = idp_len;
1531 res_argv_types[res_argc] = res_argc + 3;
1534 /* Found the client, join it to the channel */
1535 client = (SilcClientEntry)id_cache->context;
1536 chu = silc_calloc(1, sizeof(*chu));
1537 chu->client = client;
1539 silc_list_add(channel->clients, chu);
1541 silc_free(client_id);
1545 silc_buffer_pull(client_id_list, idp_len);
1546 silc_buffer_pull(client_mode_list, 4);
1549 /* Query the client information from server if the list included clients
1550 that we don't know about. */
1554 /* Send the IDENTIFY command to server */
1555 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1556 res_argc, res_argv, res_argv_lens,
1557 res_argv_types, ++conn->cmd_ident);
1558 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1559 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1562 /* Register pending command callback. After we've received the IDENTIFY
1563 command reply we will reprocess this command reply by re-calling this
1564 USERS command reply callback. */
1565 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1566 NULL, silc_client_command_reply_users, cmd);
1568 silc_buffer_free(res_cmd);
1570 silc_free(channel_id);
1572 silc_free(res_argv);
1573 silc_free(res_argv_lens);
1574 silc_free(res_argv_types);
1578 /* Notify application */
1579 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1581 /* Execute any pending command callbacks */
1582 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1584 silc_buffer_free(client_id_list);
1585 silc_buffer_free(client_mode_list);
1589 silc_free(channel_id);
1590 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1591 silc_client_command_reply_free(cmd);