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), "Your host is not among the privileged" },
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 SILC_CLIENT_CMD_REPLY_FUNC(kill)
681 /* Received reply to INFO command. We receive the server ID and some
682 information about the server user requested. */
684 SILC_CLIENT_CMD_REPLY_FUNC(info)
686 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
687 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
688 SilcClient client = cmd->client;
689 SilcCommandStatus status;
692 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
693 SILC_GET16_MSB(status, tmp);
694 if (status != SILC_STATUS_OK) {
695 cmd->client->ops->say(cmd->client, conn,
696 "%s", silc_client_command_status_message(status));
698 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
699 silc_client_command_reply_free(cmd);
704 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
708 /* XXX save server id */
710 /* Get server info */
711 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
715 client->ops->say(cmd->client, conn, "Info: %s", tmp);
717 /* Notify application */
718 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
720 /* Execute any pending command callbacks */
721 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
724 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
725 silc_client_command_reply_free(cmd);
728 /* Received reply to PING command. The reply time is shown to user. */
730 SILC_CLIENT_CMD_REPLY_FUNC(ping)
732 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
733 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
734 SilcCommandStatus status;
737 time_t diff, curtime;
739 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
740 if (status != SILC_STATUS_OK) {
741 cmd->client->ops->say(cmd->client, conn,
742 "%s", silc_client_command_status_message(status));
747 curtime = time(NULL);
748 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
749 cmd->packet->src_id_type);
755 for (i = 0; i < conn->ping_count; i++) {
756 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
757 diff = curtime - conn->ping[i].start_time;
758 cmd->client->ops->say(cmd->client, conn,
759 "Ping reply from %s: %d second%s",
760 conn->ping[i].dest_name, diff,
761 diff == 1 ? "" : "s");
763 conn->ping[i].start_time = 0;
764 silc_free(conn->ping[i].dest_id);
765 conn->ping[i].dest_id = NULL;
766 silc_free(conn->ping[i].dest_name);
767 conn->ping[i].dest_name = NULL;
774 /* Notify application */
775 COMMAND_REPLY((ARGS));
777 /* Execute any pending command callbacks */
778 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
781 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
782 silc_client_command_reply_free(cmd);
785 /* Received reply for JOIN command. */
787 SILC_CLIENT_CMD_REPLY_FUNC(join)
789 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
790 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
791 SilcCommandStatus status;
792 SilcIDPayload idp = NULL;
793 SilcChannelEntry channel;
794 SilcIDCacheEntry id_cache = NULL;
796 unsigned int argc, mode, len, list_count;
797 char *topic, *tmp, *channel_name = NULL, *hmac;
798 SilcBuffer keyp, client_id_list, client_mode_list;
801 SILC_LOG_DEBUG(("Start"));
803 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
804 if (status != SILC_STATUS_OK) {
805 cmd->client->ops->say(cmd->client, conn,
806 "%s", silc_client_command_status_message(status));
811 argc = silc_argument_get_arg_num(cmd->args);
812 if (argc < 7 || argc > 14) {
813 cmd->client->ops->say(cmd->client, conn,
814 "Cannot join channel: Bad reply packet");
819 /* Get channel name */
820 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
822 cmd->client->ops->say(cmd->client, conn,
823 "Cannot join channel: Bad reply packet");
827 channel_name = strdup(tmp);
830 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
832 cmd->client->ops->say(cmd->client, conn,
833 "Cannot join channel: Bad reply packet");
835 silc_free(channel_name);
838 idp = silc_id_payload_parse_data(tmp, len);
841 silc_free(channel_name);
845 /* Get channel mode */
846 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
848 SILC_GET32_MSB(mode, tmp);
852 /* Get channel key */
853 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
855 silc_id_payload_free(idp);
856 silc_free(channel_name);
859 keyp = silc_buffer_alloc(len);
860 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
861 silc_buffer_put(keyp, tmp, len);
864 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
866 /* Save received Channel ID. This actually creates the channel */
867 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
869 silc_id_payload_free(idp);
872 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
874 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
875 cmd->client->ops->say(cmd->client, conn,
876 "Cannot join channel: Unsupported HMAC `%s'",
879 silc_free(channel_name);
884 /* Get the list count */
885 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
888 SILC_GET32_MSB(list_count, tmp);
890 /* Get Client ID list */
891 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
895 client_id_list = silc_buffer_alloc(len);
896 silc_buffer_pull_tail(client_id_list, len);
897 silc_buffer_put(client_id_list, tmp, len);
899 /* Get client mode list */
900 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
904 client_mode_list = silc_buffer_alloc(len);
905 silc_buffer_pull_tail(client_mode_list, len);
906 silc_buffer_put(client_mode_list, tmp, len);
908 /* Add clients we received in the reply to the channel */
909 for (i = 0; i < list_count; i++) {
910 unsigned short idp_len;
912 SilcClientID *client_id;
913 SilcClientEntry client_entry;
916 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
918 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
923 SILC_GET32_MSB(mode, client_mode_list->data);
925 /* Check if we have this client cached already. */
926 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
927 SILC_ID_CLIENT, &id_cache)) {
928 /* No, we don't have it, add entry for it. */
929 client_entry = silc_calloc(1, sizeof(*client_entry));
930 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
931 silc_idcache_add(conn->client_cache, NULL, SILC_ID_CLIENT,
932 client_entry->id, (void *)client_entry, FALSE, FALSE);
934 /* Yes, we have it already */
935 client_entry = (SilcClientEntry)id_cache->context;
938 /* Join the client to the channel */
939 chu = silc_calloc(1, sizeof(*chu));
940 chu->client = client_entry;
942 silc_list_add(channel->clients, chu);
943 silc_free(client_id);
945 silc_buffer_pull(client_id_list, idp_len);
946 silc_buffer_pull(client_mode_list, 4);
948 silc_buffer_push(client_id_list, client_id_list->data -
949 client_id_list->head);
950 silc_buffer_push(client_mode_list, client_mode_list->data -
951 client_mode_list->head);
953 /* Save channel key */
954 silc_client_save_channel_key(conn, keyp, channel);
956 /* Notify application */
957 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, keyp->head, NULL,
958 NULL, topic, hmac, list_count, client_id_list,
961 /* Execute any pending command callbacks */
962 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
964 silc_buffer_free(keyp);
965 silc_buffer_free(client_id_list);
966 silc_buffer_free(client_mode_list);
969 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
970 silc_client_command_reply_free(cmd);
973 /* Received reply for MOTD command */
975 SILC_CLIENT_CMD_REPLY_FUNC(motd)
977 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
978 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
979 SilcCommandStatus status;
980 unsigned int argc, i;
982 char *motd = NULL, *cp, line[256];
984 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
985 SILC_GET16_MSB(status, tmp);
986 if (status != SILC_STATUS_OK) {
987 cmd->client->ops->say(cmd->client, conn,
988 "%s", silc_client_command_status_message(status));
993 argc = silc_argument_get_arg_num(cmd->args);
1000 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
1002 COMMAND_REPLY_ERROR;
1009 if (cp[i++] == '\n') {
1010 memset(line, 0, sizeof(line));
1011 strncat(line, cp, i - 1);
1017 cmd->client->ops->say(cmd->client, conn, "%s", line);
1026 /* Notify application */
1027 COMMAND_REPLY((ARGS, motd));
1029 /* Execute any pending command callbacks */
1030 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1033 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1034 silc_client_command_reply_free(cmd);
1037 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1041 /* Received reply for CMODE command. */
1043 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1045 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1046 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1047 SilcCommandStatus status;
1050 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1051 if (status != SILC_STATUS_OK) {
1052 cmd->client->ops->say(cmd->client, conn,
1053 "%s", silc_client_command_status_message(status));
1054 COMMAND_REPLY_ERROR;
1058 /* Get channel mode */
1059 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1061 COMMAND_REPLY_ERROR;
1065 /* Notify application */
1066 COMMAND_REPLY((ARGS, tmp));
1068 /* Execute any pending command callbacks */
1069 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1072 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1073 silc_client_command_reply_free(cmd);
1076 /* Received reply for CUMODE command */
1078 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1080 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1081 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1082 SilcCommandStatus status;
1083 SilcIDCacheEntry id_cache = NULL;
1084 SilcClientID *client_id;
1085 unsigned char *tmp, *id;
1088 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1089 if (status != SILC_STATUS_OK) {
1090 cmd->client->ops->say(cmd->client, conn,
1091 "%s", silc_client_command_status_message(status));
1092 COMMAND_REPLY_ERROR;
1096 /* Get channel mode */
1097 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1099 COMMAND_REPLY_ERROR;
1104 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1106 COMMAND_REPLY_ERROR;
1109 client_id = silc_id_payload_parse_id(id, len);
1111 COMMAND_REPLY_ERROR;
1115 /* Get client entry */
1116 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1117 SILC_ID_CLIENT, &id_cache)) {
1118 COMMAND_REPLY_ERROR;
1122 /* Notify application */
1123 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1124 silc_free(client_id);
1126 /* Execute any pending command callbacks */
1127 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1130 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1131 silc_client_command_reply_free(cmd);
1134 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1136 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1137 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1138 SilcCommandStatus status;
1141 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1142 SILC_GET16_MSB(status, tmp);
1143 if (status != SILC_STATUS_OK) {
1144 cmd->client->ops->say(cmd->client, conn,
1145 "%s", silc_client_command_status_message(status));
1146 COMMAND_REPLY_ERROR;
1150 /* Notify application */
1151 COMMAND_REPLY((ARGS));
1153 /* Execute any pending command callbacks */
1154 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1157 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1158 silc_client_command_reply_free(cmd);
1161 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1163 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1164 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1165 SilcCommandStatus status;
1168 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1169 SILC_GET16_MSB(status, tmp);
1170 if (status != SILC_STATUS_OK) {
1171 cmd->client->ops->say(cmd->client, conn,
1172 "%s", silc_client_command_status_message(status));
1173 COMMAND_REPLY_ERROR;
1177 /* Notify application */
1178 COMMAND_REPLY((ARGS));
1180 /* Execute any pending command callbacks */
1181 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1184 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1185 silc_client_command_reply_free(cmd);
1188 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1190 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1191 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1192 SilcCommandStatus status;
1195 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1196 SILC_GET16_MSB(status, tmp);
1197 if (status != SILC_STATUS_OK) {
1198 cmd->client->ops->say(cmd->client, conn,
1199 "%s", silc_client_command_status_message(status));
1200 COMMAND_REPLY_ERROR;
1204 /* Notify application */
1205 COMMAND_REPLY((ARGS));
1207 /* Execute any pending command callbacks */
1208 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1211 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1212 silc_client_command_reply_free(cmd);
1215 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1217 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1218 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1219 SilcCommandStatus status;
1222 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1223 SILC_GET16_MSB(status, tmp);
1224 if (status != SILC_STATUS_OK) {
1225 cmd->client->ops->say(cmd->client, conn,
1226 "%s", silc_client_command_status_message(status));
1227 COMMAND_REPLY_ERROR;
1231 /* Notify application */
1232 COMMAND_REPLY((ARGS));
1234 /* Execute any pending command callbacks */
1235 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1238 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1239 silc_client_command_reply_free(cmd);
1242 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1244 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1245 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1246 SilcCommandStatus status;
1249 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1250 SILC_GET16_MSB(status, tmp);
1251 if (status != SILC_STATUS_OK) {
1252 cmd->client->ops->say(cmd->client, conn,
1253 "%s", silc_client_command_status_message(status));
1254 COMMAND_REPLY_ERROR;
1258 /* Notify application */
1259 COMMAND_REPLY((ARGS));
1261 /* Execute any pending command callbacks */
1262 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1265 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1266 silc_client_command_reply_free(cmd);
1269 SILC_CLIENT_CMD_REPLY_FUNC(close)
1271 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1272 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1273 SilcCommandStatus status;
1276 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1277 SILC_GET16_MSB(status, tmp);
1278 if (status != SILC_STATUS_OK) {
1279 cmd->client->ops->say(cmd->client, conn,
1280 "%s", silc_client_command_status_message(status));
1281 COMMAND_REPLY_ERROR;
1285 /* Notify application */
1286 COMMAND_REPLY((ARGS));
1288 /* Execute any pending command callbacks */
1289 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1292 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1293 silc_client_command_reply_free(cmd);
1296 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1298 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1299 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1300 SilcCommandStatus status;
1303 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1304 SILC_GET16_MSB(status, tmp);
1305 if (status != SILC_STATUS_OK) {
1306 cmd->client->ops->say(cmd->client, conn,
1307 "%s", silc_client_command_status_message(status));
1308 COMMAND_REPLY_ERROR;
1312 /* Notify application */
1313 COMMAND_REPLY((ARGS));
1315 /* Execute any pending command callbacks */
1316 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1319 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1320 silc_client_command_reply_free(cmd);
1323 /* Reply to LEAVE command. */
1325 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1327 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1328 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1329 SilcCommandStatus status;
1332 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1333 SILC_GET16_MSB(status, tmp);
1334 if (status != SILC_STATUS_OK) {
1335 cmd->client->ops->say(cmd->client, conn,
1336 "%s", silc_client_command_status_message(status));
1337 COMMAND_REPLY_ERROR;
1341 /* Notify application */
1342 COMMAND_REPLY((ARGS));
1344 /* Execute any pending command callbacks */
1345 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1348 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1349 silc_client_command_reply_free(cmd);
1352 /* Reply to USERS command. Received list of client ID's and theirs modes
1353 on the channel we requested. */
1355 SILC_CLIENT_CMD_REPLY_FUNC(users)
1357 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1358 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1359 SilcCommandStatus status;
1360 SilcIDCacheEntry id_cache = NULL;
1361 SilcChannelEntry channel;
1362 SilcChannelUser chu;
1363 SilcChannelID *channel_id = NULL;
1364 SilcBuffer client_id_list;
1365 SilcBuffer client_mode_list;
1367 unsigned int tmp_len, list_count;
1369 unsigned char **res_argv = NULL;
1370 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1372 SILC_LOG_DEBUG(("Start"));
1374 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1375 SILC_GET16_MSB(status, tmp);
1376 if (status != SILC_STATUS_OK) {
1377 cmd->client->ops->say(cmd->client, conn,
1378 "%s", silc_client_command_status_message(status));
1379 COMMAND_REPLY_ERROR;
1383 /* Get channel ID */
1384 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1387 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1391 /* Get the list count */
1392 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1395 SILC_GET32_MSB(list_count, tmp);
1397 /* Get Client ID list */
1398 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1402 client_id_list = silc_buffer_alloc(tmp_len);
1403 silc_buffer_pull_tail(client_id_list, tmp_len);
1404 silc_buffer_put(client_id_list, tmp, tmp_len);
1406 /* Get client mode list */
1407 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1411 client_mode_list = silc_buffer_alloc(tmp_len);
1412 silc_buffer_pull_tail(client_mode_list, tmp_len);
1413 silc_buffer_put(client_mode_list, tmp, tmp_len);
1415 /* Get channel entry */
1416 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1417 SILC_ID_CHANNEL, &id_cache)) {
1418 COMMAND_REPLY_ERROR;
1421 channel = (SilcChannelEntry)id_cache->context;
1423 /* Remove old client list from channel. */
1424 silc_list_start(channel->clients);
1425 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1426 silc_list_del(channel->clients, chu);
1430 /* Cache the received Client ID's and modes. This cache expires
1431 whenever server sends notify message to channel. It means two things;
1432 some user has joined or leaved the channel. XXX! */
1433 for (i = 0; i < list_count; i++) {
1434 unsigned short idp_len;
1436 SilcClientID *client_id;
1437 SilcClientEntry client;
1440 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1442 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1447 SILC_GET32_MSB(mode, client_mode_list->data);
1449 /* Check if we have this client cached already. */
1450 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1451 SILC_ID_CLIENT, &id_cache)) {
1452 /* No we don't have it, query it from the server. Assemble argument
1453 table that will be sent fr the IDENTIFY command later. */
1454 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1456 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1458 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1460 res_argv[res_argc] = client_id_list->data;
1461 res_argv_lens[res_argc] = idp_len;
1462 res_argv_types[res_argc] = res_argc + 3;
1465 /* Found the client, join it to the channel */
1466 client = (SilcClientEntry)id_cache->context;
1467 chu = silc_calloc(1, sizeof(*chu));
1468 chu->client = client;
1470 silc_list_add(channel->clients, chu);
1472 silc_free(client_id);
1476 silc_buffer_pull(client_id_list, idp_len);
1477 silc_buffer_pull(client_mode_list, 4);
1480 /* Query the client information from server if the list included clients
1481 that we don't know about. */
1485 /* Send the IDENTIFY command to server */
1486 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1487 res_argc, res_argv, res_argv_lens,
1488 res_argv_types, ++conn->cmd_ident);
1489 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1490 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1493 /* Register pending command callback. After we've received the IDENTIFY
1494 command reply we will reprocess this command reply by re-calling this
1495 USERS command reply callback. */
1496 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1497 NULL, silc_client_command_reply_users, cmd);
1499 silc_buffer_free(res_cmd);
1501 silc_free(channel_id);
1503 silc_free(res_argv);
1504 silc_free(res_argv_lens);
1505 silc_free(res_argv_types);
1509 /* Notify application */
1510 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1512 /* Execute any pending command callbacks */
1513 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1515 silc_buffer_free(client_id_list);
1516 silc_buffer_free(client_mode_list);
1520 silc_free(channel_id);
1521 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1522 silc_client_command_reply_free(cmd);