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;
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(idle, tmp);
239 /* Check if we have this client cached already. */
240 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
241 SILC_ID_CLIENT, &id_cache)) {
242 SILC_LOG_DEBUG(("Adding new client entry"));
244 client_entry = silc_calloc(1, sizeof(*client_entry));
245 client_entry->id = client_id;
246 silc_parse_nickname(nickname, &client_entry->nickname,
247 &client_entry->server, &client_entry->num);
248 client_entry->username = strdup(username);
250 client_entry->realname = strdup(realname);
252 /* Add client to cache */
253 silc_idcache_add(conn->client_cache, client_entry->nickname,
254 SILC_ID_CLIENT, client_id, (void *)client_entry,
257 client_entry = (SilcClientEntry)id_cache->context;
258 if (client_entry->nickname)
259 silc_free(client_entry->nickname);
260 if (client_entry->server)
261 silc_free(client_entry->server);
262 if (client_entry->username)
263 silc_free(client_entry->username);
264 if (client_entry->realname)
265 silc_free(client_entry->realname);
267 SILC_LOG_DEBUG(("Updating client entry"));
269 silc_parse_nickname(nickname, &client_entry->nickname,
270 &client_entry->server, &client_entry->num);
271 client_entry->username = strdup(username);
273 client_entry->realname = strdup(realname);
275 id_cache->data = client_entry->nickname;
276 silc_idcache_sort_by_data(conn->client_cache);
278 silc_free(client_id);
281 /* Notify application */
283 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
287 /* Received reply for WHOIS command. This maybe called several times
288 for one WHOIS command as server may reply with list of results. */
290 SILC_CLIENT_CMD_REPLY_FUNC(whois)
292 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
293 SilcCommandStatus status;
296 SILC_LOG_DEBUG(("Start"));
298 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
299 SILC_GET16_MSB(status, tmp);
300 if (status != SILC_STATUS_OK &&
301 status != SILC_STATUS_LIST_START &&
302 status != SILC_STATUS_LIST_ITEM &&
303 status != SILC_STATUS_LIST_END) {
308 /* Display one whois reply */
309 if (status == SILC_STATUS_OK)
310 silc_client_command_reply_whois_save(cmd, status);
313 if (status == SILC_STATUS_LIST_START ||
314 status == SILC_STATUS_LIST_ITEM ||
315 status == SILC_STATUS_LIST_END)
316 silc_client_command_reply_whois_save(cmd, status);
318 /* Pending callbacks are not executed if this was an list entry */
319 if (status != SILC_STATUS_OK &&
320 status != SILC_STATUS_LIST_END) {
321 silc_client_command_reply_free(cmd);
325 /* Execute any pending command callbacks */
326 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
329 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
330 silc_client_command_reply_free(cmd);
333 /* Received reply for WHOWAS command. */
335 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
337 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
338 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
339 SilcCommandStatus status;
340 SilcClientID *client_id;
341 SilcIDCacheEntry id_cache = NULL;
342 SilcClientEntry client_entry = NULL;
344 unsigned char *id_data, *tmp;
345 char *nickname, *username;
346 char *realname = NULL;
348 SILC_LOG_DEBUG(("Start"));
350 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
351 SILC_GET16_MSB(status, tmp);
352 if (status != SILC_STATUS_OK &&
353 status != SILC_STATUS_LIST_START &&
354 status != SILC_STATUS_LIST_ITEM &&
355 status != SILC_STATUS_LIST_END) {
360 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
366 client_id = silc_id_payload_parse_id(id_data, len);
372 /* Get the client entry, if exists */
373 if (silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
374 SILC_ID_CLIENT, &id_cache))
375 client_entry = (SilcClientEntry)id_cache->context;
376 silc_free(client_id);
378 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
379 username = silc_argument_get_arg_type(cmd->args, 4, &len);
380 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
381 if (!nickname || !username) {
385 /* Notify application. We don't save any history information to any
386 cache. Just pass the data to the application for displaying on
388 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
390 /* Pending callbacks are not executed if this was an list entry */
391 if (status != SILC_STATUS_OK &&
392 status != SILC_STATUS_LIST_END) {
393 silc_client_command_reply_free(cmd);
397 /* Execute any pending command callbacks */
398 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
401 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
402 silc_client_command_reply_free(cmd);
406 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
407 SilcCommandStatus status)
409 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
410 SilcClientID *client_id;
411 SilcIDCacheEntry id_cache = NULL;
412 SilcClientEntry client_entry = NULL;
414 unsigned char *id_data;
415 char *nickname = NULL, *username = NULL;
417 argc = silc_argument_get_arg_num(cmd->args);
419 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
425 client_id = silc_id_payload_parse_id(id_data, len);
431 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
432 username = silc_argument_get_arg_type(cmd->args, 4, &len);
434 /* Check if we have this client cached already. */
435 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
436 SILC_ID_CLIENT, &id_cache)) {
437 SILC_LOG_DEBUG(("Adding new client entry"));
439 client_entry = silc_calloc(1, sizeof(*client_entry));
440 client_entry->id = client_id;
441 silc_parse_nickname(nickname, &client_entry->nickname,
442 &client_entry->server, &client_entry->num);
444 client_entry->username = strdup(username);
446 /* Add client to cache */
447 silc_idcache_add(conn->client_cache, client_entry->nickname,
448 SILC_ID_CLIENT, client_id, (void *)client_entry,
451 client_entry = (SilcClientEntry)id_cache->context;
452 if (client_entry->nickname)
453 silc_free(client_entry->nickname);
454 if (client_entry->server)
455 silc_free(client_entry->server);
456 if (username && client_entry->username)
457 silc_free(client_entry->username);
459 SILC_LOG_DEBUG(("Updating client entry"));
461 silc_parse_nickname(nickname, &client_entry->nickname,
462 &client_entry->server, &client_entry->num);
465 client_entry->username = strdup(username);
467 id_cache->data = client_entry->nickname;
468 silc_idcache_sort_by_data(conn->client_cache);
470 silc_free(client_id);
473 /* Notify application */
474 COMMAND_REPLY((ARGS, client_entry, nickname, username));
477 /* Received reply for IDENTIFY command. This maybe called several times
478 for one IDENTIFY command as server may reply with list of results.
479 This is totally silent and does not print anything on screen. */
481 SILC_CLIENT_CMD_REPLY_FUNC(identify)
483 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
484 SilcCommandStatus status;
487 SILC_LOG_DEBUG(("Start"));
489 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
490 SILC_GET16_MSB(status, tmp);
491 if (status != SILC_STATUS_OK &&
492 status != SILC_STATUS_LIST_START &&
493 status != SILC_STATUS_LIST_ITEM &&
494 status != SILC_STATUS_LIST_END) {
499 /* Save one IDENTIFY entry */
500 if (status == SILC_STATUS_OK)
501 silc_client_command_reply_identify_save(cmd, status);
504 if (status == SILC_STATUS_LIST_START ||
505 status == SILC_STATUS_LIST_ITEM ||
506 status == SILC_STATUS_LIST_END)
507 silc_client_command_reply_identify_save(cmd, status);
509 /* Pending callbacks are not executed if this was an list entry */
510 if (status != SILC_STATUS_OK &&
511 status != SILC_STATUS_LIST_END) {
512 silc_client_command_reply_free(cmd);
516 /* Execute any pending command callbacks */
517 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
520 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
521 silc_client_command_reply_free(cmd);
524 /* Received reply for command NICK. If everything went without errors
525 we just received our new Client ID. */
527 SILC_CLIENT_CMD_REPLY_FUNC(nick)
529 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
530 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
531 SilcCommandStatus status;
534 unsigned int argc, len;
536 SILC_LOG_DEBUG(("Start"));
538 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
539 if (status != SILC_STATUS_OK) {
540 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
541 silc_client_command_status_message(status));
546 argc = silc_argument_get_arg_num(cmd->args);
547 if (argc < 2 || argc > 2) {
548 cmd->client->ops->say(cmd->client, conn,
549 "Cannot set nickname: bad reply to command");
554 /* Take received Client ID */
555 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
556 idp = silc_id_payload_parse_data(tmp, len);
561 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
563 /* Notify application */
564 COMMAND_REPLY((ARGS, conn->local_entry));
566 /* Execute any pending command callbacks */
567 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
570 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
571 silc_client_command_reply_free(cmd);
574 SILC_CLIENT_CMD_REPLY_FUNC(list)
578 /* Received reply to topic command. */
580 SILC_CLIENT_CMD_REPLY_FUNC(topic)
582 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
583 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
584 SilcCommandStatus status;
585 SilcChannelEntry channel;
586 SilcChannelID *channel_id = NULL;
587 SilcIDCacheEntry id_cache = NULL;
590 unsigned int argc, len;
592 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
593 if (status != SILC_STATUS_OK) {
594 cmd->client->ops->say(cmd->client, conn,
595 "%s", silc_client_command_status_message(status));
597 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
598 silc_client_command_reply_free(cmd);
602 argc = silc_argument_get_arg_num(cmd->args);
603 if (argc < 1 || argc > 3) {
608 /* Take Channel ID */
609 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
614 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
618 channel_id = silc_id_payload_parse_id(tmp, len);
622 /* Get the channel name */
623 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
624 SILC_ID_CHANNEL, &id_cache)) {
625 silc_free(channel_id);
630 channel = (SilcChannelEntry)id_cache->context;
632 cmd->client->ops->say(cmd->client, conn,
633 "Topic on channel %s: %s", channel->channel_name,
636 /* Notify application */
637 COMMAND_REPLY((ARGS, channel, topic));
639 /* Execute any pending command callbacks */
640 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
643 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
644 silc_client_command_reply_free(cmd);
647 /* Received reply to invite command. */
649 SILC_CLIENT_CMD_REPLY_FUNC(invite)
651 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
652 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
653 SilcCommandStatus status;
656 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
657 SILC_GET16_MSB(status, tmp);
658 if (status != SILC_STATUS_OK) {
659 cmd->client->ops->say(cmd->client, conn,
660 "%s", silc_client_command_status_message(status));
662 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
663 silc_client_command_reply_free(cmd);
667 /* Notify application */
668 COMMAND_REPLY((ARGS));
670 /* Execute any pending command callbacks */
671 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
673 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
674 silc_client_command_reply_free(cmd);
677 /* Received reply to the KILL command. */
679 SILC_CLIENT_CMD_REPLY_FUNC(kill)
681 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
682 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
683 SilcCommandStatus status;
686 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
687 SILC_GET16_MSB(status, tmp);
688 if (status != SILC_STATUS_OK) {
689 cmd->client->ops->say(cmd->client, conn,
690 "%s", silc_client_command_status_message(status));
695 /* Notify application */
696 COMMAND_REPLY((ARGS));
698 /* Execute any pending command callbacks */
699 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
702 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
703 silc_client_command_reply_free(cmd);
706 /* Received reply to INFO command. We receive the server ID and some
707 information about the server user requested. */
709 SILC_CLIENT_CMD_REPLY_FUNC(info)
711 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
712 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
713 SilcClient client = cmd->client;
714 SilcCommandStatus status;
717 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
718 SILC_GET16_MSB(status, tmp);
719 if (status != SILC_STATUS_OK) {
720 cmd->client->ops->say(cmd->client, conn,
721 "%s", silc_client_command_status_message(status));
723 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
724 silc_client_command_reply_free(cmd);
729 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
733 /* XXX save server id */
735 /* Get server info */
736 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
740 client->ops->say(cmd->client, conn, "Info: %s", tmp);
742 /* Notify application */
743 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
745 /* Execute any pending command callbacks */
746 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
749 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
750 silc_client_command_reply_free(cmd);
753 /* Received reply to PING command. The reply time is shown to user. */
755 SILC_CLIENT_CMD_REPLY_FUNC(ping)
757 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
758 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
759 SilcCommandStatus status;
762 time_t diff, curtime;
764 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
765 if (status != SILC_STATUS_OK) {
766 cmd->client->ops->say(cmd->client, conn,
767 "%s", silc_client_command_status_message(status));
772 curtime = time(NULL);
773 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
774 cmd->packet->src_id_type);
780 for (i = 0; i < conn->ping_count; i++) {
781 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
782 diff = curtime - conn->ping[i].start_time;
783 cmd->client->ops->say(cmd->client, conn,
784 "Ping reply from %s: %d second%s",
785 conn->ping[i].dest_name, diff,
786 diff == 1 ? "" : "s");
788 conn->ping[i].start_time = 0;
789 silc_free(conn->ping[i].dest_id);
790 conn->ping[i].dest_id = NULL;
791 silc_free(conn->ping[i].dest_name);
792 conn->ping[i].dest_name = NULL;
799 /* Notify application */
800 COMMAND_REPLY((ARGS));
802 /* Execute any pending command callbacks */
803 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
806 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
807 silc_client_command_reply_free(cmd);
810 /* Received reply for JOIN command. */
812 SILC_CLIENT_CMD_REPLY_FUNC(join)
814 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
815 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
816 SilcCommandStatus status;
817 SilcIDPayload idp = NULL;
818 SilcChannelEntry channel;
819 SilcIDCacheEntry id_cache = NULL;
821 unsigned int argc, mode, len, list_count;
822 char *topic, *tmp, *channel_name = NULL, *hmac;
823 SilcBuffer keyp, client_id_list, client_mode_list;
826 SILC_LOG_DEBUG(("Start"));
828 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
829 if (status != SILC_STATUS_OK) {
830 cmd->client->ops->say(cmd->client, conn,
831 "%s", silc_client_command_status_message(status));
836 argc = silc_argument_get_arg_num(cmd->args);
837 if (argc < 7 || argc > 14) {
838 cmd->client->ops->say(cmd->client, conn,
839 "Cannot join channel: Bad reply packet");
844 /* Get channel name */
845 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
847 cmd->client->ops->say(cmd->client, conn,
848 "Cannot join channel: Bad reply packet");
852 channel_name = strdup(tmp);
855 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
857 cmd->client->ops->say(cmd->client, conn,
858 "Cannot join channel: Bad reply packet");
860 silc_free(channel_name);
863 idp = silc_id_payload_parse_data(tmp, len);
866 silc_free(channel_name);
870 /* Get channel mode */
871 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
873 SILC_GET32_MSB(mode, tmp);
877 /* Get channel key */
878 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
880 silc_id_payload_free(idp);
881 silc_free(channel_name);
884 keyp = silc_buffer_alloc(len);
885 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
886 silc_buffer_put(keyp, tmp, len);
889 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
891 /* Save received Channel ID. This actually creates the channel */
892 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
894 silc_id_payload_free(idp);
897 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
899 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
900 cmd->client->ops->say(cmd->client, conn,
901 "Cannot join channel: Unsupported HMAC `%s'",
904 silc_free(channel_name);
909 /* Get the list count */
910 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
913 SILC_GET32_MSB(list_count, tmp);
915 /* Get Client ID list */
916 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
920 client_id_list = silc_buffer_alloc(len);
921 silc_buffer_pull_tail(client_id_list, len);
922 silc_buffer_put(client_id_list, tmp, len);
924 /* Get client mode list */
925 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
929 client_mode_list = silc_buffer_alloc(len);
930 silc_buffer_pull_tail(client_mode_list, len);
931 silc_buffer_put(client_mode_list, tmp, len);
933 /* Add clients we received in the reply to the channel */
934 for (i = 0; i < list_count; i++) {
935 unsigned short idp_len;
937 SilcClientID *client_id;
938 SilcClientEntry client_entry;
941 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
943 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
948 SILC_GET32_MSB(mode, client_mode_list->data);
950 /* Check if we have this client cached already. */
951 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
952 SILC_ID_CLIENT, &id_cache)) {
953 /* No, we don't have it, add entry for it. */
954 client_entry = silc_calloc(1, sizeof(*client_entry));
955 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
956 silc_idcache_add(conn->client_cache, NULL, SILC_ID_CLIENT,
957 client_entry->id, (void *)client_entry, FALSE, FALSE);
959 /* Yes, we have it already */
960 client_entry = (SilcClientEntry)id_cache->context;
963 /* Join the client to the channel */
964 chu = silc_calloc(1, sizeof(*chu));
965 chu->client = client_entry;
967 silc_list_add(channel->clients, chu);
968 silc_free(client_id);
970 silc_buffer_pull(client_id_list, idp_len);
971 silc_buffer_pull(client_mode_list, 4);
973 silc_buffer_push(client_id_list, client_id_list->data -
974 client_id_list->head);
975 silc_buffer_push(client_mode_list, client_mode_list->data -
976 client_mode_list->head);
978 /* Save channel key */
979 silc_client_save_channel_key(conn, keyp, channel);
981 /* Notify application */
982 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, keyp->head, NULL,
983 NULL, topic, hmac, list_count, client_id_list,
986 /* Execute any pending command callbacks */
987 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
989 silc_buffer_free(keyp);
990 silc_buffer_free(client_id_list);
991 silc_buffer_free(client_mode_list);
994 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
995 silc_client_command_reply_free(cmd);
998 /* Received reply for MOTD command */
1000 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1002 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1003 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1004 SilcCommandStatus status;
1005 unsigned int argc, i;
1007 char *motd = NULL, *cp, line[256];
1009 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1010 SILC_GET16_MSB(status, tmp);
1011 if (status != SILC_STATUS_OK) {
1012 cmd->client->ops->say(cmd->client, conn,
1013 "%s", silc_client_command_status_message(status));
1014 COMMAND_REPLY_ERROR;
1018 argc = silc_argument_get_arg_num(cmd->args);
1020 COMMAND_REPLY_ERROR;
1025 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
1027 COMMAND_REPLY_ERROR;
1034 if (cp[i++] == '\n') {
1035 memset(line, 0, sizeof(line));
1036 strncat(line, cp, i - 1);
1042 cmd->client->ops->say(cmd->client, conn, "%s", line);
1051 /* Notify application */
1052 COMMAND_REPLY((ARGS, motd));
1054 /* Execute any pending command callbacks */
1055 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1058 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1059 silc_client_command_reply_free(cmd);
1062 /* Received reply tot he UMODE command. Save the current user mode */
1064 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1066 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1067 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1068 SilcCommandStatus status;
1072 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1073 SILC_GET16_MSB(status, tmp);
1074 if (status != SILC_STATUS_OK) {
1075 cmd->client->ops->say(cmd->client, conn,
1076 "%s", silc_client_command_status_message(status));
1077 COMMAND_REPLY_ERROR;
1081 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1083 COMMAND_REPLY_ERROR;
1087 SILC_GET32_MSB(mode, tmp);
1088 conn->local_entry->mode = mode;
1090 /* Notify application */
1091 COMMAND_REPLY((ARGS, mode));
1093 /* Execute any pending command callbacks */
1094 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1097 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1098 silc_client_command_reply_free(cmd);
1101 /* Received reply for CMODE command. */
1103 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1105 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1106 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1107 SilcCommandStatus status;
1110 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1111 if (status != SILC_STATUS_OK) {
1112 cmd->client->ops->say(cmd->client, conn,
1113 "%s", silc_client_command_status_message(status));
1114 COMMAND_REPLY_ERROR;
1118 /* Get channel mode */
1119 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1121 COMMAND_REPLY_ERROR;
1125 /* Notify application */
1126 COMMAND_REPLY((ARGS, tmp));
1128 /* Execute any pending command callbacks */
1129 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1132 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1133 silc_client_command_reply_free(cmd);
1136 /* Received reply for CUMODE command */
1138 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1140 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1141 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1142 SilcCommandStatus status;
1143 SilcIDCacheEntry id_cache = NULL;
1144 SilcClientID *client_id;
1145 unsigned char *tmp, *id;
1148 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1149 if (status != SILC_STATUS_OK) {
1150 cmd->client->ops->say(cmd->client, conn,
1151 "%s", silc_client_command_status_message(status));
1152 COMMAND_REPLY_ERROR;
1156 /* Get channel mode */
1157 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1159 COMMAND_REPLY_ERROR;
1164 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1166 COMMAND_REPLY_ERROR;
1169 client_id = silc_id_payload_parse_id(id, len);
1171 COMMAND_REPLY_ERROR;
1175 /* Get client entry */
1176 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1177 SILC_ID_CLIENT, &id_cache)) {
1178 COMMAND_REPLY_ERROR;
1182 /* Notify application */
1183 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1184 silc_free(client_id);
1186 /* Execute any pending command callbacks */
1187 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1190 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1191 silc_client_command_reply_free(cmd);
1194 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1196 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1197 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1198 SilcCommandStatus status;
1201 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1202 SILC_GET16_MSB(status, tmp);
1203 if (status != SILC_STATUS_OK) {
1204 cmd->client->ops->say(cmd->client, conn,
1205 "%s", silc_client_command_status_message(status));
1206 COMMAND_REPLY_ERROR;
1210 /* Notify application */
1211 COMMAND_REPLY((ARGS));
1213 /* Execute any pending command callbacks */
1214 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1217 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1218 silc_client_command_reply_free(cmd);
1221 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1223 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1224 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1225 SilcCommandStatus status;
1228 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1229 SILC_GET16_MSB(status, tmp);
1230 if (status != SILC_STATUS_OK) {
1231 cmd->client->ops->say(cmd->client, conn,
1232 "%s", silc_client_command_status_message(status));
1233 COMMAND_REPLY_ERROR;
1237 /* Notify application */
1238 COMMAND_REPLY((ARGS));
1240 /* Execute any pending command callbacks */
1241 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1244 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1245 silc_client_command_reply_free(cmd);
1248 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1250 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1251 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1252 SilcCommandStatus status;
1255 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1256 SILC_GET16_MSB(status, tmp);
1257 if (status != SILC_STATUS_OK) {
1258 cmd->client->ops->say(cmd->client, conn,
1259 "%s", silc_client_command_status_message(status));
1260 COMMAND_REPLY_ERROR;
1264 /* Notify application */
1265 COMMAND_REPLY((ARGS));
1267 /* Execute any pending command callbacks */
1268 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1271 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1272 silc_client_command_reply_free(cmd);
1275 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1277 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1278 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1279 SilcCommandStatus status;
1282 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1283 SILC_GET16_MSB(status, tmp);
1284 if (status != SILC_STATUS_OK) {
1285 cmd->client->ops->say(cmd->client, conn,
1286 "%s", silc_client_command_status_message(status));
1287 COMMAND_REPLY_ERROR;
1291 /* Notify application */
1292 COMMAND_REPLY((ARGS));
1294 /* Execute any pending command callbacks */
1295 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1298 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1299 silc_client_command_reply_free(cmd);
1302 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1304 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1305 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1306 SilcCommandStatus status;
1309 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1310 SILC_GET16_MSB(status, tmp);
1311 if (status != SILC_STATUS_OK) {
1312 cmd->client->ops->say(cmd->client, conn,
1313 "%s", silc_client_command_status_message(status));
1314 COMMAND_REPLY_ERROR;
1318 /* Notify application */
1319 COMMAND_REPLY((ARGS));
1321 /* Execute any pending command callbacks */
1322 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1325 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1326 silc_client_command_reply_free(cmd);
1329 SILC_CLIENT_CMD_REPLY_FUNC(close)
1331 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1332 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1333 SilcCommandStatus status;
1336 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1337 SILC_GET16_MSB(status, tmp);
1338 if (status != SILC_STATUS_OK) {
1339 cmd->client->ops->say(cmd->client, conn,
1340 "%s", silc_client_command_status_message(status));
1341 COMMAND_REPLY_ERROR;
1345 /* Notify application */
1346 COMMAND_REPLY((ARGS));
1348 /* Execute any pending command callbacks */
1349 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1352 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1353 silc_client_command_reply_free(cmd);
1356 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1358 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1359 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1360 SilcCommandStatus status;
1363 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1364 SILC_GET16_MSB(status, tmp);
1365 if (status != SILC_STATUS_OK) {
1366 cmd->client->ops->say(cmd->client, conn,
1367 "%s", silc_client_command_status_message(status));
1368 COMMAND_REPLY_ERROR;
1372 /* Notify application */
1373 COMMAND_REPLY((ARGS));
1375 /* Execute any pending command callbacks */
1376 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1379 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1380 silc_client_command_reply_free(cmd);
1383 /* Reply to LEAVE command. */
1385 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1387 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1388 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1389 SilcCommandStatus status;
1392 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1393 SILC_GET16_MSB(status, tmp);
1394 if (status != SILC_STATUS_OK) {
1395 cmd->client->ops->say(cmd->client, conn,
1396 "%s", silc_client_command_status_message(status));
1397 COMMAND_REPLY_ERROR;
1401 /* Notify application */
1402 COMMAND_REPLY((ARGS));
1404 /* Execute any pending command callbacks */
1405 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1408 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1409 silc_client_command_reply_free(cmd);
1412 /* Reply to USERS command. Received list of client ID's and theirs modes
1413 on the channel we requested. */
1415 SILC_CLIENT_CMD_REPLY_FUNC(users)
1417 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1418 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1419 SilcCommandStatus status;
1420 SilcIDCacheEntry id_cache = NULL;
1421 SilcChannelEntry channel;
1422 SilcChannelUser chu;
1423 SilcChannelID *channel_id = NULL;
1424 SilcBuffer client_id_list;
1425 SilcBuffer client_mode_list;
1427 unsigned int tmp_len, list_count;
1429 unsigned char **res_argv = NULL;
1430 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1432 SILC_LOG_DEBUG(("Start"));
1434 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1435 SILC_GET16_MSB(status, tmp);
1436 if (status != SILC_STATUS_OK) {
1437 cmd->client->ops->say(cmd->client, conn,
1438 "%s", silc_client_command_status_message(status));
1439 COMMAND_REPLY_ERROR;
1443 /* Get channel ID */
1444 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1447 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1451 /* Get the list count */
1452 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1455 SILC_GET32_MSB(list_count, tmp);
1457 /* Get Client ID list */
1458 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1462 client_id_list = silc_buffer_alloc(tmp_len);
1463 silc_buffer_pull_tail(client_id_list, tmp_len);
1464 silc_buffer_put(client_id_list, tmp, tmp_len);
1466 /* Get client mode list */
1467 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1471 client_mode_list = silc_buffer_alloc(tmp_len);
1472 silc_buffer_pull_tail(client_mode_list, tmp_len);
1473 silc_buffer_put(client_mode_list, tmp, tmp_len);
1475 /* Get channel entry */
1476 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1477 SILC_ID_CHANNEL, &id_cache)) {
1478 COMMAND_REPLY_ERROR;
1481 channel = (SilcChannelEntry)id_cache->context;
1483 /* Remove old client list from channel. */
1484 silc_list_start(channel->clients);
1485 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1486 silc_list_del(channel->clients, chu);
1490 /* Cache the received Client ID's and modes. This cache expires
1491 whenever server sends notify message to channel. It means two things;
1492 some user has joined or leaved the channel. XXX! */
1493 for (i = 0; i < list_count; i++) {
1494 unsigned short idp_len;
1496 SilcClientID *client_id;
1497 SilcClientEntry client;
1500 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1502 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1507 SILC_GET32_MSB(mode, client_mode_list->data);
1509 /* Check if we have this client cached already. */
1510 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1511 SILC_ID_CLIENT, &id_cache)) {
1512 /* No we don't have it, query it from the server. Assemble argument
1513 table that will be sent fr the IDENTIFY command later. */
1514 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1516 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1518 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1520 res_argv[res_argc] = client_id_list->data;
1521 res_argv_lens[res_argc] = idp_len;
1522 res_argv_types[res_argc] = res_argc + 3;
1525 /* Found the client, join it to the channel */
1526 client = (SilcClientEntry)id_cache->context;
1527 chu = silc_calloc(1, sizeof(*chu));
1528 chu->client = client;
1530 silc_list_add(channel->clients, chu);
1532 silc_free(client_id);
1536 silc_buffer_pull(client_id_list, idp_len);
1537 silc_buffer_pull(client_mode_list, 4);
1540 /* Query the client information from server if the list included clients
1541 that we don't know about. */
1545 /* Send the IDENTIFY command to server */
1546 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1547 res_argc, res_argv, res_argv_lens,
1548 res_argv_types, ++conn->cmd_ident);
1549 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1550 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1553 /* Register pending command callback. After we've received the IDENTIFY
1554 command reply we will reprocess this command reply by re-calling this
1555 USERS command reply callback. */
1556 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1557 NULL, silc_client_command_reply_users, cmd);
1559 silc_buffer_free(res_cmd);
1561 silc_free(channel_id);
1563 silc_free(res_argv);
1564 silc_free(res_argv_lens);
1565 silc_free(res_argv_types);
1569 /* Notify application */
1570 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1572 /* Execute any pending command callbacks */
1573 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1575 silc_buffer_free(client_id_list);
1576 silc_buffer_free(client_mode_list);
1580 silc_free(channel_id);
1581 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1582 silc_client_command_reply_free(cmd);