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 /* Received reply to the LIST command. */
597 SILC_CLIENT_CMD_REPLY_FUNC(list)
599 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
600 SilcCommandStatus status;
601 unsigned char *tmp, *name, *topic;
602 unsigned int usercount = 0;
604 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
605 SILC_GET16_MSB(status, tmp);
606 if (status != SILC_STATUS_OK &&
607 status != SILC_STATUS_LIST_START &&
608 status != SILC_STATUS_LIST_ITEM &&
609 status != SILC_STATUS_LIST_END) {
614 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
615 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
616 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
618 SILC_GET32_MSB(usercount, tmp);
620 /* Notify application */
621 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
623 /* Pending callbacks are not executed if this was an list entry */
624 if (status != SILC_STATUS_OK &&
625 status != SILC_STATUS_LIST_END) {
626 silc_client_command_reply_free(cmd);
630 /* Execute any pending command callbacks */
631 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
634 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
635 silc_client_command_reply_free(cmd);
638 /* Received reply to topic command. */
640 SILC_CLIENT_CMD_REPLY_FUNC(topic)
642 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
643 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
644 SilcCommandStatus status;
645 SilcChannelEntry channel;
646 SilcChannelID *channel_id = NULL;
647 SilcIDCacheEntry id_cache = NULL;
650 unsigned int argc, len;
652 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
653 if (status != SILC_STATUS_OK) {
654 cmd->client->ops->say(cmd->client, conn,
655 "%s", silc_client_command_status_message(status));
657 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
658 silc_client_command_reply_free(cmd);
662 argc = silc_argument_get_arg_num(cmd->args);
663 if (argc < 1 || argc > 3) {
668 /* Take Channel ID */
669 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
674 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
678 channel_id = silc_id_payload_parse_id(tmp, len);
682 /* Get the channel name */
683 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
684 SILC_ID_CHANNEL, &id_cache)) {
685 silc_free(channel_id);
690 channel = (SilcChannelEntry)id_cache->context;
692 cmd->client->ops->say(cmd->client, conn,
693 "Topic on channel %s: %s", channel->channel_name,
696 /* Notify application */
697 COMMAND_REPLY((ARGS, channel, topic));
699 /* Execute any pending command callbacks */
700 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
703 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
704 silc_client_command_reply_free(cmd);
707 /* Received reply to invite command. */
709 SILC_CLIENT_CMD_REPLY_FUNC(invite)
711 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
712 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
713 SilcCommandStatus status;
716 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
717 SILC_GET16_MSB(status, tmp);
718 if (status != SILC_STATUS_OK) {
719 cmd->client->ops->say(cmd->client, conn,
720 "%s", silc_client_command_status_message(status));
722 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
723 silc_client_command_reply_free(cmd);
727 /* Notify application */
728 COMMAND_REPLY((ARGS));
730 /* Execute any pending command callbacks */
731 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
733 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
734 silc_client_command_reply_free(cmd);
737 /* Received reply to the KILL command. */
739 SILC_CLIENT_CMD_REPLY_FUNC(kill)
741 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
742 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
743 SilcCommandStatus status;
746 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
747 SILC_GET16_MSB(status, tmp);
748 if (status != SILC_STATUS_OK) {
749 cmd->client->ops->say(cmd->client, conn,
750 "%s", silc_client_command_status_message(status));
755 /* Notify application */
756 COMMAND_REPLY((ARGS));
758 /* Execute any pending command callbacks */
759 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
762 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
763 silc_client_command_reply_free(cmd);
766 /* Received reply to INFO command. We receive the server ID and some
767 information about the server user requested. */
769 SILC_CLIENT_CMD_REPLY_FUNC(info)
771 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
772 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
773 SilcClient client = cmd->client;
774 SilcCommandStatus status;
777 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
778 SILC_GET16_MSB(status, tmp);
779 if (status != SILC_STATUS_OK) {
780 cmd->client->ops->say(cmd->client, conn,
781 "%s", silc_client_command_status_message(status));
783 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
784 silc_client_command_reply_free(cmd);
789 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
793 /* XXX save server id */
795 /* Get server name */
796 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
800 /* Get server info */
801 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
805 client->ops->say(cmd->client, conn, "Info: %s", tmp);
807 /* Notify application */
808 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
810 /* Execute any pending command callbacks */
811 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
814 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
815 silc_client_command_reply_free(cmd);
818 /* Received reply to PING command. The reply time is shown to user. */
820 SILC_CLIENT_CMD_REPLY_FUNC(ping)
822 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
823 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
824 SilcCommandStatus status;
827 time_t diff, curtime;
829 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
830 if (status != SILC_STATUS_OK) {
831 cmd->client->ops->say(cmd->client, conn,
832 "%s", silc_client_command_status_message(status));
837 curtime = time(NULL);
838 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
839 cmd->packet->src_id_type);
845 for (i = 0; i < conn->ping_count; i++) {
846 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
847 diff = curtime - conn->ping[i].start_time;
848 cmd->client->ops->say(cmd->client, conn,
849 "Ping reply from %s: %d second%s",
850 conn->ping[i].dest_name, diff,
851 diff == 1 ? "" : "s");
853 conn->ping[i].start_time = 0;
854 silc_free(conn->ping[i].dest_id);
855 conn->ping[i].dest_id = NULL;
856 silc_free(conn->ping[i].dest_name);
857 conn->ping[i].dest_name = NULL;
864 /* Notify application */
865 COMMAND_REPLY((ARGS));
867 /* Execute any pending command callbacks */
868 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
871 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
872 silc_client_command_reply_free(cmd);
875 /* Received reply for JOIN command. */
877 SILC_CLIENT_CMD_REPLY_FUNC(join)
879 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
880 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
881 SilcCommandStatus status;
882 SilcIDPayload idp = NULL;
883 SilcChannelEntry channel;
884 SilcIDCacheEntry id_cache = NULL;
886 unsigned int argc, mode, len, list_count;
887 char *topic, *tmp, *channel_name = NULL, *hmac;
888 SilcBuffer keyp, client_id_list, client_mode_list;
891 SILC_LOG_DEBUG(("Start"));
893 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
894 if (status != SILC_STATUS_OK) {
895 cmd->client->ops->say(cmd->client, conn,
896 "%s", silc_client_command_status_message(status));
901 argc = silc_argument_get_arg_num(cmd->args);
902 if (argc < 7 || argc > 14) {
903 cmd->client->ops->say(cmd->client, conn,
904 "Cannot join channel: Bad reply packet");
909 /* Get channel name */
910 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
912 cmd->client->ops->say(cmd->client, conn,
913 "Cannot join channel: Bad reply packet");
917 channel_name = strdup(tmp);
920 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
922 cmd->client->ops->say(cmd->client, conn,
923 "Cannot join channel: Bad reply packet");
925 silc_free(channel_name);
928 idp = silc_id_payload_parse_data(tmp, len);
931 silc_free(channel_name);
935 /* Get channel mode */
936 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
938 SILC_GET32_MSB(mode, tmp);
942 /* Get channel key */
943 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
945 silc_id_payload_free(idp);
946 silc_free(channel_name);
949 keyp = silc_buffer_alloc(len);
950 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
951 silc_buffer_put(keyp, tmp, len);
954 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
956 /* Save received Channel ID. This actually creates the channel */
957 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
959 silc_id_payload_free(idp);
962 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
964 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
965 cmd->client->ops->say(cmd->client, conn,
966 "Cannot join channel: Unsupported HMAC `%s'",
969 silc_free(channel_name);
974 /* Get the list count */
975 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
978 SILC_GET32_MSB(list_count, tmp);
980 /* Get Client ID list */
981 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
985 client_id_list = silc_buffer_alloc(len);
986 silc_buffer_pull_tail(client_id_list, len);
987 silc_buffer_put(client_id_list, tmp, len);
989 /* Get client mode list */
990 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
994 client_mode_list = silc_buffer_alloc(len);
995 silc_buffer_pull_tail(client_mode_list, len);
996 silc_buffer_put(client_mode_list, tmp, len);
998 /* Add clients we received in the reply to the channel */
999 for (i = 0; i < list_count; i++) {
1000 unsigned short idp_len;
1002 SilcClientID *client_id;
1003 SilcClientEntry client_entry;
1006 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1008 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1013 SILC_GET32_MSB(mode, client_mode_list->data);
1015 /* Check if we have this client cached already. */
1016 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1017 SILC_ID_CLIENT, &id_cache)) {
1018 /* No, we don't have it, add entry for it. */
1019 client_entry = silc_calloc(1, sizeof(*client_entry));
1020 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1021 silc_idcache_add(conn->client_cache, NULL, 0, SILC_ID_CLIENT,
1022 client_entry->id, (void *)client_entry, FALSE, FALSE);
1024 /* Yes, we have it already */
1025 client_entry = (SilcClientEntry)id_cache->context;
1028 /* Join the client to the channel */
1029 chu = silc_calloc(1, sizeof(*chu));
1030 chu->client = client_entry;
1032 silc_list_add(channel->clients, chu);
1033 silc_free(client_id);
1035 silc_buffer_pull(client_id_list, idp_len);
1036 silc_buffer_pull(client_mode_list, 4);
1038 silc_buffer_push(client_id_list, client_id_list->data -
1039 client_id_list->head);
1040 silc_buffer_push(client_mode_list, client_mode_list->data -
1041 client_mode_list->head);
1043 /* Save channel key */
1044 silc_client_save_channel_key(conn, keyp, channel);
1046 /* Notify application */
1047 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, keyp->head, NULL,
1048 NULL, topic, hmac, list_count, client_id_list,
1051 /* Execute any pending command callbacks */
1052 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1054 silc_buffer_free(keyp);
1055 silc_buffer_free(client_id_list);
1056 silc_buffer_free(client_mode_list);
1059 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1060 silc_client_command_reply_free(cmd);
1063 /* Received reply for MOTD command */
1065 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1067 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1068 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1069 SilcCommandStatus status;
1070 unsigned int argc, i;
1072 char *motd = NULL, *cp, line[256];
1074 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1075 SILC_GET16_MSB(status, tmp);
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 argc = silc_argument_get_arg_num(cmd->args);
1085 COMMAND_REPLY_ERROR;
1090 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1092 COMMAND_REPLY_ERROR;
1099 if (cp[i++] == '\n') {
1100 memset(line, 0, sizeof(line));
1101 strncat(line, cp, i - 1);
1107 cmd->client->ops->say(cmd->client, conn, "%s", line);
1116 /* Notify application */
1117 COMMAND_REPLY((ARGS, motd));
1119 /* Execute any pending command callbacks */
1120 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1123 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1124 silc_client_command_reply_free(cmd);
1127 /* Received reply tot he UMODE command. Save the current user mode */
1129 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1131 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1132 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1133 SilcCommandStatus status;
1137 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1138 SILC_GET16_MSB(status, tmp);
1139 if (status != SILC_STATUS_OK) {
1140 cmd->client->ops->say(cmd->client, conn,
1141 "%s", silc_client_command_status_message(status));
1142 COMMAND_REPLY_ERROR;
1146 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1148 COMMAND_REPLY_ERROR;
1152 SILC_GET32_MSB(mode, tmp);
1153 conn->local_entry->mode = mode;
1155 /* Notify application */
1156 COMMAND_REPLY((ARGS, mode));
1158 /* Execute any pending command callbacks */
1159 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1162 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1163 silc_client_command_reply_free(cmd);
1166 /* Received reply for CMODE command. */
1168 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1170 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1171 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1172 SilcCommandStatus status;
1175 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1176 if (status != SILC_STATUS_OK) {
1177 cmd->client->ops->say(cmd->client, conn,
1178 "%s", silc_client_command_status_message(status));
1179 COMMAND_REPLY_ERROR;
1183 /* Get channel mode */
1184 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1186 COMMAND_REPLY_ERROR;
1190 /* Notify application */
1191 COMMAND_REPLY((ARGS, tmp));
1193 /* Execute any pending command callbacks */
1194 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1197 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1198 silc_client_command_reply_free(cmd);
1201 /* Received reply for CUMODE command */
1203 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1205 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1206 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1207 SilcCommandStatus status;
1208 SilcIDCacheEntry id_cache = NULL;
1209 SilcClientID *client_id;
1210 unsigned char *tmp, *id;
1213 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1214 if (status != SILC_STATUS_OK) {
1215 cmd->client->ops->say(cmd->client, conn,
1216 "%s", silc_client_command_status_message(status));
1217 COMMAND_REPLY_ERROR;
1221 /* Get channel mode */
1222 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1224 COMMAND_REPLY_ERROR;
1229 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1231 COMMAND_REPLY_ERROR;
1234 client_id = silc_id_payload_parse_id(id, len);
1236 COMMAND_REPLY_ERROR;
1240 /* Get client entry */
1241 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1242 SILC_ID_CLIENT, &id_cache)) {
1243 COMMAND_REPLY_ERROR;
1247 /* Notify application */
1248 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1249 silc_free(client_id);
1251 /* Execute any pending command callbacks */
1252 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1255 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1256 silc_client_command_reply_free(cmd);
1259 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1261 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1262 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1263 SilcCommandStatus status;
1266 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1267 SILC_GET16_MSB(status, tmp);
1268 if (status != SILC_STATUS_OK) {
1269 cmd->client->ops->say(cmd->client, conn,
1270 "%s", silc_client_command_status_message(status));
1271 COMMAND_REPLY_ERROR;
1275 /* Notify application */
1276 COMMAND_REPLY((ARGS));
1278 /* Execute any pending command callbacks */
1279 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1282 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1283 silc_client_command_reply_free(cmd);
1286 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1288 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1289 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1290 SilcCommandStatus status;
1293 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1294 SILC_GET16_MSB(status, tmp);
1295 if (status != SILC_STATUS_OK) {
1296 cmd->client->ops->say(cmd->client, conn,
1297 "%s", silc_client_command_status_message(status));
1298 COMMAND_REPLY_ERROR;
1302 /* Notify application */
1303 COMMAND_REPLY((ARGS));
1305 /* Execute any pending command callbacks */
1306 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1309 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1310 silc_client_command_reply_free(cmd);
1313 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1315 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1316 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1317 SilcCommandStatus status;
1320 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1321 SILC_GET16_MSB(status, tmp);
1322 if (status != SILC_STATUS_OK) {
1323 cmd->client->ops->say(cmd->client, conn,
1324 "%s", silc_client_command_status_message(status));
1325 COMMAND_REPLY_ERROR;
1329 /* Notify application */
1330 COMMAND_REPLY((ARGS));
1332 /* Execute any pending command callbacks */
1333 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1336 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1337 silc_client_command_reply_free(cmd);
1340 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1342 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1343 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1344 SilcCommandStatus status;
1347 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1348 SILC_GET16_MSB(status, tmp);
1349 if (status != SILC_STATUS_OK) {
1350 cmd->client->ops->say(cmd->client, conn,
1351 "%s", silc_client_command_status_message(status));
1352 COMMAND_REPLY_ERROR;
1356 /* Notify application */
1357 COMMAND_REPLY((ARGS));
1359 /* Execute any pending command callbacks */
1360 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1363 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1364 silc_client_command_reply_free(cmd);
1367 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1369 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1370 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1371 SilcCommandStatus status;
1374 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1375 SILC_GET16_MSB(status, tmp);
1376 if (status != SILC_STATUS_OK) {
1377 cmd->client->ops->say(cmd->client, conn,
1378 "%s", silc_client_command_status_message(status));
1379 COMMAND_REPLY_ERROR;
1383 /* Notify application */
1384 COMMAND_REPLY((ARGS));
1386 /* Execute any pending command callbacks */
1387 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1390 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1391 silc_client_command_reply_free(cmd);
1394 SILC_CLIENT_CMD_REPLY_FUNC(close)
1396 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1397 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1398 SilcCommandStatus status;
1401 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1402 SILC_GET16_MSB(status, tmp);
1403 if (status != SILC_STATUS_OK) {
1404 cmd->client->ops->say(cmd->client, conn,
1405 "%s", silc_client_command_status_message(status));
1406 COMMAND_REPLY_ERROR;
1410 /* Notify application */
1411 COMMAND_REPLY((ARGS));
1413 /* Execute any pending command callbacks */
1414 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1417 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1418 silc_client_command_reply_free(cmd);
1421 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1423 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1424 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1425 SilcCommandStatus status;
1428 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1429 SILC_GET16_MSB(status, tmp);
1430 if (status != SILC_STATUS_OK) {
1431 cmd->client->ops->say(cmd->client, conn,
1432 "%s", silc_client_command_status_message(status));
1433 COMMAND_REPLY_ERROR;
1437 /* Notify application */
1438 COMMAND_REPLY((ARGS));
1440 /* Execute any pending command callbacks */
1441 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1444 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1445 silc_client_command_reply_free(cmd);
1448 /* Reply to LEAVE command. */
1450 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1452 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1453 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1454 SilcCommandStatus status;
1457 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1458 SILC_GET16_MSB(status, tmp);
1459 if (status != SILC_STATUS_OK) {
1460 cmd->client->ops->say(cmd->client, conn,
1461 "%s", silc_client_command_status_message(status));
1462 COMMAND_REPLY_ERROR;
1466 /* Notify application */
1467 COMMAND_REPLY((ARGS));
1469 /* Execute any pending command callbacks */
1470 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1473 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1474 silc_client_command_reply_free(cmd);
1477 /* Reply to USERS command. Received list of client ID's and theirs modes
1478 on the channel we requested. */
1480 SILC_CLIENT_CMD_REPLY_FUNC(users)
1482 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1483 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1484 SilcCommandStatus status;
1485 SilcIDCacheEntry id_cache = NULL;
1486 SilcChannelEntry channel;
1487 SilcChannelUser chu;
1488 SilcChannelID *channel_id = NULL;
1489 SilcBuffer client_id_list;
1490 SilcBuffer client_mode_list;
1492 unsigned int tmp_len, list_count;
1494 unsigned char **res_argv = NULL;
1495 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1497 SILC_LOG_DEBUG(("Start"));
1499 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1500 SILC_GET16_MSB(status, tmp);
1501 if (status != SILC_STATUS_OK) {
1502 cmd->client->ops->say(cmd->client, conn,
1503 "%s", silc_client_command_status_message(status));
1504 COMMAND_REPLY_ERROR;
1508 /* Get channel ID */
1509 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1512 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1516 /* Get the list count */
1517 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1520 SILC_GET32_MSB(list_count, tmp);
1522 /* Get Client ID list */
1523 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1527 client_id_list = silc_buffer_alloc(tmp_len);
1528 silc_buffer_pull_tail(client_id_list, tmp_len);
1529 silc_buffer_put(client_id_list, tmp, tmp_len);
1531 /* Get client mode list */
1532 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1536 client_mode_list = silc_buffer_alloc(tmp_len);
1537 silc_buffer_pull_tail(client_mode_list, tmp_len);
1538 silc_buffer_put(client_mode_list, tmp, tmp_len);
1540 /* Get channel entry */
1541 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1542 SILC_ID_CHANNEL, &id_cache)) {
1543 COMMAND_REPLY_ERROR;
1546 channel = (SilcChannelEntry)id_cache->context;
1548 /* Remove old client list from channel. */
1549 silc_list_start(channel->clients);
1550 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1551 silc_list_del(channel->clients, chu);
1555 /* Cache the received Client ID's and modes. This cache expires
1556 whenever server sends notify message to channel. It means two things;
1557 some user has joined or leaved the channel. XXX! */
1558 for (i = 0; i < list_count; i++) {
1559 unsigned short idp_len;
1561 SilcClientID *client_id;
1562 SilcClientEntry client;
1565 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1567 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1572 SILC_GET32_MSB(mode, client_mode_list->data);
1574 /* Check if we have this client cached already. */
1575 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1576 SILC_ID_CLIENT, &id_cache)) {
1577 /* No we don't have it, query it from the server. Assemble argument
1578 table that will be sent fr the IDENTIFY command later. */
1579 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1581 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1583 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1585 res_argv[res_argc] = client_id_list->data;
1586 res_argv_lens[res_argc] = idp_len;
1587 res_argv_types[res_argc] = res_argc + 3;
1590 /* Found the client, join it to the channel */
1591 client = (SilcClientEntry)id_cache->context;
1592 chu = silc_calloc(1, sizeof(*chu));
1593 chu->client = client;
1595 silc_list_add(channel->clients, chu);
1597 silc_free(client_id);
1601 silc_buffer_pull(client_id_list, idp_len);
1602 silc_buffer_pull(client_mode_list, 4);
1605 /* Query the client information from server if the list included clients
1606 that we don't know about. */
1610 /* Send the IDENTIFY command to server */
1611 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1612 res_argc, res_argv, res_argv_lens,
1613 res_argv_types, ++conn->cmd_ident);
1614 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1615 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1618 /* Register pending command callback. After we've received the IDENTIFY
1619 command reply we will reprocess this command reply by re-calling this
1620 USERS command reply callback. */
1621 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1622 NULL, silc_client_command_reply_users, cmd);
1624 silc_buffer_free(res_cmd);
1626 silc_free(channel_id);
1628 silc_free(res_argv);
1629 silc_free(res_argv_lens);
1630 silc_free(res_argv_types);
1634 /* Notify application */
1635 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1637 /* Execute any pending command callbacks */
1638 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1640 silc_buffer_free(client_id_list);
1641 silc_buffer_free(client_mode_list);
1645 silc_free(channel_id);
1646 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1647 silc_client_command_reply_free(cmd);