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 SILC_ID_CLIENT, client_id, (void *)client_entry,
270 client_entry = (SilcClientEntry)id_cache->context;
271 if (client_entry->nickname)
272 silc_free(client_entry->nickname);
273 if (client_entry->server)
274 silc_free(client_entry->server);
275 if (client_entry->username)
276 silc_free(client_entry->username);
277 if (client_entry->realname)
278 silc_free(client_entry->realname);
279 client_entry->mode = mode;
281 SILC_LOG_DEBUG(("Updating client entry"));
283 silc_parse_nickname(nickname, &client_entry->nickname,
284 &client_entry->server, &client_entry->num);
285 client_entry->username = strdup(username);
287 client_entry->realname = strdup(realname);
289 id_cache->data = client_entry->nickname;
290 silc_idcache_sort_by_data(conn->client_cache);
292 silc_free(client_id);
295 /* Notify application */
297 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
298 channels, mode, idle));
301 silc_buffer_free(channels);
304 /* Received reply for WHOIS command. This maybe called several times
305 for one WHOIS command as server may reply with list of results. */
307 SILC_CLIENT_CMD_REPLY_FUNC(whois)
309 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
310 SilcCommandStatus status;
313 SILC_LOG_DEBUG(("Start"));
315 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
316 SILC_GET16_MSB(status, tmp);
317 if (status != SILC_STATUS_OK &&
318 status != SILC_STATUS_LIST_START &&
319 status != SILC_STATUS_LIST_ITEM &&
320 status != SILC_STATUS_LIST_END) {
325 /* Display one whois reply */
326 if (status == SILC_STATUS_OK)
327 silc_client_command_reply_whois_save(cmd, status);
330 if (status == SILC_STATUS_LIST_START ||
331 status == SILC_STATUS_LIST_ITEM ||
332 status == SILC_STATUS_LIST_END)
333 silc_client_command_reply_whois_save(cmd, status);
335 /* Pending callbacks are not executed if this was an list entry */
336 if (status != SILC_STATUS_OK &&
337 status != SILC_STATUS_LIST_END) {
338 silc_client_command_reply_free(cmd);
342 /* Execute any pending command callbacks */
343 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
346 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
347 silc_client_command_reply_free(cmd);
350 /* Received reply for WHOWAS command. */
352 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
354 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
355 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
356 SilcCommandStatus status;
357 SilcClientID *client_id;
358 SilcIDCacheEntry id_cache = NULL;
359 SilcClientEntry client_entry = NULL;
361 unsigned char *id_data, *tmp;
362 char *nickname, *username;
363 char *realname = NULL;
365 SILC_LOG_DEBUG(("Start"));
367 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
368 SILC_GET16_MSB(status, tmp);
369 if (status != SILC_STATUS_OK &&
370 status != SILC_STATUS_LIST_START &&
371 status != SILC_STATUS_LIST_ITEM &&
372 status != SILC_STATUS_LIST_END) {
377 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
383 client_id = silc_id_payload_parse_id(id_data, len);
389 /* Get the client entry, if exists */
390 if (silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
391 SILC_ID_CLIENT, &id_cache))
392 client_entry = (SilcClientEntry)id_cache->context;
393 silc_free(client_id);
395 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
396 username = silc_argument_get_arg_type(cmd->args, 4, &len);
397 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
398 if (!nickname || !username) {
402 /* Notify application. We don't save any history information to any
403 cache. Just pass the data to the application for displaying on
405 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
407 /* Pending callbacks are not executed if this was an list entry */
408 if (status != SILC_STATUS_OK &&
409 status != SILC_STATUS_LIST_END) {
410 silc_client_command_reply_free(cmd);
414 /* Execute any pending command callbacks */
415 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
418 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
419 silc_client_command_reply_free(cmd);
423 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
424 SilcCommandStatus status)
426 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
427 SilcClientID *client_id;
428 SilcIDCacheEntry id_cache = NULL;
429 SilcClientEntry client_entry = NULL;
431 unsigned char *id_data;
432 char *nickname = NULL, *username = NULL;
434 argc = silc_argument_get_arg_num(cmd->args);
436 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
442 client_id = silc_id_payload_parse_id(id_data, len);
448 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
449 username = silc_argument_get_arg_type(cmd->args, 4, &len);
451 /* Check if we have this client cached already. */
452 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
453 SILC_ID_CLIENT, &id_cache)) {
454 SILC_LOG_DEBUG(("Adding new client entry"));
456 client_entry = silc_calloc(1, sizeof(*client_entry));
457 client_entry->id = client_id;
458 silc_parse_nickname(nickname, &client_entry->nickname,
459 &client_entry->server, &client_entry->num);
461 client_entry->username = strdup(username);
463 /* Add client to cache */
464 silc_idcache_add(conn->client_cache, client_entry->nickname,
465 SILC_ID_CLIENT, client_id, (void *)client_entry,
468 client_entry = (SilcClientEntry)id_cache->context;
469 if (client_entry->nickname)
470 silc_free(client_entry->nickname);
471 if (client_entry->server)
472 silc_free(client_entry->server);
473 if (username && client_entry->username)
474 silc_free(client_entry->username);
476 SILC_LOG_DEBUG(("Updating client entry"));
478 silc_parse_nickname(nickname, &client_entry->nickname,
479 &client_entry->server, &client_entry->num);
482 client_entry->username = strdup(username);
484 id_cache->data = client_entry->nickname;
485 silc_idcache_sort_by_data(conn->client_cache);
487 silc_free(client_id);
490 /* Notify application */
491 COMMAND_REPLY((ARGS, client_entry, nickname, username));
494 /* Received reply for IDENTIFY command. This maybe called several times
495 for one IDENTIFY command as server may reply with list of results.
496 This is totally silent and does not print anything on screen. */
498 SILC_CLIENT_CMD_REPLY_FUNC(identify)
500 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
501 SilcCommandStatus status;
504 SILC_LOG_DEBUG(("Start"));
506 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
507 SILC_GET16_MSB(status, tmp);
508 if (status != SILC_STATUS_OK &&
509 status != SILC_STATUS_LIST_START &&
510 status != SILC_STATUS_LIST_ITEM &&
511 status != SILC_STATUS_LIST_END) {
516 /* Save one IDENTIFY entry */
517 if (status == SILC_STATUS_OK)
518 silc_client_command_reply_identify_save(cmd, status);
521 if (status == SILC_STATUS_LIST_START ||
522 status == SILC_STATUS_LIST_ITEM ||
523 status == SILC_STATUS_LIST_END)
524 silc_client_command_reply_identify_save(cmd, status);
526 /* Pending callbacks are not executed if this was an list entry */
527 if (status != SILC_STATUS_OK &&
528 status != SILC_STATUS_LIST_END) {
529 silc_client_command_reply_free(cmd);
533 /* Execute any pending command callbacks */
534 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
537 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
538 silc_client_command_reply_free(cmd);
541 /* Received reply for command NICK. If everything went without errors
542 we just received our new Client ID. */
544 SILC_CLIENT_CMD_REPLY_FUNC(nick)
546 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
547 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
548 SilcCommandStatus status;
551 unsigned int argc, len;
553 SILC_LOG_DEBUG(("Start"));
555 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
556 if (status != SILC_STATUS_OK) {
557 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
558 silc_client_command_status_message(status));
563 argc = silc_argument_get_arg_num(cmd->args);
564 if (argc < 2 || argc > 2) {
565 cmd->client->ops->say(cmd->client, conn,
566 "Cannot set nickname: bad reply to command");
571 /* Take received Client ID */
572 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
573 idp = silc_id_payload_parse_data(tmp, len);
578 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
580 /* Notify application */
581 COMMAND_REPLY((ARGS, conn->local_entry));
583 /* Execute any pending command callbacks */
584 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
587 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
588 silc_client_command_reply_free(cmd);
591 SILC_CLIENT_CMD_REPLY_FUNC(list)
595 /* Received reply to topic command. */
597 SILC_CLIENT_CMD_REPLY_FUNC(topic)
599 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
600 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
601 SilcCommandStatus status;
602 SilcChannelEntry channel;
603 SilcChannelID *channel_id = NULL;
604 SilcIDCacheEntry id_cache = NULL;
607 unsigned int argc, len;
609 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
610 if (status != SILC_STATUS_OK) {
611 cmd->client->ops->say(cmd->client, conn,
612 "%s", silc_client_command_status_message(status));
614 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
615 silc_client_command_reply_free(cmd);
619 argc = silc_argument_get_arg_num(cmd->args);
620 if (argc < 1 || argc > 3) {
625 /* Take Channel ID */
626 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
631 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
635 channel_id = silc_id_payload_parse_id(tmp, len);
639 /* Get the channel name */
640 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
641 SILC_ID_CHANNEL, &id_cache)) {
642 silc_free(channel_id);
647 channel = (SilcChannelEntry)id_cache->context;
649 cmd->client->ops->say(cmd->client, conn,
650 "Topic on channel %s: %s", channel->channel_name,
653 /* Notify application */
654 COMMAND_REPLY((ARGS, channel, topic));
656 /* Execute any pending command callbacks */
657 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
660 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
661 silc_client_command_reply_free(cmd);
664 /* Received reply to invite command. */
666 SILC_CLIENT_CMD_REPLY_FUNC(invite)
668 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
669 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
670 SilcCommandStatus status;
673 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
674 SILC_GET16_MSB(status, tmp);
675 if (status != SILC_STATUS_OK) {
676 cmd->client->ops->say(cmd->client, conn,
677 "%s", silc_client_command_status_message(status));
679 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
680 silc_client_command_reply_free(cmd);
684 /* Notify application */
685 COMMAND_REPLY((ARGS));
687 /* Execute any pending command callbacks */
688 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
690 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
691 silc_client_command_reply_free(cmd);
694 /* Received reply to the KILL command. */
696 SILC_CLIENT_CMD_REPLY_FUNC(kill)
698 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
699 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
700 SilcCommandStatus status;
703 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
704 SILC_GET16_MSB(status, tmp);
705 if (status != SILC_STATUS_OK) {
706 cmd->client->ops->say(cmd->client, conn,
707 "%s", silc_client_command_status_message(status));
712 /* Notify application */
713 COMMAND_REPLY((ARGS));
715 /* Execute any pending command callbacks */
716 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
719 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
720 silc_client_command_reply_free(cmd);
723 /* Received reply to INFO command. We receive the server ID and some
724 information about the server user requested. */
726 SILC_CLIENT_CMD_REPLY_FUNC(info)
728 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
729 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
730 SilcClient client = cmd->client;
731 SilcCommandStatus status;
734 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
735 SILC_GET16_MSB(status, tmp);
736 if (status != SILC_STATUS_OK) {
737 cmd->client->ops->say(cmd->client, conn,
738 "%s", silc_client_command_status_message(status));
740 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
741 silc_client_command_reply_free(cmd);
746 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
750 /* XXX save server id */
752 /* Get server info */
753 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
757 client->ops->say(cmd->client, conn, "Info: %s", tmp);
759 /* Notify application */
760 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
762 /* Execute any pending command callbacks */
763 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
766 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
767 silc_client_command_reply_free(cmd);
770 /* Received reply to PING command. The reply time is shown to user. */
772 SILC_CLIENT_CMD_REPLY_FUNC(ping)
774 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
775 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
776 SilcCommandStatus status;
779 time_t diff, curtime;
781 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
782 if (status != SILC_STATUS_OK) {
783 cmd->client->ops->say(cmd->client, conn,
784 "%s", silc_client_command_status_message(status));
789 curtime = time(NULL);
790 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
791 cmd->packet->src_id_type);
797 for (i = 0; i < conn->ping_count; i++) {
798 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
799 diff = curtime - conn->ping[i].start_time;
800 cmd->client->ops->say(cmd->client, conn,
801 "Ping reply from %s: %d second%s",
802 conn->ping[i].dest_name, diff,
803 diff == 1 ? "" : "s");
805 conn->ping[i].start_time = 0;
806 silc_free(conn->ping[i].dest_id);
807 conn->ping[i].dest_id = NULL;
808 silc_free(conn->ping[i].dest_name);
809 conn->ping[i].dest_name = NULL;
816 /* Notify application */
817 COMMAND_REPLY((ARGS));
819 /* Execute any pending command callbacks */
820 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
823 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
824 silc_client_command_reply_free(cmd);
827 /* Received reply for JOIN command. */
829 SILC_CLIENT_CMD_REPLY_FUNC(join)
831 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
832 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
833 SilcCommandStatus status;
834 SilcIDPayload idp = NULL;
835 SilcChannelEntry channel;
836 SilcIDCacheEntry id_cache = NULL;
838 unsigned int argc, mode, len, list_count;
839 char *topic, *tmp, *channel_name = NULL, *hmac;
840 SilcBuffer keyp, client_id_list, client_mode_list;
843 SILC_LOG_DEBUG(("Start"));
845 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
846 if (status != SILC_STATUS_OK) {
847 cmd->client->ops->say(cmd->client, conn,
848 "%s", silc_client_command_status_message(status));
853 argc = silc_argument_get_arg_num(cmd->args);
854 if (argc < 7 || argc > 14) {
855 cmd->client->ops->say(cmd->client, conn,
856 "Cannot join channel: Bad reply packet");
861 /* Get channel name */
862 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
864 cmd->client->ops->say(cmd->client, conn,
865 "Cannot join channel: Bad reply packet");
869 channel_name = strdup(tmp);
872 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
874 cmd->client->ops->say(cmd->client, conn,
875 "Cannot join channel: Bad reply packet");
877 silc_free(channel_name);
880 idp = silc_id_payload_parse_data(tmp, len);
883 silc_free(channel_name);
887 /* Get channel mode */
888 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
890 SILC_GET32_MSB(mode, tmp);
894 /* Get channel key */
895 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
897 silc_id_payload_free(idp);
898 silc_free(channel_name);
901 keyp = silc_buffer_alloc(len);
902 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
903 silc_buffer_put(keyp, tmp, len);
906 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
908 /* Save received Channel ID. This actually creates the channel */
909 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
911 silc_id_payload_free(idp);
914 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
916 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
917 cmd->client->ops->say(cmd->client, conn,
918 "Cannot join channel: Unsupported HMAC `%s'",
921 silc_free(channel_name);
926 /* Get the list count */
927 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
930 SILC_GET32_MSB(list_count, tmp);
932 /* Get Client ID list */
933 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
937 client_id_list = silc_buffer_alloc(len);
938 silc_buffer_pull_tail(client_id_list, len);
939 silc_buffer_put(client_id_list, tmp, len);
941 /* Get client mode list */
942 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
946 client_mode_list = silc_buffer_alloc(len);
947 silc_buffer_pull_tail(client_mode_list, len);
948 silc_buffer_put(client_mode_list, tmp, len);
950 /* Add clients we received in the reply to the channel */
951 for (i = 0; i < list_count; i++) {
952 unsigned short idp_len;
954 SilcClientID *client_id;
955 SilcClientEntry client_entry;
958 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
960 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
965 SILC_GET32_MSB(mode, client_mode_list->data);
967 /* Check if we have this client cached already. */
968 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
969 SILC_ID_CLIENT, &id_cache)) {
970 /* No, we don't have it, add entry for it. */
971 client_entry = silc_calloc(1, sizeof(*client_entry));
972 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
973 silc_idcache_add(conn->client_cache, NULL, SILC_ID_CLIENT,
974 client_entry->id, (void *)client_entry, FALSE, FALSE);
976 /* Yes, we have it already */
977 client_entry = (SilcClientEntry)id_cache->context;
980 /* Join the client to the channel */
981 chu = silc_calloc(1, sizeof(*chu));
982 chu->client = client_entry;
984 silc_list_add(channel->clients, chu);
985 silc_free(client_id);
987 silc_buffer_pull(client_id_list, idp_len);
988 silc_buffer_pull(client_mode_list, 4);
990 silc_buffer_push(client_id_list, client_id_list->data -
991 client_id_list->head);
992 silc_buffer_push(client_mode_list, client_mode_list->data -
993 client_mode_list->head);
995 /* Save channel key */
996 silc_client_save_channel_key(conn, keyp, channel);
998 /* Notify application */
999 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, keyp->head, NULL,
1000 NULL, topic, hmac, list_count, client_id_list,
1003 /* Execute any pending command callbacks */
1004 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1006 silc_buffer_free(keyp);
1007 silc_buffer_free(client_id_list);
1008 silc_buffer_free(client_mode_list);
1011 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1012 silc_client_command_reply_free(cmd);
1015 /* Received reply for MOTD command */
1017 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1019 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1020 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1021 SilcCommandStatus status;
1022 unsigned int argc, i;
1024 char *motd = NULL, *cp, line[256];
1026 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1027 SILC_GET16_MSB(status, tmp);
1028 if (status != SILC_STATUS_OK) {
1029 cmd->client->ops->say(cmd->client, conn,
1030 "%s", silc_client_command_status_message(status));
1031 COMMAND_REPLY_ERROR;
1035 argc = silc_argument_get_arg_num(cmd->args);
1037 COMMAND_REPLY_ERROR;
1042 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
1044 COMMAND_REPLY_ERROR;
1051 if (cp[i++] == '\n') {
1052 memset(line, 0, sizeof(line));
1053 strncat(line, cp, i - 1);
1059 cmd->client->ops->say(cmd->client, conn, "%s", line);
1068 /* Notify application */
1069 COMMAND_REPLY((ARGS, motd));
1071 /* Execute any pending command callbacks */
1072 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1075 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1076 silc_client_command_reply_free(cmd);
1079 /* Received reply tot he UMODE command. Save the current user mode */
1081 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1083 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1084 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1085 SilcCommandStatus status;
1089 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1090 SILC_GET16_MSB(status, tmp);
1091 if (status != SILC_STATUS_OK) {
1092 cmd->client->ops->say(cmd->client, conn,
1093 "%s", silc_client_command_status_message(status));
1094 COMMAND_REPLY_ERROR;
1098 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1100 COMMAND_REPLY_ERROR;
1104 SILC_GET32_MSB(mode, tmp);
1105 conn->local_entry->mode = mode;
1107 /* Notify application */
1108 COMMAND_REPLY((ARGS, mode));
1110 /* Execute any pending command callbacks */
1111 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1114 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1115 silc_client_command_reply_free(cmd);
1118 /* Received reply for CMODE command. */
1120 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1122 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1123 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1124 SilcCommandStatus status;
1127 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1128 if (status != SILC_STATUS_OK) {
1129 cmd->client->ops->say(cmd->client, conn,
1130 "%s", silc_client_command_status_message(status));
1131 COMMAND_REPLY_ERROR;
1135 /* Get channel mode */
1136 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1138 COMMAND_REPLY_ERROR;
1142 /* Notify application */
1143 COMMAND_REPLY((ARGS, tmp));
1145 /* Execute any pending command callbacks */
1146 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1149 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1150 silc_client_command_reply_free(cmd);
1153 /* Received reply for CUMODE command */
1155 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1157 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1158 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1159 SilcCommandStatus status;
1160 SilcIDCacheEntry id_cache = NULL;
1161 SilcClientID *client_id;
1162 unsigned char *tmp, *id;
1165 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1166 if (status != SILC_STATUS_OK) {
1167 cmd->client->ops->say(cmd->client, conn,
1168 "%s", silc_client_command_status_message(status));
1169 COMMAND_REPLY_ERROR;
1173 /* Get channel mode */
1174 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1176 COMMAND_REPLY_ERROR;
1181 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1183 COMMAND_REPLY_ERROR;
1186 client_id = silc_id_payload_parse_id(id, len);
1188 COMMAND_REPLY_ERROR;
1192 /* Get client entry */
1193 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1194 SILC_ID_CLIENT, &id_cache)) {
1195 COMMAND_REPLY_ERROR;
1199 /* Notify application */
1200 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1201 silc_free(client_id);
1203 /* Execute any pending command callbacks */
1204 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1207 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1208 silc_client_command_reply_free(cmd);
1211 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1213 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1214 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1215 SilcCommandStatus status;
1218 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1219 SILC_GET16_MSB(status, tmp);
1220 if (status != SILC_STATUS_OK) {
1221 cmd->client->ops->say(cmd->client, conn,
1222 "%s", silc_client_command_status_message(status));
1223 COMMAND_REPLY_ERROR;
1227 /* Notify application */
1228 COMMAND_REPLY((ARGS));
1230 /* Execute any pending command callbacks */
1231 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1234 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1235 silc_client_command_reply_free(cmd);
1238 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1240 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1241 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1242 SilcCommandStatus status;
1245 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1246 SILC_GET16_MSB(status, tmp);
1247 if (status != SILC_STATUS_OK) {
1248 cmd->client->ops->say(cmd->client, conn,
1249 "%s", silc_client_command_status_message(status));
1250 COMMAND_REPLY_ERROR;
1254 /* Notify application */
1255 COMMAND_REPLY((ARGS));
1257 /* Execute any pending command callbacks */
1258 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1261 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1262 silc_client_command_reply_free(cmd);
1265 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1267 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1268 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1269 SilcCommandStatus status;
1272 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1273 SILC_GET16_MSB(status, tmp);
1274 if (status != SILC_STATUS_OK) {
1275 cmd->client->ops->say(cmd->client, conn,
1276 "%s", silc_client_command_status_message(status));
1277 COMMAND_REPLY_ERROR;
1281 /* Notify application */
1282 COMMAND_REPLY((ARGS));
1284 /* Execute any pending command callbacks */
1285 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1288 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1289 silc_client_command_reply_free(cmd);
1292 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1294 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1295 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1296 SilcCommandStatus status;
1299 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1300 SILC_GET16_MSB(status, tmp);
1301 if (status != SILC_STATUS_OK) {
1302 cmd->client->ops->say(cmd->client, conn,
1303 "%s", silc_client_command_status_message(status));
1304 COMMAND_REPLY_ERROR;
1308 /* Notify application */
1309 COMMAND_REPLY((ARGS));
1311 /* Execute any pending command callbacks */
1312 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1315 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1316 silc_client_command_reply_free(cmd);
1319 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1321 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1322 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1323 SilcCommandStatus status;
1326 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1327 SILC_GET16_MSB(status, tmp);
1328 if (status != SILC_STATUS_OK) {
1329 cmd->client->ops->say(cmd->client, conn,
1330 "%s", silc_client_command_status_message(status));
1331 COMMAND_REPLY_ERROR;
1335 /* Notify application */
1336 COMMAND_REPLY((ARGS));
1338 /* Execute any pending command callbacks */
1339 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1342 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1343 silc_client_command_reply_free(cmd);
1346 SILC_CLIENT_CMD_REPLY_FUNC(close)
1348 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1349 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1350 SilcCommandStatus status;
1353 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1354 SILC_GET16_MSB(status, tmp);
1355 if (status != SILC_STATUS_OK) {
1356 cmd->client->ops->say(cmd->client, conn,
1357 "%s", silc_client_command_status_message(status));
1358 COMMAND_REPLY_ERROR;
1362 /* Notify application */
1363 COMMAND_REPLY((ARGS));
1365 /* Execute any pending command callbacks */
1366 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1369 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1370 silc_client_command_reply_free(cmd);
1373 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1375 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1376 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1377 SilcCommandStatus status;
1380 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1381 SILC_GET16_MSB(status, tmp);
1382 if (status != SILC_STATUS_OK) {
1383 cmd->client->ops->say(cmd->client, conn,
1384 "%s", silc_client_command_status_message(status));
1385 COMMAND_REPLY_ERROR;
1389 /* Notify application */
1390 COMMAND_REPLY((ARGS));
1392 /* Execute any pending command callbacks */
1393 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1396 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1397 silc_client_command_reply_free(cmd);
1400 /* Reply to LEAVE command. */
1402 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1404 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1405 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1406 SilcCommandStatus status;
1409 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1410 SILC_GET16_MSB(status, tmp);
1411 if (status != SILC_STATUS_OK) {
1412 cmd->client->ops->say(cmd->client, conn,
1413 "%s", silc_client_command_status_message(status));
1414 COMMAND_REPLY_ERROR;
1418 /* Notify application */
1419 COMMAND_REPLY((ARGS));
1421 /* Execute any pending command callbacks */
1422 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1425 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1426 silc_client_command_reply_free(cmd);
1429 /* Reply to USERS command. Received list of client ID's and theirs modes
1430 on the channel we requested. */
1432 SILC_CLIENT_CMD_REPLY_FUNC(users)
1434 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1435 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1436 SilcCommandStatus status;
1437 SilcIDCacheEntry id_cache = NULL;
1438 SilcChannelEntry channel;
1439 SilcChannelUser chu;
1440 SilcChannelID *channel_id = NULL;
1441 SilcBuffer client_id_list;
1442 SilcBuffer client_mode_list;
1444 unsigned int tmp_len, list_count;
1446 unsigned char **res_argv = NULL;
1447 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1449 SILC_LOG_DEBUG(("Start"));
1451 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1452 SILC_GET16_MSB(status, tmp);
1453 if (status != SILC_STATUS_OK) {
1454 cmd->client->ops->say(cmd->client, conn,
1455 "%s", silc_client_command_status_message(status));
1456 COMMAND_REPLY_ERROR;
1460 /* Get channel ID */
1461 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1464 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1468 /* Get the list count */
1469 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1472 SILC_GET32_MSB(list_count, tmp);
1474 /* Get Client ID list */
1475 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1479 client_id_list = silc_buffer_alloc(tmp_len);
1480 silc_buffer_pull_tail(client_id_list, tmp_len);
1481 silc_buffer_put(client_id_list, tmp, tmp_len);
1483 /* Get client mode list */
1484 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1488 client_mode_list = silc_buffer_alloc(tmp_len);
1489 silc_buffer_pull_tail(client_mode_list, tmp_len);
1490 silc_buffer_put(client_mode_list, tmp, tmp_len);
1492 /* Get channel entry */
1493 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1494 SILC_ID_CHANNEL, &id_cache)) {
1495 COMMAND_REPLY_ERROR;
1498 channel = (SilcChannelEntry)id_cache->context;
1500 /* Remove old client list from channel. */
1501 silc_list_start(channel->clients);
1502 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1503 silc_list_del(channel->clients, chu);
1507 /* Cache the received Client ID's and modes. This cache expires
1508 whenever server sends notify message to channel. It means two things;
1509 some user has joined or leaved the channel. XXX! */
1510 for (i = 0; i < list_count; i++) {
1511 unsigned short idp_len;
1513 SilcClientID *client_id;
1514 SilcClientEntry client;
1517 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1519 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1524 SILC_GET32_MSB(mode, client_mode_list->data);
1526 /* Check if we have this client cached already. */
1527 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1528 SILC_ID_CLIENT, &id_cache)) {
1529 /* No we don't have it, query it from the server. Assemble argument
1530 table that will be sent fr the IDENTIFY command later. */
1531 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1533 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1535 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1537 res_argv[res_argc] = client_id_list->data;
1538 res_argv_lens[res_argc] = idp_len;
1539 res_argv_types[res_argc] = res_argc + 3;
1542 /* Found the client, join it to the channel */
1543 client = (SilcClientEntry)id_cache->context;
1544 chu = silc_calloc(1, sizeof(*chu));
1545 chu->client = client;
1547 silc_list_add(channel->clients, chu);
1549 silc_free(client_id);
1553 silc_buffer_pull(client_id_list, idp_len);
1554 silc_buffer_pull(client_mode_list, 4);
1557 /* Query the client information from server if the list included clients
1558 that we don't know about. */
1562 /* Send the IDENTIFY command to server */
1563 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1564 res_argc, res_argv, res_argv_lens,
1565 res_argv_types, ++conn->cmd_ident);
1566 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1567 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1570 /* Register pending command callback. After we've received the IDENTIFY
1571 command reply we will reprocess this command reply by re-calling this
1572 USERS command reply callback. */
1573 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1574 NULL, silc_client_command_reply_users, cmd);
1576 silc_buffer_free(res_cmd);
1578 silc_free(channel_id);
1580 silc_free(res_argv);
1581 silc_free(res_argv_lens);
1582 silc_free(res_argv_types);
1586 /* Notify application */
1587 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1589 /* Execute any pending command callbacks */
1590 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1592 silc_buffer_free(client_id_list);
1593 silc_buffer_free(client_mode_list);
1597 silc_free(channel_id);
1598 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1599 silc_client_command_reply_free(cmd);