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 /* 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_CLOSE);
702 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
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 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1066 /* Received reply for CMODE command. */
1068 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1070 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1071 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1072 SilcCommandStatus status;
1075 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1076 if (status != SILC_STATUS_OK) {
1077 cmd->client->ops->say(cmd->client, conn,
1078 "%s", silc_client_command_status_message(status));
1079 COMMAND_REPLY_ERROR;
1083 /* Get channel mode */
1084 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1086 COMMAND_REPLY_ERROR;
1090 /* Notify application */
1091 COMMAND_REPLY((ARGS, tmp));
1093 /* Execute any pending command callbacks */
1094 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1097 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1098 silc_client_command_reply_free(cmd);
1101 /* Received reply for CUMODE command */
1103 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1105 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1106 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1107 SilcCommandStatus status;
1108 SilcIDCacheEntry id_cache = NULL;
1109 SilcClientID *client_id;
1110 unsigned char *tmp, *id;
1113 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1114 if (status != SILC_STATUS_OK) {
1115 cmd->client->ops->say(cmd->client, conn,
1116 "%s", silc_client_command_status_message(status));
1117 COMMAND_REPLY_ERROR;
1121 /* Get channel mode */
1122 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1124 COMMAND_REPLY_ERROR;
1129 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1131 COMMAND_REPLY_ERROR;
1134 client_id = silc_id_payload_parse_id(id, len);
1136 COMMAND_REPLY_ERROR;
1140 /* Get client entry */
1141 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1142 SILC_ID_CLIENT, &id_cache)) {
1143 COMMAND_REPLY_ERROR;
1147 /* Notify application */
1148 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1149 silc_free(client_id);
1151 /* Execute any pending command callbacks */
1152 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1155 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1156 silc_client_command_reply_free(cmd);
1159 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1161 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1162 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1163 SilcCommandStatus status;
1166 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1167 SILC_GET16_MSB(status, tmp);
1168 if (status != SILC_STATUS_OK) {
1169 cmd->client->ops->say(cmd->client, conn,
1170 "%s", silc_client_command_status_message(status));
1171 COMMAND_REPLY_ERROR;
1175 /* Notify application */
1176 COMMAND_REPLY((ARGS));
1178 /* Execute any pending command callbacks */
1179 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1182 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1183 silc_client_command_reply_free(cmd);
1186 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1188 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1189 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1190 SilcCommandStatus status;
1193 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1194 SILC_GET16_MSB(status, tmp);
1195 if (status != SILC_STATUS_OK) {
1196 cmd->client->ops->say(cmd->client, conn,
1197 "%s", silc_client_command_status_message(status));
1198 COMMAND_REPLY_ERROR;
1202 /* Notify application */
1203 COMMAND_REPLY((ARGS));
1205 /* Execute any pending command callbacks */
1206 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1209 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1210 silc_client_command_reply_free(cmd);
1213 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1215 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1216 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1217 SilcCommandStatus status;
1220 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1221 SILC_GET16_MSB(status, tmp);
1222 if (status != SILC_STATUS_OK) {
1223 cmd->client->ops->say(cmd->client, conn,
1224 "%s", silc_client_command_status_message(status));
1225 COMMAND_REPLY_ERROR;
1229 /* Notify application */
1230 COMMAND_REPLY((ARGS));
1232 /* Execute any pending command callbacks */
1233 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1236 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1237 silc_client_command_reply_free(cmd);
1240 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1242 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1243 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1244 SilcCommandStatus status;
1247 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1248 SILC_GET16_MSB(status, tmp);
1249 if (status != SILC_STATUS_OK) {
1250 cmd->client->ops->say(cmd->client, conn,
1251 "%s", silc_client_command_status_message(status));
1252 COMMAND_REPLY_ERROR;
1256 /* Notify application */
1257 COMMAND_REPLY((ARGS));
1259 /* Execute any pending command callbacks */
1260 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1263 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1264 silc_client_command_reply_free(cmd);
1267 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1269 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1270 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1271 SilcCommandStatus status;
1274 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1275 SILC_GET16_MSB(status, tmp);
1276 if (status != SILC_STATUS_OK) {
1277 cmd->client->ops->say(cmd->client, conn,
1278 "%s", silc_client_command_status_message(status));
1279 COMMAND_REPLY_ERROR;
1283 /* Notify application */
1284 COMMAND_REPLY((ARGS));
1286 /* Execute any pending command callbacks */
1287 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1290 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1291 silc_client_command_reply_free(cmd);
1294 SILC_CLIENT_CMD_REPLY_FUNC(close)
1296 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1297 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1298 SilcCommandStatus status;
1301 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1302 SILC_GET16_MSB(status, tmp);
1303 if (status != SILC_STATUS_OK) {
1304 cmd->client->ops->say(cmd->client, conn,
1305 "%s", silc_client_command_status_message(status));
1306 COMMAND_REPLY_ERROR;
1310 /* Notify application */
1311 COMMAND_REPLY((ARGS));
1313 /* Execute any pending command callbacks */
1314 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1317 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1318 silc_client_command_reply_free(cmd);
1321 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1323 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1324 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1325 SilcCommandStatus status;
1328 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1329 SILC_GET16_MSB(status, tmp);
1330 if (status != SILC_STATUS_OK) {
1331 cmd->client->ops->say(cmd->client, conn,
1332 "%s", silc_client_command_status_message(status));
1333 COMMAND_REPLY_ERROR;
1337 /* Notify application */
1338 COMMAND_REPLY((ARGS));
1340 /* Execute any pending command callbacks */
1341 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1344 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1345 silc_client_command_reply_free(cmd);
1348 /* Reply to LEAVE command. */
1350 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1352 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1353 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1354 SilcCommandStatus status;
1357 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1358 SILC_GET16_MSB(status, tmp);
1359 if (status != SILC_STATUS_OK) {
1360 cmd->client->ops->say(cmd->client, conn,
1361 "%s", silc_client_command_status_message(status));
1362 COMMAND_REPLY_ERROR;
1366 /* Notify application */
1367 COMMAND_REPLY((ARGS));
1369 /* Execute any pending command callbacks */
1370 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1373 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1374 silc_client_command_reply_free(cmd);
1377 /* Reply to USERS command. Received list of client ID's and theirs modes
1378 on the channel we requested. */
1380 SILC_CLIENT_CMD_REPLY_FUNC(users)
1382 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1383 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1384 SilcCommandStatus status;
1385 SilcIDCacheEntry id_cache = NULL;
1386 SilcChannelEntry channel;
1387 SilcChannelUser chu;
1388 SilcChannelID *channel_id = NULL;
1389 SilcBuffer client_id_list;
1390 SilcBuffer client_mode_list;
1392 unsigned int tmp_len, list_count;
1394 unsigned char **res_argv = NULL;
1395 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1397 SILC_LOG_DEBUG(("Start"));
1399 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1400 SILC_GET16_MSB(status, tmp);
1401 if (status != SILC_STATUS_OK) {
1402 cmd->client->ops->say(cmd->client, conn,
1403 "%s", silc_client_command_status_message(status));
1404 COMMAND_REPLY_ERROR;
1408 /* Get channel ID */
1409 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1412 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1416 /* Get the list count */
1417 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1420 SILC_GET32_MSB(list_count, tmp);
1422 /* Get Client ID list */
1423 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1427 client_id_list = silc_buffer_alloc(tmp_len);
1428 silc_buffer_pull_tail(client_id_list, tmp_len);
1429 silc_buffer_put(client_id_list, tmp, tmp_len);
1431 /* Get client mode list */
1432 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1436 client_mode_list = silc_buffer_alloc(tmp_len);
1437 silc_buffer_pull_tail(client_mode_list, tmp_len);
1438 silc_buffer_put(client_mode_list, tmp, tmp_len);
1440 /* Get channel entry */
1441 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1442 SILC_ID_CHANNEL, &id_cache)) {
1443 COMMAND_REPLY_ERROR;
1446 channel = (SilcChannelEntry)id_cache->context;
1448 /* Remove old client list from channel. */
1449 silc_list_start(channel->clients);
1450 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1451 silc_list_del(channel->clients, chu);
1455 /* Cache the received Client ID's and modes. This cache expires
1456 whenever server sends notify message to channel. It means two things;
1457 some user has joined or leaved the channel. XXX! */
1458 for (i = 0; i < list_count; i++) {
1459 unsigned short idp_len;
1461 SilcClientID *client_id;
1462 SilcClientEntry client;
1465 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1467 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1472 SILC_GET32_MSB(mode, client_mode_list->data);
1474 /* Check if we have this client cached already. */
1475 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1476 SILC_ID_CLIENT, &id_cache)) {
1477 /* No we don't have it, query it from the server. Assemble argument
1478 table that will be sent fr the IDENTIFY command later. */
1479 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1481 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1483 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1485 res_argv[res_argc] = client_id_list->data;
1486 res_argv_lens[res_argc] = idp_len;
1487 res_argv_types[res_argc] = res_argc + 3;
1490 /* Found the client, join it to the channel */
1491 client = (SilcClientEntry)id_cache->context;
1492 chu = silc_calloc(1, sizeof(*chu));
1493 chu->client = client;
1495 silc_list_add(channel->clients, chu);
1497 silc_free(client_id);
1501 silc_buffer_pull(client_id_list, idp_len);
1502 silc_buffer_pull(client_mode_list, 4);
1505 /* Query the client information from server if the list included clients
1506 that we don't know about. */
1510 /* Send the IDENTIFY command to server */
1511 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1512 res_argc, res_argv, res_argv_lens,
1513 res_argv_types, ++conn->cmd_ident);
1514 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1515 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1518 /* Register pending command callback. After we've received the IDENTIFY
1519 command reply we will reprocess this command reply by re-calling this
1520 USERS command reply callback. */
1521 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1522 NULL, silc_client_command_reply_users, cmd);
1524 silc_buffer_free(res_cmd);
1526 silc_free(channel_id);
1528 silc_free(res_argv);
1529 silc_free(res_argv_lens);
1530 silc_free(res_argv_types);
1534 /* Notify application */
1535 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1537 /* Execute any pending command callbacks */
1538 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1540 silc_buffer_free(client_id_list);
1541 silc_buffer_free(client_mode_list);
1545 silc_free(channel_id);
1546 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1547 silc_client_command_reply_free(cmd);