5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 * Command reply functions are "the otherside" of the command functions.
22 * Reply to a command sent by server is handled by these functions.
24 * The arguments received from server are also passed to the calling
25 * application through command_reply client operation. The arguments are
26 * exactly same and in same order as the server sent it. However, ID's are
27 * not sent to the application. Instead, corresponding ID entry is sent
28 * to the application. For example, instead of sending Client ID the
29 * corresponding SilcClientEntry is sent to the application. The case is
30 * same with for example Channel ID's. This way application has all the
31 * necessary data already in hand without redundant searching. If ID is
32 * received but ID entry does not exist, NULL is sent.
36 #include "clientlibincludes.h"
37 #include "client_internal.h"
39 /* Client command reply list. */
40 SilcClientCommandReply silc_command_reply_list[] =
42 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
43 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
44 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
45 SILC_CLIENT_CMD_REPLY(nick, NICK),
46 SILC_CLIENT_CMD_REPLY(list, LIST),
47 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
48 SILC_CLIENT_CMD_REPLY(invite, INVITE),
49 SILC_CLIENT_CMD_REPLY(kill, KILL),
50 SILC_CLIENT_CMD_REPLY(info, INFO),
51 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
52 SILC_CLIENT_CMD_REPLY(ping, PING),
53 SILC_CLIENT_CMD_REPLY(oper, OPER),
54 SILC_CLIENT_CMD_REPLY(join, JOIN),
55 SILC_CLIENT_CMD_REPLY(motd, MOTD),
56 SILC_CLIENT_CMD_REPLY(umode, UMODE),
57 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
58 SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
59 SILC_CLIENT_CMD_REPLY(kick, KICK),
60 SILC_CLIENT_CMD_REPLY(restart, RESTART),
61 SILC_CLIENT_CMD_REPLY(close, CLOSE),
62 SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN),
63 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
64 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
65 SILC_CLIENT_CMD_REPLY(users, USERS),
70 const SilcCommandStatusMessage silc_command_status_messages[] = {
72 { STAT(NO_SUCH_NICK), "There was no such nickname" },
73 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
74 { STAT(NO_SUCH_SERVER), "No such server" },
75 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
76 { STAT(NO_RECIPIENT), "No recipient given" },
77 { STAT(UNKNOWN_COMMAND), "Unknown command" },
78 { STAT(WILDCARDS), "Unknown command" },
79 { STAT(NO_CLIENT_ID), "No Client ID given" },
80 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
81 { STAT(NO_SERVER_ID), "No Server ID given" },
82 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
83 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
84 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
85 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
86 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
87 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
88 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
89 { STAT(USER_ON_CHANNEL), "User already on the channel" },
90 { STAT(NOT_REGISTERED), "You have not registered" },
91 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
92 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
93 { STAT(PERM_DENIED), "Permission denied" },
94 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
95 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
96 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
97 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
98 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
99 { STAT(UNKNOWN_MODE), "Unknown mode" },
100 { STAT(NOT_YOU), "Cannot change mode for other users" },
101 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
102 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
103 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
104 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
105 { STAT(BAD_NICKNAME), "Bad nickname" },
106 { STAT(BAD_CHANNEL), "Bad channel name" },
107 { STAT(AUTH_FAILED), "Authentication failed" },
108 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
112 /* Command reply operation that is called at the end of all command replys.
113 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
114 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
115 #define ARGS cmd->client, cmd->sock->user_data, \
116 cmd->payload, TRUE, silc_command_get(cmd->payload), status
118 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
119 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
120 cmd->sock->user_data, cmd->payload, FALSE, \
121 silc_command_get(cmd->payload), status)
123 /* Process received command reply. */
125 void silc_client_command_reply_process(SilcClient client,
126 SilcSocketConnection sock,
127 SilcPacketContext *packet)
129 SilcBuffer buffer = packet->buffer;
130 SilcClientCommandReply *cmd;
131 SilcClientCommandReplyContext ctx;
132 SilcCommandPayload payload;
134 unsigned short ident;
136 /* Get command reply payload from packet */
137 payload = silc_command_payload_parse(buffer);
139 /* Silently ignore bad reply packet */
140 SILC_LOG_DEBUG(("Bad command reply packet"));
144 /* Allocate command reply context. This must be free'd by the
145 command reply routine receiving it. */
146 ctx = silc_calloc(1, sizeof(*ctx));
147 ctx->client = client;
149 ctx->payload = payload;
150 ctx->args = silc_command_get_args(ctx->payload);
151 ctx->packet = packet;
152 ident = silc_command_get_ident(ctx->payload);
154 /* Check for pending commands and mark to be exeucted */
155 silc_client_command_pending_check(sock->user_data, ctx,
156 silc_command_get(ctx->payload), ident);
158 /* Execute command reply */
159 command = silc_command_get(ctx->payload);
160 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
161 if (cmd->cmd == command)
164 if (cmd == NULL || !cmd->cb) {
172 /* Returns status message string */
174 char *silc_client_command_status_message(SilcCommandStatus status)
178 for (i = 0; silc_command_status_messages[i].message; i++) {
179 if (silc_command_status_messages[i].status == status)
183 if (silc_command_status_messages[i].message == NULL)
186 return silc_command_status_messages[i].message;
189 /* Free command reply context and its internals. */
191 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
194 silc_command_free_payload(cmd->payload);
200 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
201 SilcCommandStatus status)
203 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
204 SilcClientID *client_id;
205 SilcIDCacheEntry id_cache = NULL;
206 SilcClientEntry client_entry = NULL;
208 unsigned char *id_data, *tmp;
209 char *nickname = NULL, *username = NULL;
210 char *realname = NULL;
211 unsigned int idle = 0, mode = 0;
212 SilcBuffer channels = NULL;
214 argc = silc_argument_get_arg_num(cmd->args);
216 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
222 client_id = silc_id_payload_parse_id(id_data, len);
228 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
229 username = silc_argument_get_arg_type(cmd->args, 4, &len);
230 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
231 if (!nickname || !username || !realname) {
236 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
238 channels = silc_buffer_alloc(len);
239 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
240 silc_buffer_put(channels, tmp, len);
243 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
245 SILC_GET32_MSB(mode, tmp);
247 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
249 SILC_GET32_MSB(idle, tmp);
251 /* Check if we have this client cached already. */
252 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
253 SILC_ID_CLIENT, &id_cache)) {
254 SILC_LOG_DEBUG(("Adding new client entry"));
256 client_entry = silc_calloc(1, sizeof(*client_entry));
257 client_entry->id = client_id;
258 silc_parse_nickname(nickname, &client_entry->nickname,
259 &client_entry->server, &client_entry->num);
260 client_entry->username = strdup(username);
262 client_entry->realname = strdup(realname);
263 client_entry->mode = mode;
265 /* Add client to cache */
266 silc_idcache_add(conn->client_cache, client_entry->nickname,
267 strlen(client_entry->nickname),
268 SILC_ID_CLIENT, client_id, (void *)client_entry,
271 client_entry = (SilcClientEntry)id_cache->context;
272 if (client_entry->nickname)
273 silc_free(client_entry->nickname);
274 if (client_entry->server)
275 silc_free(client_entry->server);
276 if (client_entry->username)
277 silc_free(client_entry->username);
278 if (client_entry->realname)
279 silc_free(client_entry->realname);
280 client_entry->mode = mode;
282 SILC_LOG_DEBUG(("Updating client entry"));
284 silc_parse_nickname(nickname, &client_entry->nickname,
285 &client_entry->server, &client_entry->num);
286 client_entry->username = strdup(username);
288 client_entry->realname = strdup(realname);
290 id_cache->data = client_entry->nickname;
291 id_cache->data_len = strlen(client_entry->nickname);
292 silc_idcache_sort_by_data(conn->client_cache);
294 silc_free(client_id);
297 /* Notify application */
299 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
300 channels, mode, idle));
303 silc_buffer_free(channels);
306 /* Received reply for WHOIS command. This maybe called several times
307 for one WHOIS command as server may reply with list of results. */
309 SILC_CLIENT_CMD_REPLY_FUNC(whois)
311 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
312 SilcCommandStatus status;
315 SILC_LOG_DEBUG(("Start"));
317 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
318 SILC_GET16_MSB(status, tmp);
319 if (status != SILC_STATUS_OK &&
320 status != SILC_STATUS_LIST_START &&
321 status != SILC_STATUS_LIST_ITEM &&
322 status != SILC_STATUS_LIST_END) {
327 /* Display one whois reply */
328 if (status == SILC_STATUS_OK)
329 silc_client_command_reply_whois_save(cmd, status);
332 if (status == SILC_STATUS_LIST_START ||
333 status == SILC_STATUS_LIST_ITEM ||
334 status == SILC_STATUS_LIST_END)
335 silc_client_command_reply_whois_save(cmd, status);
337 /* Pending callbacks are not executed if this was an list entry */
338 if (status != SILC_STATUS_OK &&
339 status != SILC_STATUS_LIST_END) {
340 silc_client_command_reply_free(cmd);
344 /* Execute any pending command callbacks */
345 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
348 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
349 silc_client_command_reply_free(cmd);
352 /* Received reply for WHOWAS command. */
354 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
356 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
357 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
358 SilcCommandStatus status;
359 SilcClientID *client_id;
360 SilcIDCacheEntry id_cache = NULL;
361 SilcClientEntry client_entry = NULL;
363 unsigned char *id_data, *tmp;
364 char *nickname, *username;
365 char *realname = NULL;
367 SILC_LOG_DEBUG(("Start"));
369 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
370 SILC_GET16_MSB(status, tmp);
371 if (status != SILC_STATUS_OK &&
372 status != SILC_STATUS_LIST_START &&
373 status != SILC_STATUS_LIST_ITEM &&
374 status != SILC_STATUS_LIST_END) {
379 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
385 client_id = silc_id_payload_parse_id(id_data, len);
391 /* Get the client entry, if exists */
392 if (silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
393 SILC_ID_CLIENT, &id_cache))
394 client_entry = (SilcClientEntry)id_cache->context;
395 silc_free(client_id);
397 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
398 username = silc_argument_get_arg_type(cmd->args, 4, &len);
399 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
400 if (!nickname || !username) {
404 /* Notify application. We don't save any history information to any
405 cache. Just pass the data to the application for displaying on
407 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
409 /* Pending callbacks are not executed if this was an list entry */
410 if (status != SILC_STATUS_OK &&
411 status != SILC_STATUS_LIST_END) {
412 silc_client_command_reply_free(cmd);
416 /* Execute any pending command callbacks */
417 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
420 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
421 silc_client_command_reply_free(cmd);
425 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
426 SilcCommandStatus status)
428 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
429 SilcClientID *client_id;
430 SilcIDCacheEntry id_cache = NULL;
431 SilcClientEntry client_entry = NULL;
433 unsigned char *id_data;
434 char *nickname = NULL, *username = NULL;
436 argc = silc_argument_get_arg_num(cmd->args);
438 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
444 client_id = silc_id_payload_parse_id(id_data, len);
450 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
451 username = silc_argument_get_arg_type(cmd->args, 4, &len);
453 /* Check if we have this client cached already. */
454 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
455 SILC_ID_CLIENT, &id_cache)) {
456 SILC_LOG_DEBUG(("Adding new client entry"));
458 client_entry = silc_calloc(1, sizeof(*client_entry));
459 client_entry->id = client_id;
460 silc_parse_nickname(nickname, &client_entry->nickname,
461 &client_entry->server, &client_entry->num);
463 client_entry->username = strdup(username);
465 /* Add client to cache */
466 silc_idcache_add(conn->client_cache, client_entry->nickname,
467 strlen(client_entry->nickname),
468 SILC_ID_CLIENT, client_id, (void *)client_entry,
471 client_entry = (SilcClientEntry)id_cache->context;
472 if (client_entry->nickname)
473 silc_free(client_entry->nickname);
474 if (client_entry->server)
475 silc_free(client_entry->server);
476 if (username && client_entry->username)
477 silc_free(client_entry->username);
479 SILC_LOG_DEBUG(("Updating client entry"));
481 silc_parse_nickname(nickname, &client_entry->nickname,
482 &client_entry->server, &client_entry->num);
485 client_entry->username = strdup(username);
487 id_cache->data = client_entry->nickname;
488 id_cache->data_len = strlen(client_entry->nickname);
489 silc_idcache_sort_by_data(conn->client_cache);
491 silc_free(client_id);
494 /* Notify application */
495 COMMAND_REPLY((ARGS, client_entry, nickname, username));
498 /* Received reply for IDENTIFY command. This maybe called several times
499 for one IDENTIFY command as server may reply with list of results.
500 This is totally silent and does not print anything on screen. */
502 SILC_CLIENT_CMD_REPLY_FUNC(identify)
504 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
505 SilcCommandStatus status;
508 SILC_LOG_DEBUG(("Start"));
510 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
511 SILC_GET16_MSB(status, tmp);
512 if (status != SILC_STATUS_OK &&
513 status != SILC_STATUS_LIST_START &&
514 status != SILC_STATUS_LIST_ITEM &&
515 status != SILC_STATUS_LIST_END) {
520 /* Save one IDENTIFY entry */
521 if (status == SILC_STATUS_OK)
522 silc_client_command_reply_identify_save(cmd, status);
525 if (status == SILC_STATUS_LIST_START ||
526 status == SILC_STATUS_LIST_ITEM ||
527 status == SILC_STATUS_LIST_END)
528 silc_client_command_reply_identify_save(cmd, status);
530 /* Pending callbacks are not executed if this was an list entry */
531 if (status != SILC_STATUS_OK &&
532 status != SILC_STATUS_LIST_END) {
533 silc_client_command_reply_free(cmd);
537 /* Execute any pending command callbacks */
538 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
541 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
542 silc_client_command_reply_free(cmd);
545 /* Received reply for command NICK. If everything went without errors
546 we just received our new Client ID. */
548 SILC_CLIENT_CMD_REPLY_FUNC(nick)
550 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
551 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
552 SilcCommandStatus status;
555 unsigned int argc, len;
557 SILC_LOG_DEBUG(("Start"));
559 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
560 if (status != SILC_STATUS_OK) {
561 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
562 silc_client_command_status_message(status));
567 argc = silc_argument_get_arg_num(cmd->args);
568 if (argc < 2 || argc > 2) {
569 cmd->client->ops->say(cmd->client, conn,
570 "Cannot set nickname: bad reply to command");
575 /* Take received Client ID */
576 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
577 idp = silc_id_payload_parse_data(tmp, len);
582 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
584 /* Notify application */
585 COMMAND_REPLY((ARGS, conn->local_entry));
587 /* Execute any pending command callbacks */
588 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
591 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
592 silc_client_command_reply_free(cmd);
595 SILC_CLIENT_CMD_REPLY_FUNC(list)
599 /* Received reply to topic command. */
601 SILC_CLIENT_CMD_REPLY_FUNC(topic)
603 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
604 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
605 SilcCommandStatus status;
606 SilcChannelEntry channel;
607 SilcChannelID *channel_id = NULL;
608 SilcIDCacheEntry id_cache = NULL;
611 unsigned int argc, len;
613 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
614 if (status != SILC_STATUS_OK) {
615 cmd->client->ops->say(cmd->client, conn,
616 "%s", silc_client_command_status_message(status));
618 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
619 silc_client_command_reply_free(cmd);
623 argc = silc_argument_get_arg_num(cmd->args);
624 if (argc < 1 || argc > 3) {
629 /* Take Channel ID */
630 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
635 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
639 channel_id = silc_id_payload_parse_id(tmp, len);
643 /* Get the channel name */
644 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
645 SILC_ID_CHANNEL, &id_cache)) {
646 silc_free(channel_id);
651 channel = (SilcChannelEntry)id_cache->context;
653 cmd->client->ops->say(cmd->client, conn,
654 "Topic on channel %s: %s", channel->channel_name,
657 /* Notify application */
658 COMMAND_REPLY((ARGS, channel, topic));
660 /* Execute any pending command callbacks */
661 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
664 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
665 silc_client_command_reply_free(cmd);
668 /* Received reply to invite command. */
670 SILC_CLIENT_CMD_REPLY_FUNC(invite)
672 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
673 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
674 SilcCommandStatus status;
677 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
678 SILC_GET16_MSB(status, tmp);
679 if (status != SILC_STATUS_OK) {
680 cmd->client->ops->say(cmd->client, conn,
681 "%s", silc_client_command_status_message(status));
683 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
684 silc_client_command_reply_free(cmd);
688 /* Notify application */
689 COMMAND_REPLY((ARGS));
691 /* Execute any pending command callbacks */
692 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
694 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
695 silc_client_command_reply_free(cmd);
698 /* Received reply to the KILL command. */
700 SILC_CLIENT_CMD_REPLY_FUNC(kill)
702 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
703 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
704 SilcCommandStatus status;
707 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
708 SILC_GET16_MSB(status, tmp);
709 if (status != SILC_STATUS_OK) {
710 cmd->client->ops->say(cmd->client, conn,
711 "%s", silc_client_command_status_message(status));
716 /* Notify application */
717 COMMAND_REPLY((ARGS));
719 /* Execute any pending command callbacks */
720 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
723 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
724 silc_client_command_reply_free(cmd);
727 /* Received reply to INFO command. We receive the server ID and some
728 information about the server user requested. */
730 SILC_CLIENT_CMD_REPLY_FUNC(info)
732 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
733 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
734 SilcClient client = cmd->client;
735 SilcCommandStatus status;
738 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
739 SILC_GET16_MSB(status, tmp);
740 if (status != SILC_STATUS_OK) {
741 cmd->client->ops->say(cmd->client, conn,
742 "%s", silc_client_command_status_message(status));
744 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
745 silc_client_command_reply_free(cmd);
750 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
754 /* XXX save server id */
756 /* Get server name */
757 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
761 /* Get server info */
762 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
766 client->ops->say(cmd->client, conn, "Info: %s", tmp);
768 /* Notify application */
769 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
771 /* Execute any pending command callbacks */
772 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
775 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
776 silc_client_command_reply_free(cmd);
779 /* Received reply to PING command. The reply time is shown to user. */
781 SILC_CLIENT_CMD_REPLY_FUNC(ping)
783 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
784 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
785 SilcCommandStatus status;
788 time_t diff, curtime;
790 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
791 if (status != SILC_STATUS_OK) {
792 cmd->client->ops->say(cmd->client, conn,
793 "%s", silc_client_command_status_message(status));
798 curtime = time(NULL);
799 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
800 cmd->packet->src_id_type);
806 for (i = 0; i < conn->ping_count; i++) {
807 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
808 diff = curtime - conn->ping[i].start_time;
809 cmd->client->ops->say(cmd->client, conn,
810 "Ping reply from %s: %d second%s",
811 conn->ping[i].dest_name, diff,
812 diff == 1 ? "" : "s");
814 conn->ping[i].start_time = 0;
815 silc_free(conn->ping[i].dest_id);
816 conn->ping[i].dest_id = NULL;
817 silc_free(conn->ping[i].dest_name);
818 conn->ping[i].dest_name = NULL;
825 /* Notify application */
826 COMMAND_REPLY((ARGS));
828 /* Execute any pending command callbacks */
829 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
832 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
833 silc_client_command_reply_free(cmd);
836 /* Received reply for JOIN command. */
838 SILC_CLIENT_CMD_REPLY_FUNC(join)
840 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
841 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
842 SilcCommandStatus status;
843 SilcIDPayload idp = NULL;
844 SilcChannelEntry channel;
845 SilcIDCacheEntry id_cache = NULL;
847 unsigned int argc, mode, len, list_count;
848 char *topic, *tmp, *channel_name = NULL, *hmac;
849 SilcBuffer keyp, client_id_list, client_mode_list;
852 SILC_LOG_DEBUG(("Start"));
854 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
855 if (status != SILC_STATUS_OK) {
856 cmd->client->ops->say(cmd->client, conn,
857 "%s", silc_client_command_status_message(status));
862 argc = silc_argument_get_arg_num(cmd->args);
863 if (argc < 7 || argc > 14) {
864 cmd->client->ops->say(cmd->client, conn,
865 "Cannot join channel: Bad reply packet");
870 /* Get channel name */
871 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
873 cmd->client->ops->say(cmd->client, conn,
874 "Cannot join channel: Bad reply packet");
878 channel_name = strdup(tmp);
881 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
883 cmd->client->ops->say(cmd->client, conn,
884 "Cannot join channel: Bad reply packet");
886 silc_free(channel_name);
889 idp = silc_id_payload_parse_data(tmp, len);
892 silc_free(channel_name);
896 /* Get channel mode */
897 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
899 SILC_GET32_MSB(mode, tmp);
903 /* Get channel key */
904 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
906 silc_id_payload_free(idp);
907 silc_free(channel_name);
910 keyp = silc_buffer_alloc(len);
911 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
912 silc_buffer_put(keyp, tmp, len);
915 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
917 /* Save received Channel ID. This actually creates the channel */
918 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
920 silc_id_payload_free(idp);
923 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
925 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
926 cmd->client->ops->say(cmd->client, conn,
927 "Cannot join channel: Unsupported HMAC `%s'",
930 silc_free(channel_name);
935 /* Get the list count */
936 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
939 SILC_GET32_MSB(list_count, tmp);
941 /* Get Client ID list */
942 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
946 client_id_list = silc_buffer_alloc(len);
947 silc_buffer_pull_tail(client_id_list, len);
948 silc_buffer_put(client_id_list, tmp, len);
950 /* Get client mode list */
951 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
955 client_mode_list = silc_buffer_alloc(len);
956 silc_buffer_pull_tail(client_mode_list, len);
957 silc_buffer_put(client_mode_list, tmp, len);
959 /* Add clients we received in the reply to the channel */
960 for (i = 0; i < list_count; i++) {
961 unsigned short idp_len;
963 SilcClientID *client_id;
964 SilcClientEntry client_entry;
967 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
969 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
974 SILC_GET32_MSB(mode, client_mode_list->data);
976 /* Check if we have this client cached already. */
977 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
978 SILC_ID_CLIENT, &id_cache)) {
979 /* No, we don't have it, add entry for it. */
980 client_entry = silc_calloc(1, sizeof(*client_entry));
981 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
982 silc_idcache_add(conn->client_cache, NULL, 0, SILC_ID_CLIENT,
983 client_entry->id, (void *)client_entry, FALSE, FALSE);
985 /* Yes, we have it already */
986 client_entry = (SilcClientEntry)id_cache->context;
989 /* Join the client to the channel */
990 chu = silc_calloc(1, sizeof(*chu));
991 chu->client = client_entry;
993 silc_list_add(channel->clients, chu);
994 silc_free(client_id);
996 silc_buffer_pull(client_id_list, idp_len);
997 silc_buffer_pull(client_mode_list, 4);
999 silc_buffer_push(client_id_list, client_id_list->data -
1000 client_id_list->head);
1001 silc_buffer_push(client_mode_list, client_mode_list->data -
1002 client_mode_list->head);
1004 /* Save channel key */
1005 silc_client_save_channel_key(conn, keyp, channel);
1007 /* Notify application */
1008 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, keyp->head, NULL,
1009 NULL, topic, hmac, list_count, client_id_list,
1012 /* Execute any pending command callbacks */
1013 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1015 silc_buffer_free(keyp);
1016 silc_buffer_free(client_id_list);
1017 silc_buffer_free(client_mode_list);
1020 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1021 silc_client_command_reply_free(cmd);
1024 /* Received reply for MOTD command */
1026 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1028 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1029 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1030 SilcCommandStatus status;
1031 unsigned int argc, i;
1033 char *motd = NULL, *cp, line[256];
1035 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1036 SILC_GET16_MSB(status, tmp);
1037 if (status != SILC_STATUS_OK) {
1038 cmd->client->ops->say(cmd->client, conn,
1039 "%s", silc_client_command_status_message(status));
1040 COMMAND_REPLY_ERROR;
1044 argc = silc_argument_get_arg_num(cmd->args);
1046 COMMAND_REPLY_ERROR;
1051 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
1053 COMMAND_REPLY_ERROR;
1060 if (cp[i++] == '\n') {
1061 memset(line, 0, sizeof(line));
1062 strncat(line, cp, i - 1);
1068 cmd->client->ops->say(cmd->client, conn, "%s", line);
1077 /* Notify application */
1078 COMMAND_REPLY((ARGS, motd));
1080 /* Execute any pending command callbacks */
1081 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1084 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1085 silc_client_command_reply_free(cmd);
1088 /* Received reply tot he UMODE command. Save the current user mode */
1090 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1092 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1093 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1094 SilcCommandStatus status;
1098 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1099 SILC_GET16_MSB(status, tmp);
1100 if (status != SILC_STATUS_OK) {
1101 cmd->client->ops->say(cmd->client, conn,
1102 "%s", silc_client_command_status_message(status));
1103 COMMAND_REPLY_ERROR;
1107 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1109 COMMAND_REPLY_ERROR;
1113 SILC_GET32_MSB(mode, tmp);
1114 conn->local_entry->mode = mode;
1116 /* Notify application */
1117 COMMAND_REPLY((ARGS, mode));
1119 /* Execute any pending command callbacks */
1120 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1123 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1124 silc_client_command_reply_free(cmd);
1127 /* Received reply for CMODE command. */
1129 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1131 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1132 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1133 SilcCommandStatus status;
1136 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1137 if (status != SILC_STATUS_OK) {
1138 cmd->client->ops->say(cmd->client, conn,
1139 "%s", silc_client_command_status_message(status));
1140 COMMAND_REPLY_ERROR;
1144 /* Get channel mode */
1145 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1147 COMMAND_REPLY_ERROR;
1151 /* Notify application */
1152 COMMAND_REPLY((ARGS, tmp));
1154 /* Execute any pending command callbacks */
1155 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1158 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1159 silc_client_command_reply_free(cmd);
1162 /* Received reply for CUMODE command */
1164 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1166 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1167 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1168 SilcCommandStatus status;
1169 SilcIDCacheEntry id_cache = NULL;
1170 SilcClientID *client_id;
1171 unsigned char *tmp, *id;
1174 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1175 if (status != SILC_STATUS_OK) {
1176 cmd->client->ops->say(cmd->client, conn,
1177 "%s", silc_client_command_status_message(status));
1178 COMMAND_REPLY_ERROR;
1182 /* Get channel mode */
1183 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1185 COMMAND_REPLY_ERROR;
1190 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1192 COMMAND_REPLY_ERROR;
1195 client_id = silc_id_payload_parse_id(id, len);
1197 COMMAND_REPLY_ERROR;
1201 /* Get client entry */
1202 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1203 SILC_ID_CLIENT, &id_cache)) {
1204 COMMAND_REPLY_ERROR;
1208 /* Notify application */
1209 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1210 silc_free(client_id);
1212 /* Execute any pending command callbacks */
1213 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1216 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1217 silc_client_command_reply_free(cmd);
1220 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1222 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1223 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1224 SilcCommandStatus status;
1227 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1228 SILC_GET16_MSB(status, tmp);
1229 if (status != SILC_STATUS_OK) {
1230 cmd->client->ops->say(cmd->client, conn,
1231 "%s", silc_client_command_status_message(status));
1232 COMMAND_REPLY_ERROR;
1236 /* Notify application */
1237 COMMAND_REPLY((ARGS));
1239 /* Execute any pending command callbacks */
1240 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1243 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1244 silc_client_command_reply_free(cmd);
1247 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1249 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1250 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1251 SilcCommandStatus status;
1254 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1255 SILC_GET16_MSB(status, tmp);
1256 if (status != SILC_STATUS_OK) {
1257 cmd->client->ops->say(cmd->client, conn,
1258 "%s", silc_client_command_status_message(status));
1259 COMMAND_REPLY_ERROR;
1263 /* Notify application */
1264 COMMAND_REPLY((ARGS));
1266 /* Execute any pending command callbacks */
1267 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1270 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1271 silc_client_command_reply_free(cmd);
1274 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1276 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1277 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1278 SilcCommandStatus status;
1281 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1282 SILC_GET16_MSB(status, tmp);
1283 if (status != SILC_STATUS_OK) {
1284 cmd->client->ops->say(cmd->client, conn,
1285 "%s", silc_client_command_status_message(status));
1286 COMMAND_REPLY_ERROR;
1290 /* Notify application */
1291 COMMAND_REPLY((ARGS));
1293 /* Execute any pending command callbacks */
1294 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1297 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1298 silc_client_command_reply_free(cmd);
1301 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1303 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1304 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1305 SilcCommandStatus status;
1308 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1309 SILC_GET16_MSB(status, tmp);
1310 if (status != SILC_STATUS_OK) {
1311 cmd->client->ops->say(cmd->client, conn,
1312 "%s", silc_client_command_status_message(status));
1313 COMMAND_REPLY_ERROR;
1317 /* Notify application */
1318 COMMAND_REPLY((ARGS));
1320 /* Execute any pending command callbacks */
1321 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1324 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1325 silc_client_command_reply_free(cmd);
1328 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1330 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1331 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1332 SilcCommandStatus status;
1335 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1336 SILC_GET16_MSB(status, tmp);
1337 if (status != SILC_STATUS_OK) {
1338 cmd->client->ops->say(cmd->client, conn,
1339 "%s", silc_client_command_status_message(status));
1340 COMMAND_REPLY_ERROR;
1344 /* Notify application */
1345 COMMAND_REPLY((ARGS));
1347 /* Execute any pending command callbacks */
1348 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1351 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1352 silc_client_command_reply_free(cmd);
1355 SILC_CLIENT_CMD_REPLY_FUNC(close)
1357 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1358 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1359 SilcCommandStatus status;
1362 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1363 SILC_GET16_MSB(status, tmp);
1364 if (status != SILC_STATUS_OK) {
1365 cmd->client->ops->say(cmd->client, conn,
1366 "%s", silc_client_command_status_message(status));
1367 COMMAND_REPLY_ERROR;
1371 /* Notify application */
1372 COMMAND_REPLY((ARGS));
1374 /* Execute any pending command callbacks */
1375 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1378 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1379 silc_client_command_reply_free(cmd);
1382 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1384 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1385 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1386 SilcCommandStatus status;
1389 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1390 SILC_GET16_MSB(status, tmp);
1391 if (status != SILC_STATUS_OK) {
1392 cmd->client->ops->say(cmd->client, conn,
1393 "%s", silc_client_command_status_message(status));
1394 COMMAND_REPLY_ERROR;
1398 /* Notify application */
1399 COMMAND_REPLY((ARGS));
1401 /* Execute any pending command callbacks */
1402 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1405 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1406 silc_client_command_reply_free(cmd);
1409 /* Reply to LEAVE command. */
1411 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1413 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1414 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1415 SilcCommandStatus status;
1418 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1419 SILC_GET16_MSB(status, tmp);
1420 if (status != SILC_STATUS_OK) {
1421 cmd->client->ops->say(cmd->client, conn,
1422 "%s", silc_client_command_status_message(status));
1423 COMMAND_REPLY_ERROR;
1427 /* Notify application */
1428 COMMAND_REPLY((ARGS));
1430 /* Execute any pending command callbacks */
1431 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1434 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1435 silc_client_command_reply_free(cmd);
1438 /* Reply to USERS command. Received list of client ID's and theirs modes
1439 on the channel we requested. */
1441 SILC_CLIENT_CMD_REPLY_FUNC(users)
1443 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1444 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1445 SilcCommandStatus status;
1446 SilcIDCacheEntry id_cache = NULL;
1447 SilcChannelEntry channel;
1448 SilcChannelUser chu;
1449 SilcChannelID *channel_id = NULL;
1450 SilcBuffer client_id_list;
1451 SilcBuffer client_mode_list;
1453 unsigned int tmp_len, list_count;
1455 unsigned char **res_argv = NULL;
1456 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1458 SILC_LOG_DEBUG(("Start"));
1460 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1461 SILC_GET16_MSB(status, tmp);
1462 if (status != SILC_STATUS_OK) {
1463 cmd->client->ops->say(cmd->client, conn,
1464 "%s", silc_client_command_status_message(status));
1465 COMMAND_REPLY_ERROR;
1469 /* Get channel ID */
1470 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1473 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1477 /* Get the list count */
1478 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1481 SILC_GET32_MSB(list_count, tmp);
1483 /* Get Client ID list */
1484 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1488 client_id_list = silc_buffer_alloc(tmp_len);
1489 silc_buffer_pull_tail(client_id_list, tmp_len);
1490 silc_buffer_put(client_id_list, tmp, tmp_len);
1492 /* Get client mode list */
1493 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1497 client_mode_list = silc_buffer_alloc(tmp_len);
1498 silc_buffer_pull_tail(client_mode_list, tmp_len);
1499 silc_buffer_put(client_mode_list, tmp, tmp_len);
1501 /* Get channel entry */
1502 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1503 SILC_ID_CHANNEL, &id_cache)) {
1504 COMMAND_REPLY_ERROR;
1507 channel = (SilcChannelEntry)id_cache->context;
1509 /* Remove old client list from channel. */
1510 silc_list_start(channel->clients);
1511 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1512 silc_list_del(channel->clients, chu);
1516 /* Cache the received Client ID's and modes. This cache expires
1517 whenever server sends notify message to channel. It means two things;
1518 some user has joined or leaved the channel. XXX! */
1519 for (i = 0; i < list_count; i++) {
1520 unsigned short idp_len;
1522 SilcClientID *client_id;
1523 SilcClientEntry client;
1526 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1528 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1533 SILC_GET32_MSB(mode, client_mode_list->data);
1535 /* Check if we have this client cached already. */
1536 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1537 SILC_ID_CLIENT, &id_cache)) {
1538 /* No we don't have it, query it from the server. Assemble argument
1539 table that will be sent fr the IDENTIFY command later. */
1540 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1542 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1544 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1546 res_argv[res_argc] = client_id_list->data;
1547 res_argv_lens[res_argc] = idp_len;
1548 res_argv_types[res_argc] = res_argc + 3;
1551 /* Found the client, join it to the channel */
1552 client = (SilcClientEntry)id_cache->context;
1553 chu = silc_calloc(1, sizeof(*chu));
1554 chu->client = client;
1556 silc_list_add(channel->clients, chu);
1558 silc_free(client_id);
1562 silc_buffer_pull(client_id_list, idp_len);
1563 silc_buffer_pull(client_mode_list, 4);
1566 /* Query the client information from server if the list included clients
1567 that we don't know about. */
1571 /* Send the IDENTIFY command to server */
1572 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1573 res_argc, res_argv, res_argv_lens,
1574 res_argv_types, ++conn->cmd_ident);
1575 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1576 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1579 /* Register pending command callback. After we've received the IDENTIFY
1580 command reply we will reprocess this command reply by re-calling this
1581 USERS command reply callback. */
1582 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1583 NULL, silc_client_command_reply_users, cmd);
1585 silc_buffer_free(res_cmd);
1587 silc_free(channel_id);
1589 silc_free(res_argv);
1590 silc_free(res_argv_lens);
1591 silc_free(res_argv_types);
1595 /* Notify application */
1596 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1598 /* Execute any pending command callbacks */
1599 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1601 silc_buffer_free(client_id_list);
1602 silc_buffer_free(client_mode_list);
1606 silc_free(channel_id);
1607 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1608 silc_client_command_reply_free(cmd);