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(close, CLOSE),
61 SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN),
62 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
63 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
64 SILC_CLIENT_CMD_REPLY(users, USERS),
65 SILC_CLIENT_CMD_REPLY(ban, BAN),
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 entry */
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;
714 SilcChannelEntry channel;
715 SilcChannelID *channel_id;
716 SilcIDCacheEntry id_cache;
720 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
721 SILC_GET16_MSB(status, tmp);
722 if (status != SILC_STATUS_OK) {
723 cmd->client->ops->say(cmd->client, conn,
724 "%s", silc_client_command_status_message(status));
726 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
727 silc_client_command_reply_free(cmd);
731 /* Take Channel ID */
732 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
736 channel_id = silc_id_payload_parse_id(tmp, len);
740 /* Get the channel entry */
741 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
742 SILC_ID_CHANNEL, &id_cache)) {
743 silc_free(channel_id);
748 channel = (SilcChannelEntry)id_cache->context;
750 /* Get the invite list */
751 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
753 /* Notify application */
754 COMMAND_REPLY((ARGS, channel, tmp));
756 /* Execute any pending command callbacks */
757 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
760 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
761 silc_client_command_reply_free(cmd);
764 /* Received reply to the KILL command. */
766 SILC_CLIENT_CMD_REPLY_FUNC(kill)
768 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
769 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
770 SilcCommandStatus status;
773 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
774 SILC_GET16_MSB(status, tmp);
775 if (status != SILC_STATUS_OK) {
776 cmd->client->ops->say(cmd->client, conn,
777 "%s", silc_client_command_status_message(status));
782 /* Notify application */
783 COMMAND_REPLY((ARGS));
785 /* Execute any pending command callbacks */
786 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
789 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
790 silc_client_command_reply_free(cmd);
793 /* Received reply to INFO command. We receive the server ID and some
794 information about the server user requested. */
796 SILC_CLIENT_CMD_REPLY_FUNC(info)
798 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
799 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
800 SilcClient client = cmd->client;
801 SilcCommandStatus status;
804 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
805 SILC_GET16_MSB(status, tmp);
806 if (status != SILC_STATUS_OK) {
807 cmd->client->ops->say(cmd->client, conn,
808 "%s", silc_client_command_status_message(status));
810 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
811 silc_client_command_reply_free(cmd);
816 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
820 /* XXX save server id */
822 /* Get server name */
823 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
827 /* Get server info */
828 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
832 client->ops->say(cmd->client, conn, "Info: %s", tmp);
834 /* Notify application */
835 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
837 /* Execute any pending command callbacks */
838 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
841 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
842 silc_client_command_reply_free(cmd);
845 /* Received reply to PING command. The reply time is shown to user. */
847 SILC_CLIENT_CMD_REPLY_FUNC(ping)
849 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
850 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
851 SilcCommandStatus status;
854 time_t diff, curtime;
856 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
857 if (status != SILC_STATUS_OK) {
858 cmd->client->ops->say(cmd->client, conn,
859 "%s", silc_client_command_status_message(status));
864 curtime = time(NULL);
865 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
866 cmd->packet->src_id_type);
872 for (i = 0; i < conn->ping_count; i++) {
873 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
874 diff = curtime - conn->ping[i].start_time;
875 cmd->client->ops->say(cmd->client, conn,
876 "Ping reply from %s: %d second%s",
877 conn->ping[i].dest_name, diff,
878 diff == 1 ? "" : "s");
880 conn->ping[i].start_time = 0;
881 silc_free(conn->ping[i].dest_id);
882 conn->ping[i].dest_id = NULL;
883 silc_free(conn->ping[i].dest_name);
884 conn->ping[i].dest_name = NULL;
891 /* Notify application */
892 COMMAND_REPLY((ARGS));
894 /* Execute any pending command callbacks */
895 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
898 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
899 silc_client_command_reply_free(cmd);
902 /* Received reply for JOIN command. */
904 SILC_CLIENT_CMD_REPLY_FUNC(join)
906 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
907 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
908 SilcCommandStatus status;
909 SilcIDPayload idp = NULL;
910 SilcChannelEntry channel;
911 SilcIDCacheEntry id_cache = NULL;
913 unsigned int argc, mode, len, list_count;
914 char *topic, *tmp, *channel_name = NULL, *hmac;
915 SilcBuffer keyp = NULL, client_id_list, client_mode_list;
918 SILC_LOG_DEBUG(("Start"));
920 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
921 if (status != SILC_STATUS_OK) {
922 cmd->client->ops->say(cmd->client, conn,
923 "%s", silc_client_command_status_message(status));
928 argc = silc_argument_get_arg_num(cmd->args);
929 if (argc < 7 || argc > 14) {
930 cmd->client->ops->say(cmd->client, conn,
931 "Cannot join channel: Bad reply packet");
936 /* Get channel name */
937 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
939 cmd->client->ops->say(cmd->client, conn,
940 "Cannot join channel: Bad reply packet");
944 channel_name = strdup(tmp);
947 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
949 cmd->client->ops->say(cmd->client, conn,
950 "Cannot join channel: Bad reply packet");
952 silc_free(channel_name);
955 idp = silc_id_payload_parse_data(tmp, len);
958 silc_free(channel_name);
962 /* Get channel mode */
963 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
965 SILC_GET32_MSB(mode, tmp);
969 /* Get channel key */
970 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
972 keyp = silc_buffer_alloc(len);
973 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
974 silc_buffer_put(keyp, tmp, len);
978 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
980 /* Save received Channel ID. This actually creates the channel */
981 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
983 silc_id_payload_free(idp);
986 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
988 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
989 cmd->client->ops->say(cmd->client, conn,
990 "Cannot join channel: Unsupported HMAC `%s'",
993 silc_free(channel_name);
998 /* Get the list count */
999 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1002 SILC_GET32_MSB(list_count, tmp);
1004 /* Get Client ID list */
1005 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1009 client_id_list = silc_buffer_alloc(len);
1010 silc_buffer_pull_tail(client_id_list, len);
1011 silc_buffer_put(client_id_list, tmp, len);
1013 /* Get client mode list */
1014 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1018 client_mode_list = silc_buffer_alloc(len);
1019 silc_buffer_pull_tail(client_mode_list, len);
1020 silc_buffer_put(client_mode_list, tmp, len);
1022 /* Add clients we received in the reply to the channel */
1023 for (i = 0; i < list_count; i++) {
1024 unsigned short idp_len;
1026 SilcClientID *client_id;
1027 SilcClientEntry client_entry;
1030 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1032 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1037 SILC_GET32_MSB(mode, client_mode_list->data);
1039 /* Check if we have this client cached already. */
1040 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1041 SILC_ID_CLIENT, &id_cache)) {
1042 /* No, we don't have it, add entry for it. */
1043 client_entry = silc_calloc(1, sizeof(*client_entry));
1044 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1045 silc_idcache_add(conn->client_cache, NULL, 0, SILC_ID_CLIENT,
1046 client_entry->id, (void *)client_entry, FALSE, FALSE);
1048 /* Yes, we have it already */
1049 client_entry = (SilcClientEntry)id_cache->context;
1052 /* Join the client to the channel */
1053 chu = silc_calloc(1, sizeof(*chu));
1054 chu->client = client_entry;
1056 silc_list_add(channel->clients, chu);
1057 silc_free(client_id);
1059 silc_buffer_pull(client_id_list, idp_len);
1060 silc_buffer_pull(client_mode_list, 4);
1062 silc_buffer_push(client_id_list, client_id_list->data -
1063 client_id_list->head);
1064 silc_buffer_push(client_mode_list, client_mode_list->data -
1065 client_mode_list->head);
1067 /* Save channel key */
1068 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1069 silc_client_save_channel_key(conn, keyp, channel);
1071 /* Client is now joined to the channel */
1072 channel->on_channel = TRUE;
1074 /* Notify application */
1075 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1076 keyp ? keyp->head : NULL, NULL,
1077 NULL, topic, hmac, list_count, client_id_list,
1080 /* Execute any pending command callbacks */
1081 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1084 silc_buffer_free(keyp);
1085 silc_buffer_free(client_id_list);
1086 silc_buffer_free(client_mode_list);
1089 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1090 silc_client_command_reply_free(cmd);
1093 /* Received reply for MOTD command */
1095 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1097 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1098 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1099 SilcCommandStatus status;
1100 unsigned int argc, i;
1102 char *motd = NULL, *cp, line[256];
1104 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1105 SILC_GET16_MSB(status, tmp);
1106 if (status != SILC_STATUS_OK) {
1107 cmd->client->ops->say(cmd->client, conn,
1108 "%s", silc_client_command_status_message(status));
1109 COMMAND_REPLY_ERROR;
1113 argc = silc_argument_get_arg_num(cmd->args);
1115 COMMAND_REPLY_ERROR;
1120 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1122 COMMAND_REPLY_ERROR;
1129 if (cp[i++] == '\n') {
1130 memset(line, 0, sizeof(line));
1131 strncat(line, cp, i - 1);
1137 cmd->client->ops->say(cmd->client, conn, "%s", line);
1146 /* Notify application */
1147 COMMAND_REPLY((ARGS, motd));
1149 /* Execute any pending command callbacks */
1150 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1153 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1154 silc_client_command_reply_free(cmd);
1157 /* Received reply tot he UMODE command. Save the current user mode */
1159 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1161 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1162 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1163 SilcCommandStatus status;
1167 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1168 SILC_GET16_MSB(status, tmp);
1169 if (status != SILC_STATUS_OK) {
1170 cmd->client->ops->say(cmd->client, conn,
1171 "%s", silc_client_command_status_message(status));
1172 COMMAND_REPLY_ERROR;
1176 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1178 COMMAND_REPLY_ERROR;
1182 SILC_GET32_MSB(mode, tmp);
1183 conn->local_entry->mode = mode;
1185 /* Notify application */
1186 COMMAND_REPLY((ARGS, mode));
1188 /* Execute any pending command callbacks */
1189 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1192 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1193 silc_client_command_reply_free(cmd);
1196 /* Received reply for CMODE command. */
1198 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1200 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1201 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1202 SilcCommandStatus status;
1205 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1206 if (status != SILC_STATUS_OK) {
1207 cmd->client->ops->say(cmd->client, conn,
1208 "%s", silc_client_command_status_message(status));
1209 COMMAND_REPLY_ERROR;
1213 /* Get channel mode */
1214 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1216 COMMAND_REPLY_ERROR;
1220 /* Notify application */
1221 COMMAND_REPLY((ARGS, tmp));
1223 /* Execute any pending command callbacks */
1224 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1227 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1228 silc_client_command_reply_free(cmd);
1231 /* Received reply for CUMODE command */
1233 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1235 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1236 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1237 SilcCommandStatus status;
1238 SilcIDCacheEntry id_cache = NULL;
1239 SilcClientID *client_id;
1240 unsigned char *tmp, *id;
1243 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1244 if (status != SILC_STATUS_OK) {
1245 cmd->client->ops->say(cmd->client, conn,
1246 "%s", silc_client_command_status_message(status));
1247 COMMAND_REPLY_ERROR;
1251 /* Get channel mode */
1252 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1254 COMMAND_REPLY_ERROR;
1259 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1261 COMMAND_REPLY_ERROR;
1264 client_id = silc_id_payload_parse_id(id, len);
1266 COMMAND_REPLY_ERROR;
1270 /* Get client entry */
1271 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1272 SILC_ID_CLIENT, &id_cache)) {
1273 COMMAND_REPLY_ERROR;
1277 /* Notify application */
1278 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1279 silc_free(client_id);
1281 /* Execute any pending command callbacks */
1282 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1285 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1286 silc_client_command_reply_free(cmd);
1289 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1291 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1292 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1293 SilcCommandStatus status;
1296 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1297 SILC_GET16_MSB(status, tmp);
1298 if (status != SILC_STATUS_OK) {
1299 cmd->client->ops->say(cmd->client, conn,
1300 "%s", silc_client_command_status_message(status));
1301 COMMAND_REPLY_ERROR;
1305 /* Notify application */
1306 COMMAND_REPLY((ARGS));
1308 /* Execute any pending command callbacks */
1309 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1312 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1313 silc_client_command_reply_free(cmd);
1316 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1318 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1319 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1320 SilcCommandStatus status;
1323 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1324 SILC_GET16_MSB(status, tmp);
1325 if (status != SILC_STATUS_OK) {
1326 cmd->client->ops->say(cmd->client, conn,
1327 "%s", silc_client_command_status_message(status));
1328 COMMAND_REPLY_ERROR;
1332 /* Notify application */
1333 COMMAND_REPLY((ARGS));
1335 /* Execute any pending command callbacks */
1336 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1339 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1340 silc_client_command_reply_free(cmd);
1343 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1345 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1346 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1347 SilcCommandStatus status;
1350 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1351 SILC_GET16_MSB(status, tmp);
1352 if (status != SILC_STATUS_OK) {
1353 cmd->client->ops->say(cmd->client, conn,
1354 "%s", silc_client_command_status_message(status));
1355 COMMAND_REPLY_ERROR;
1359 /* Notify application */
1360 COMMAND_REPLY((ARGS));
1362 /* Execute any pending command callbacks */
1363 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1366 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1367 silc_client_command_reply_free(cmd);
1370 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1372 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1373 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1374 SilcCommandStatus status;
1377 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1378 SILC_GET16_MSB(status, tmp);
1379 if (status != SILC_STATUS_OK) {
1380 cmd->client->ops->say(cmd->client, conn,
1381 "%s", silc_client_command_status_message(status));
1382 COMMAND_REPLY_ERROR;
1386 /* Notify application */
1387 COMMAND_REPLY((ARGS));
1389 /* Execute any pending command callbacks */
1390 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1393 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1394 silc_client_command_reply_free(cmd);
1397 SILC_CLIENT_CMD_REPLY_FUNC(close)
1399 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1400 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1401 SilcCommandStatus status;
1404 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1405 SILC_GET16_MSB(status, tmp);
1406 if (status != SILC_STATUS_OK) {
1407 cmd->client->ops->say(cmd->client, conn,
1408 "%s", silc_client_command_status_message(status));
1409 COMMAND_REPLY_ERROR;
1413 /* Notify application */
1414 COMMAND_REPLY((ARGS));
1416 /* Execute any pending command callbacks */
1417 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1420 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1421 silc_client_command_reply_free(cmd);
1424 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1426 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1427 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1428 SilcCommandStatus status;
1431 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1432 SILC_GET16_MSB(status, tmp);
1433 if (status != SILC_STATUS_OK) {
1434 cmd->client->ops->say(cmd->client, conn,
1435 "%s", silc_client_command_status_message(status));
1436 COMMAND_REPLY_ERROR;
1440 /* Notify application */
1441 COMMAND_REPLY((ARGS));
1443 /* Execute any pending command callbacks */
1444 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1447 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1448 silc_client_command_reply_free(cmd);
1451 /* Reply to LEAVE command. */
1453 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1455 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1456 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1457 SilcCommandStatus status;
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 /* Notify application */
1470 COMMAND_REPLY((ARGS));
1472 /* Execute any pending command callbacks */
1473 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1476 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1477 silc_client_command_reply_free(cmd);
1480 /* Reply to USERS command. Received list of client ID's and theirs modes
1481 on the channel we requested. */
1483 SILC_CLIENT_CMD_REPLY_FUNC(users)
1485 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1486 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1487 SilcCommandStatus status;
1488 SilcIDCacheEntry id_cache = NULL;
1489 SilcChannelEntry channel;
1490 SilcChannelUser chu;
1491 SilcChannelID *channel_id = NULL;
1492 SilcBuffer client_id_list;
1493 SilcBuffer client_mode_list;
1495 unsigned int tmp_len, list_count;
1497 unsigned char **res_argv = NULL;
1498 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1500 SILC_LOG_DEBUG(("Start"));
1502 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1503 SILC_GET16_MSB(status, tmp);
1504 if (status != SILC_STATUS_OK) {
1505 cmd->client->ops->say(cmd->client, conn,
1506 "%s", silc_client_command_status_message(status));
1507 COMMAND_REPLY_ERROR;
1511 /* Get channel ID */
1512 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1515 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1519 /* Get the list count */
1520 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1523 SILC_GET32_MSB(list_count, tmp);
1525 /* Get Client ID list */
1526 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1530 client_id_list = silc_buffer_alloc(tmp_len);
1531 silc_buffer_pull_tail(client_id_list, tmp_len);
1532 silc_buffer_put(client_id_list, tmp, tmp_len);
1534 /* Get client mode list */
1535 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1539 client_mode_list = silc_buffer_alloc(tmp_len);
1540 silc_buffer_pull_tail(client_mode_list, tmp_len);
1541 silc_buffer_put(client_mode_list, tmp, tmp_len);
1543 /* Get channel entry */
1544 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1545 SILC_ID_CHANNEL, &id_cache)) {
1546 COMMAND_REPLY_ERROR;
1549 channel = (SilcChannelEntry)id_cache->context;
1551 /* Remove old client list from channel. */
1552 silc_list_start(channel->clients);
1553 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1554 silc_list_del(channel->clients, chu);
1558 /* Cache the received Client ID's and modes. This cache expires
1559 whenever server sends notify message to channel. It means two things;
1560 some user has joined or leaved the channel. XXX! */
1561 for (i = 0; i < list_count; i++) {
1562 unsigned short idp_len;
1564 SilcClientID *client_id;
1565 SilcClientEntry client;
1568 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1570 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1575 SILC_GET32_MSB(mode, client_mode_list->data);
1577 /* Check if we have this client cached already. */
1578 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1579 SILC_ID_CLIENT, &id_cache)) {
1580 /* No we don't have it, query it from the server. Assemble argument
1581 table that will be sent fr the IDENTIFY command later. */
1582 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1584 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1586 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1588 res_argv[res_argc] = client_id_list->data;
1589 res_argv_lens[res_argc] = idp_len;
1590 res_argv_types[res_argc] = res_argc + 3;
1593 /* Found the client, join it to the channel */
1594 client = (SilcClientEntry)id_cache->context;
1595 chu = silc_calloc(1, sizeof(*chu));
1596 chu->client = client;
1598 silc_list_add(channel->clients, chu);
1600 silc_free(client_id);
1604 silc_buffer_pull(client_id_list, idp_len);
1605 silc_buffer_pull(client_mode_list, 4);
1608 /* Query the client information from server if the list included clients
1609 that we don't know about. */
1613 /* Send the IDENTIFY command to server */
1614 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1615 res_argc, res_argv, res_argv_lens,
1616 res_argv_types, ++conn->cmd_ident);
1617 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1618 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1621 /* Register pending command callback. After we've received the IDENTIFY
1622 command reply we will reprocess this command reply by re-calling this
1623 USERS command reply callback. */
1624 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1625 NULL, silc_client_command_reply_users, cmd);
1627 silc_buffer_free(res_cmd);
1629 silc_free(channel_id);
1631 silc_free(res_argv);
1632 silc_free(res_argv_lens);
1633 silc_free(res_argv_types);
1637 /* Notify application */
1638 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1640 /* Execute any pending command callbacks */
1641 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1643 silc_buffer_free(client_id_list);
1644 silc_buffer_free(client_mode_list);
1648 silc_free(channel_id);
1649 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1650 silc_client_command_reply_free(cmd);
1653 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1655 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1656 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1657 SilcCommandStatus status;
1658 SilcIDCacheEntry id_cache = NULL;
1659 SilcChannelEntry channel;
1660 SilcChannelID *channel_id;
1664 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1665 SILC_GET16_MSB(status, tmp);
1666 if (status != SILC_STATUS_OK) {
1667 cmd->client->ops->say(cmd->client, conn,
1668 "%s", silc_client_command_status_message(status));
1669 COMMAND_REPLY_ERROR;
1673 /* Take Channel ID */
1674 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1678 channel_id = silc_id_payload_parse_id(tmp, len);
1682 /* Get the channel entry */
1683 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1684 SILC_ID_CHANNEL, &id_cache)) {
1685 silc_free(channel_id);
1686 COMMAND_REPLY_ERROR;
1690 channel = (SilcChannelEntry)id_cache->context;
1692 /* Get the ban list */
1693 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1695 /* Notify application */
1696 COMMAND_REPLY((ARGS, channel, tmp));
1698 /* Execute any pending command callbacks */
1699 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1702 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1703 silc_client_command_reply_free(cmd);