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),
66 SILC_CLIENT_CMD_REPLY(ban, BAN),
71 const SilcCommandStatusMessage silc_command_status_messages[] = {
73 { STAT(NO_SUCH_NICK), "There was no such nickname" },
74 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
75 { STAT(NO_SUCH_SERVER), "No such server" },
76 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
77 { STAT(NO_RECIPIENT), "No recipient given" },
78 { STAT(UNKNOWN_COMMAND), "Unknown command" },
79 { STAT(WILDCARDS), "Unknown command" },
80 { STAT(NO_CLIENT_ID), "No Client ID given" },
81 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
82 { STAT(NO_SERVER_ID), "No Server ID given" },
83 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
84 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
85 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
86 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
87 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
88 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
89 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
90 { STAT(USER_ON_CHANNEL), "User already on the channel" },
91 { STAT(NOT_REGISTERED), "You have not registered" },
92 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
93 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
94 { STAT(PERM_DENIED), "Permission denied" },
95 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
96 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
97 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
98 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
99 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
100 { STAT(UNKNOWN_MODE), "Unknown mode" },
101 { STAT(NOT_YOU), "Cannot change mode for other users" },
102 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
103 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
104 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
105 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
106 { STAT(BAD_NICKNAME), "Bad nickname" },
107 { STAT(BAD_CHANNEL), "Bad channel name" },
108 { STAT(AUTH_FAILED), "Authentication failed" },
109 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
113 /* Command reply operation that is called at the end of all command replys.
114 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
115 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
116 #define ARGS cmd->client, cmd->sock->user_data, \
117 cmd->payload, TRUE, silc_command_get(cmd->payload), status
119 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
120 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
121 cmd->sock->user_data, cmd->payload, FALSE, \
122 silc_command_get(cmd->payload), status)
124 /* Process received command reply. */
126 void silc_client_command_reply_process(SilcClient client,
127 SilcSocketConnection sock,
128 SilcPacketContext *packet)
130 SilcBuffer buffer = packet->buffer;
131 SilcClientCommandReply *cmd;
132 SilcClientCommandReplyContext ctx;
133 SilcCommandPayload payload;
135 unsigned short ident;
137 /* Get command reply payload from packet */
138 payload = silc_command_payload_parse(buffer);
140 /* Silently ignore bad reply packet */
141 SILC_LOG_DEBUG(("Bad command reply packet"));
145 /* Allocate command reply context. This must be free'd by the
146 command reply routine receiving it. */
147 ctx = silc_calloc(1, sizeof(*ctx));
148 ctx->client = client;
150 ctx->payload = payload;
151 ctx->args = silc_command_get_args(ctx->payload);
152 ctx->packet = packet;
153 ident = silc_command_get_ident(ctx->payload);
155 /* Check for pending commands and mark to be exeucted */
156 silc_client_command_pending_check(sock->user_data, ctx,
157 silc_command_get(ctx->payload), ident);
159 /* Execute command reply */
160 command = silc_command_get(ctx->payload);
161 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
162 if (cmd->cmd == command)
165 if (cmd == NULL || !cmd->cb) {
173 /* Returns status message string */
175 char *silc_client_command_status_message(SilcCommandStatus status)
179 for (i = 0; silc_command_status_messages[i].message; i++) {
180 if (silc_command_status_messages[i].status == status)
184 if (silc_command_status_messages[i].message == NULL)
187 return silc_command_status_messages[i].message;
190 /* Free command reply context and its internals. */
192 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
195 silc_command_free_payload(cmd->payload);
201 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
202 SilcCommandStatus status)
204 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
205 SilcClientID *client_id;
206 SilcIDCacheEntry id_cache = NULL;
207 SilcClientEntry client_entry = NULL;
209 unsigned char *id_data, *tmp;
210 char *nickname = NULL, *username = NULL;
211 char *realname = NULL;
212 unsigned int idle = 0, mode = 0;
213 SilcBuffer channels = NULL;
215 argc = silc_argument_get_arg_num(cmd->args);
217 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
223 client_id = silc_id_payload_parse_id(id_data, len);
229 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
230 username = silc_argument_get_arg_type(cmd->args, 4, &len);
231 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
232 if (!nickname || !username || !realname) {
237 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
239 channels = silc_buffer_alloc(len);
240 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
241 silc_buffer_put(channels, tmp, len);
244 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
246 SILC_GET32_MSB(mode, tmp);
248 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
250 SILC_GET32_MSB(idle, tmp);
252 /* Check if we have this client cached already. */
253 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
254 SILC_ID_CLIENT, &id_cache)) {
255 SILC_LOG_DEBUG(("Adding new client entry"));
257 client_entry = silc_calloc(1, sizeof(*client_entry));
258 client_entry->id = client_id;
259 silc_parse_nickname(nickname, &client_entry->nickname,
260 &client_entry->server, &client_entry->num);
261 client_entry->username = strdup(username);
263 client_entry->realname = strdup(realname);
264 client_entry->mode = mode;
266 /* Add client to cache */
267 silc_idcache_add(conn->client_cache, client_entry->nickname,
268 strlen(client_entry->nickname),
269 SILC_ID_CLIENT, client_id, (void *)client_entry,
272 client_entry = (SilcClientEntry)id_cache->context;
273 if (client_entry->nickname)
274 silc_free(client_entry->nickname);
275 if (client_entry->server)
276 silc_free(client_entry->server);
277 if (client_entry->username)
278 silc_free(client_entry->username);
279 if (client_entry->realname)
280 silc_free(client_entry->realname);
281 client_entry->mode = mode;
283 SILC_LOG_DEBUG(("Updating client entry"));
285 silc_parse_nickname(nickname, &client_entry->nickname,
286 &client_entry->server, &client_entry->num);
287 client_entry->username = strdup(username);
289 client_entry->realname = strdup(realname);
291 id_cache->data = client_entry->nickname;
292 id_cache->data_len = strlen(client_entry->nickname);
293 silc_idcache_sort_by_data(conn->client_cache);
295 silc_free(client_id);
298 /* Notify application */
300 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
301 channels, mode, idle));
304 silc_buffer_free(channels);
307 /* Received reply for WHOIS command. This maybe called several times
308 for one WHOIS command as server may reply with list of results. */
310 SILC_CLIENT_CMD_REPLY_FUNC(whois)
312 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
313 SilcCommandStatus status;
316 SILC_LOG_DEBUG(("Start"));
318 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
319 SILC_GET16_MSB(status, tmp);
320 if (status != SILC_STATUS_OK &&
321 status != SILC_STATUS_LIST_START &&
322 status != SILC_STATUS_LIST_ITEM &&
323 status != SILC_STATUS_LIST_END) {
328 /* Display one whois reply */
329 if (status == SILC_STATUS_OK)
330 silc_client_command_reply_whois_save(cmd, status);
333 if (status == SILC_STATUS_LIST_START ||
334 status == SILC_STATUS_LIST_ITEM ||
335 status == SILC_STATUS_LIST_END)
336 silc_client_command_reply_whois_save(cmd, status);
338 /* Pending callbacks are not executed if this was an list entry */
339 if (status != SILC_STATUS_OK &&
340 status != SILC_STATUS_LIST_END) {
341 silc_client_command_reply_free(cmd);
345 /* Execute any pending command callbacks */
346 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
349 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
350 silc_client_command_reply_free(cmd);
353 /* Received reply for WHOWAS command. */
355 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
357 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
358 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
359 SilcCommandStatus status;
360 SilcClientID *client_id;
361 SilcIDCacheEntry id_cache = NULL;
362 SilcClientEntry client_entry = NULL;
364 unsigned char *id_data, *tmp;
365 char *nickname, *username;
366 char *realname = NULL;
368 SILC_LOG_DEBUG(("Start"));
370 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
371 SILC_GET16_MSB(status, tmp);
372 if (status != SILC_STATUS_OK &&
373 status != SILC_STATUS_LIST_START &&
374 status != SILC_STATUS_LIST_ITEM &&
375 status != SILC_STATUS_LIST_END) {
380 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
386 client_id = silc_id_payload_parse_id(id_data, len);
392 /* Get the client entry, if exists */
393 if (silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
394 SILC_ID_CLIENT, &id_cache))
395 client_entry = (SilcClientEntry)id_cache->context;
396 silc_free(client_id);
398 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
399 username = silc_argument_get_arg_type(cmd->args, 4, &len);
400 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
401 if (!nickname || !username) {
405 /* Notify application. We don't save any history information to any
406 cache. Just pass the data to the application for displaying on
408 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
410 /* Pending callbacks are not executed if this was an list entry */
411 if (status != SILC_STATUS_OK &&
412 status != SILC_STATUS_LIST_END) {
413 silc_client_command_reply_free(cmd);
417 /* Execute any pending command callbacks */
418 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
421 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
422 silc_client_command_reply_free(cmd);
426 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
427 SilcCommandStatus status)
429 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
430 SilcClientID *client_id;
431 SilcIDCacheEntry id_cache = NULL;
432 SilcClientEntry client_entry = NULL;
434 unsigned char *id_data;
435 char *nickname = NULL, *username = NULL;
437 argc = silc_argument_get_arg_num(cmd->args);
439 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
445 client_id = silc_id_payload_parse_id(id_data, len);
451 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
452 username = silc_argument_get_arg_type(cmd->args, 4, &len);
454 /* Check if we have this client cached already. */
455 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
456 SILC_ID_CLIENT, &id_cache)) {
457 SILC_LOG_DEBUG(("Adding new client entry"));
459 client_entry = silc_calloc(1, sizeof(*client_entry));
460 client_entry->id = client_id;
461 silc_parse_nickname(nickname, &client_entry->nickname,
462 &client_entry->server, &client_entry->num);
464 client_entry->username = strdup(username);
466 /* Add client to cache */
467 silc_idcache_add(conn->client_cache, client_entry->nickname,
468 strlen(client_entry->nickname),
469 SILC_ID_CLIENT, client_id, (void *)client_entry,
472 client_entry = (SilcClientEntry)id_cache->context;
473 if (client_entry->nickname)
474 silc_free(client_entry->nickname);
475 if (client_entry->server)
476 silc_free(client_entry->server);
477 if (username && client_entry->username)
478 silc_free(client_entry->username);
480 SILC_LOG_DEBUG(("Updating client entry"));
482 silc_parse_nickname(nickname, &client_entry->nickname,
483 &client_entry->server, &client_entry->num);
486 client_entry->username = strdup(username);
488 id_cache->data = client_entry->nickname;
489 id_cache->data_len = strlen(client_entry->nickname);
490 silc_idcache_sort_by_data(conn->client_cache);
492 silc_free(client_id);
495 /* Notify application */
496 COMMAND_REPLY((ARGS, client_entry, nickname, username));
499 /* Received reply for IDENTIFY command. This maybe called several times
500 for one IDENTIFY command as server may reply with list of results.
501 This is totally silent and does not print anything on screen. */
503 SILC_CLIENT_CMD_REPLY_FUNC(identify)
505 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
506 SilcCommandStatus status;
509 SILC_LOG_DEBUG(("Start"));
511 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
512 SILC_GET16_MSB(status, tmp);
513 if (status != SILC_STATUS_OK &&
514 status != SILC_STATUS_LIST_START &&
515 status != SILC_STATUS_LIST_ITEM &&
516 status != SILC_STATUS_LIST_END) {
521 /* Save one IDENTIFY entry */
522 if (status == SILC_STATUS_OK)
523 silc_client_command_reply_identify_save(cmd, status);
526 if (status == SILC_STATUS_LIST_START ||
527 status == SILC_STATUS_LIST_ITEM ||
528 status == SILC_STATUS_LIST_END)
529 silc_client_command_reply_identify_save(cmd, status);
531 /* Pending callbacks are not executed if this was an list entry */
532 if (status != SILC_STATUS_OK &&
533 status != SILC_STATUS_LIST_END) {
534 silc_client_command_reply_free(cmd);
538 /* Execute any pending command callbacks */
539 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
542 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
543 silc_client_command_reply_free(cmd);
546 /* Received reply for command NICK. If everything went without errors
547 we just received our new Client ID. */
549 SILC_CLIENT_CMD_REPLY_FUNC(nick)
551 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
552 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
553 SilcCommandStatus status;
556 unsigned int argc, len;
558 SILC_LOG_DEBUG(("Start"));
560 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
561 if (status != SILC_STATUS_OK) {
562 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
563 silc_client_command_status_message(status));
568 argc = silc_argument_get_arg_num(cmd->args);
569 if (argc < 2 || argc > 2) {
570 cmd->client->ops->say(cmd->client, conn,
571 "Cannot set nickname: bad reply to command");
576 /* Take received Client ID */
577 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
578 idp = silc_id_payload_parse_data(tmp, len);
583 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
585 /* Notify application */
586 COMMAND_REPLY((ARGS, conn->local_entry));
588 /* Execute any pending command callbacks */
589 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
592 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
593 silc_client_command_reply_free(cmd);
596 /* Received reply to the LIST command. */
598 SILC_CLIENT_CMD_REPLY_FUNC(list)
600 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
601 SilcCommandStatus status;
602 unsigned char *tmp, *name, *topic;
603 unsigned int usercount = 0;
605 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
606 SILC_GET16_MSB(status, tmp);
607 if (status != SILC_STATUS_OK &&
608 status != SILC_STATUS_LIST_START &&
609 status != SILC_STATUS_LIST_ITEM &&
610 status != SILC_STATUS_LIST_END) {
615 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
616 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
617 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
619 SILC_GET32_MSB(usercount, tmp);
621 /* Notify application */
622 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
624 /* Pending callbacks are not executed if this was an list entry */
625 if (status != SILC_STATUS_OK &&
626 status != SILC_STATUS_LIST_END) {
627 silc_client_command_reply_free(cmd);
631 /* Execute any pending command callbacks */
632 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
635 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
636 silc_client_command_reply_free(cmd);
639 /* Received reply to topic command. */
641 SILC_CLIENT_CMD_REPLY_FUNC(topic)
643 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
644 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
645 SilcCommandStatus status;
646 SilcChannelEntry channel;
647 SilcChannelID *channel_id = NULL;
648 SilcIDCacheEntry id_cache = NULL;
651 unsigned int argc, len;
653 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
654 if (status != SILC_STATUS_OK) {
655 cmd->client->ops->say(cmd->client, conn,
656 "%s", silc_client_command_status_message(status));
658 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
659 silc_client_command_reply_free(cmd);
663 argc = silc_argument_get_arg_num(cmd->args);
664 if (argc < 1 || argc > 3) {
669 /* Take Channel ID */
670 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
675 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
679 channel_id = silc_id_payload_parse_id(tmp, len);
683 /* Get the channel entry */
684 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
685 SILC_ID_CHANNEL, &id_cache)) {
686 silc_free(channel_id);
691 channel = (SilcChannelEntry)id_cache->context;
693 cmd->client->ops->say(cmd->client, conn,
694 "Topic on channel %s: %s", channel->channel_name,
697 /* Notify application */
698 COMMAND_REPLY((ARGS, channel, topic));
700 /* Execute any pending command callbacks */
701 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
704 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
705 silc_client_command_reply_free(cmd);
708 /* Received reply to invite command. */
710 SILC_CLIENT_CMD_REPLY_FUNC(invite)
712 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
713 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
714 SilcCommandStatus status;
715 SilcChannelEntry channel;
716 SilcChannelID *channel_id;
717 SilcIDCacheEntry id_cache;
721 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
722 SILC_GET16_MSB(status, tmp);
723 if (status != SILC_STATUS_OK) {
724 cmd->client->ops->say(cmd->client, conn,
725 "%s", silc_client_command_status_message(status));
727 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
728 silc_client_command_reply_free(cmd);
732 /* Take Channel ID */
733 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
737 channel_id = silc_id_payload_parse_id(tmp, len);
741 /* Get the channel entry */
742 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
743 SILC_ID_CHANNEL, &id_cache)) {
744 silc_free(channel_id);
749 channel = (SilcChannelEntry)id_cache->context;
751 /* Get the invite list */
752 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
754 /* Notify application */
755 COMMAND_REPLY((ARGS, channel, tmp));
757 /* Execute any pending command callbacks */
758 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
761 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
762 silc_client_command_reply_free(cmd);
765 /* Received reply to the KILL command. */
767 SILC_CLIENT_CMD_REPLY_FUNC(kill)
769 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
770 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
771 SilcCommandStatus status;
774 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
775 SILC_GET16_MSB(status, tmp);
776 if (status != SILC_STATUS_OK) {
777 cmd->client->ops->say(cmd->client, conn,
778 "%s", silc_client_command_status_message(status));
783 /* Notify application */
784 COMMAND_REPLY((ARGS));
786 /* Execute any pending command callbacks */
787 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
790 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
791 silc_client_command_reply_free(cmd);
794 /* Received reply to INFO command. We receive the server ID and some
795 information about the server user requested. */
797 SILC_CLIENT_CMD_REPLY_FUNC(info)
799 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
800 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
801 SilcClient client = cmd->client;
802 SilcCommandStatus status;
805 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
806 SILC_GET16_MSB(status, tmp);
807 if (status != SILC_STATUS_OK) {
808 cmd->client->ops->say(cmd->client, conn,
809 "%s", silc_client_command_status_message(status));
811 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
812 silc_client_command_reply_free(cmd);
817 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
821 /* XXX save server id */
823 /* Get server name */
824 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
828 /* Get server info */
829 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
833 client->ops->say(cmd->client, conn, "Info: %s", tmp);
835 /* Notify application */
836 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
838 /* Execute any pending command callbacks */
839 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
842 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
843 silc_client_command_reply_free(cmd);
846 /* Received reply to PING command. The reply time is shown to user. */
848 SILC_CLIENT_CMD_REPLY_FUNC(ping)
850 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
851 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
852 SilcCommandStatus status;
855 time_t diff, curtime;
857 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
858 if (status != SILC_STATUS_OK) {
859 cmd->client->ops->say(cmd->client, conn,
860 "%s", silc_client_command_status_message(status));
865 curtime = time(NULL);
866 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
867 cmd->packet->src_id_type);
873 for (i = 0; i < conn->ping_count; i++) {
874 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
875 diff = curtime - conn->ping[i].start_time;
876 cmd->client->ops->say(cmd->client, conn,
877 "Ping reply from %s: %d second%s",
878 conn->ping[i].dest_name, diff,
879 diff == 1 ? "" : "s");
881 conn->ping[i].start_time = 0;
882 silc_free(conn->ping[i].dest_id);
883 conn->ping[i].dest_id = NULL;
884 silc_free(conn->ping[i].dest_name);
885 conn->ping[i].dest_name = NULL;
892 /* Notify application */
893 COMMAND_REPLY((ARGS));
895 /* Execute any pending command callbacks */
896 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
899 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
900 silc_client_command_reply_free(cmd);
903 /* Received reply for JOIN command. */
905 SILC_CLIENT_CMD_REPLY_FUNC(join)
907 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
908 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
909 SilcCommandStatus status;
910 SilcIDPayload idp = NULL;
911 SilcChannelEntry channel;
912 SilcIDCacheEntry id_cache = NULL;
914 unsigned int argc, mode, len, list_count;
915 char *topic, *tmp, *channel_name = NULL, *hmac;
916 SilcBuffer keyp, client_id_list, client_mode_list;
919 SILC_LOG_DEBUG(("Start"));
921 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
922 if (status != SILC_STATUS_OK) {
923 cmd->client->ops->say(cmd->client, conn,
924 "%s", silc_client_command_status_message(status));
929 argc = silc_argument_get_arg_num(cmd->args);
930 if (argc < 7 || argc > 14) {
931 cmd->client->ops->say(cmd->client, conn,
932 "Cannot join channel: Bad reply packet");
937 /* Get channel name */
938 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
940 cmd->client->ops->say(cmd->client, conn,
941 "Cannot join channel: Bad reply packet");
945 channel_name = strdup(tmp);
948 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
950 cmd->client->ops->say(cmd->client, conn,
951 "Cannot join channel: Bad reply packet");
953 silc_free(channel_name);
956 idp = silc_id_payload_parse_data(tmp, len);
959 silc_free(channel_name);
963 /* Get channel mode */
964 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
966 SILC_GET32_MSB(mode, tmp);
970 /* Get channel key */
971 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
973 silc_id_payload_free(idp);
974 silc_free(channel_name);
977 keyp = silc_buffer_alloc(len);
978 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
979 silc_buffer_put(keyp, tmp, len);
982 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
984 /* Save received Channel ID. This actually creates the channel */
985 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
987 silc_id_payload_free(idp);
990 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
992 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
993 cmd->client->ops->say(cmd->client, conn,
994 "Cannot join channel: Unsupported HMAC `%s'",
997 silc_free(channel_name);
1002 /* Get the list count */
1003 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1006 SILC_GET32_MSB(list_count, tmp);
1008 /* Get Client ID list */
1009 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1013 client_id_list = silc_buffer_alloc(len);
1014 silc_buffer_pull_tail(client_id_list, len);
1015 silc_buffer_put(client_id_list, tmp, len);
1017 /* Get client mode list */
1018 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1022 client_mode_list = silc_buffer_alloc(len);
1023 silc_buffer_pull_tail(client_mode_list, len);
1024 silc_buffer_put(client_mode_list, tmp, len);
1026 /* Add clients we received in the reply to the channel */
1027 for (i = 0; i < list_count; i++) {
1028 unsigned short idp_len;
1030 SilcClientID *client_id;
1031 SilcClientEntry client_entry;
1034 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1036 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1041 SILC_GET32_MSB(mode, client_mode_list->data);
1043 /* Check if we have this client cached already. */
1044 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1045 SILC_ID_CLIENT, &id_cache)) {
1046 /* No, we don't have it, add entry for it. */
1047 client_entry = silc_calloc(1, sizeof(*client_entry));
1048 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1049 silc_idcache_add(conn->client_cache, NULL, 0, SILC_ID_CLIENT,
1050 client_entry->id, (void *)client_entry, FALSE, FALSE);
1052 /* Yes, we have it already */
1053 client_entry = (SilcClientEntry)id_cache->context;
1056 /* Join the client to the channel */
1057 chu = silc_calloc(1, sizeof(*chu));
1058 chu->client = client_entry;
1060 silc_list_add(channel->clients, chu);
1061 silc_free(client_id);
1063 silc_buffer_pull(client_id_list, idp_len);
1064 silc_buffer_pull(client_mode_list, 4);
1066 silc_buffer_push(client_id_list, client_id_list->data -
1067 client_id_list->head);
1068 silc_buffer_push(client_mode_list, client_mode_list->data -
1069 client_mode_list->head);
1071 /* Save channel key */
1072 silc_client_save_channel_key(conn, keyp, channel);
1074 /* Notify application */
1075 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, keyp->head, NULL,
1076 NULL, topic, hmac, list_count, client_id_list,
1079 /* Execute any pending command callbacks */
1080 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1082 silc_buffer_free(keyp);
1083 silc_buffer_free(client_id_list);
1084 silc_buffer_free(client_mode_list);
1087 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1088 silc_client_command_reply_free(cmd);
1091 /* Received reply for MOTD command */
1093 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1095 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1096 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1097 SilcCommandStatus status;
1098 unsigned int argc, i;
1100 char *motd = NULL, *cp, line[256];
1102 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1103 SILC_GET16_MSB(status, tmp);
1104 if (status != SILC_STATUS_OK) {
1105 cmd->client->ops->say(cmd->client, conn,
1106 "%s", silc_client_command_status_message(status));
1107 COMMAND_REPLY_ERROR;
1111 argc = silc_argument_get_arg_num(cmd->args);
1113 COMMAND_REPLY_ERROR;
1118 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1120 COMMAND_REPLY_ERROR;
1127 if (cp[i++] == '\n') {
1128 memset(line, 0, sizeof(line));
1129 strncat(line, cp, i - 1);
1135 cmd->client->ops->say(cmd->client, conn, "%s", line);
1144 /* Notify application */
1145 COMMAND_REPLY((ARGS, motd));
1147 /* Execute any pending command callbacks */
1148 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1151 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1152 silc_client_command_reply_free(cmd);
1155 /* Received reply tot he UMODE command. Save the current user mode */
1157 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1159 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1160 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1161 SilcCommandStatus status;
1165 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1166 SILC_GET16_MSB(status, tmp);
1167 if (status != SILC_STATUS_OK) {
1168 cmd->client->ops->say(cmd->client, conn,
1169 "%s", silc_client_command_status_message(status));
1170 COMMAND_REPLY_ERROR;
1174 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1176 COMMAND_REPLY_ERROR;
1180 SILC_GET32_MSB(mode, tmp);
1181 conn->local_entry->mode = mode;
1183 /* Notify application */
1184 COMMAND_REPLY((ARGS, mode));
1186 /* Execute any pending command callbacks */
1187 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1190 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1191 silc_client_command_reply_free(cmd);
1194 /* Received reply for CMODE command. */
1196 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1198 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1199 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1200 SilcCommandStatus status;
1203 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1204 if (status != SILC_STATUS_OK) {
1205 cmd->client->ops->say(cmd->client, conn,
1206 "%s", silc_client_command_status_message(status));
1207 COMMAND_REPLY_ERROR;
1211 /* Get channel mode */
1212 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1214 COMMAND_REPLY_ERROR;
1218 /* Notify application */
1219 COMMAND_REPLY((ARGS, tmp));
1221 /* Execute any pending command callbacks */
1222 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1225 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1226 silc_client_command_reply_free(cmd);
1229 /* Received reply for CUMODE command */
1231 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1233 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1234 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1235 SilcCommandStatus status;
1236 SilcIDCacheEntry id_cache = NULL;
1237 SilcClientID *client_id;
1238 unsigned char *tmp, *id;
1241 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1242 if (status != SILC_STATUS_OK) {
1243 cmd->client->ops->say(cmd->client, conn,
1244 "%s", silc_client_command_status_message(status));
1245 COMMAND_REPLY_ERROR;
1249 /* Get channel mode */
1250 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1252 COMMAND_REPLY_ERROR;
1257 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1259 COMMAND_REPLY_ERROR;
1262 client_id = silc_id_payload_parse_id(id, len);
1264 COMMAND_REPLY_ERROR;
1268 /* Get client entry */
1269 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1270 SILC_ID_CLIENT, &id_cache)) {
1271 COMMAND_REPLY_ERROR;
1275 /* Notify application */
1276 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1277 silc_free(client_id);
1279 /* Execute any pending command callbacks */
1280 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1283 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1284 silc_client_command_reply_free(cmd);
1287 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1289 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1290 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1291 SilcCommandStatus status;
1294 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1295 SILC_GET16_MSB(status, tmp);
1296 if (status != SILC_STATUS_OK) {
1297 cmd->client->ops->say(cmd->client, conn,
1298 "%s", silc_client_command_status_message(status));
1299 COMMAND_REPLY_ERROR;
1303 /* Notify application */
1304 COMMAND_REPLY((ARGS));
1306 /* Execute any pending command callbacks */
1307 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1310 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1311 silc_client_command_reply_free(cmd);
1314 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1316 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1317 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1318 SilcCommandStatus status;
1321 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1322 SILC_GET16_MSB(status, tmp);
1323 if (status != SILC_STATUS_OK) {
1324 cmd->client->ops->say(cmd->client, conn,
1325 "%s", silc_client_command_status_message(status));
1326 COMMAND_REPLY_ERROR;
1330 /* Notify application */
1331 COMMAND_REPLY((ARGS));
1333 /* Execute any pending command callbacks */
1334 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1337 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1338 silc_client_command_reply_free(cmd);
1341 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1343 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1344 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1345 SilcCommandStatus status;
1348 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1349 SILC_GET16_MSB(status, tmp);
1350 if (status != SILC_STATUS_OK) {
1351 cmd->client->ops->say(cmd->client, conn,
1352 "%s", silc_client_command_status_message(status));
1353 COMMAND_REPLY_ERROR;
1357 /* Notify application */
1358 COMMAND_REPLY((ARGS));
1360 /* Execute any pending command callbacks */
1361 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1364 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1365 silc_client_command_reply_free(cmd);
1368 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1370 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1371 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1372 SilcCommandStatus status;
1375 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1376 SILC_GET16_MSB(status, tmp);
1377 if (status != SILC_STATUS_OK) {
1378 cmd->client->ops->say(cmd->client, conn,
1379 "%s", silc_client_command_status_message(status));
1380 COMMAND_REPLY_ERROR;
1384 /* Notify application */
1385 COMMAND_REPLY((ARGS));
1387 /* Execute any pending command callbacks */
1388 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1391 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1392 silc_client_command_reply_free(cmd);
1395 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1397 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1398 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1399 SilcCommandStatus status;
1402 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1403 SILC_GET16_MSB(status, tmp);
1404 if (status != SILC_STATUS_OK) {
1405 cmd->client->ops->say(cmd->client, conn,
1406 "%s", silc_client_command_status_message(status));
1407 COMMAND_REPLY_ERROR;
1411 /* Notify application */
1412 COMMAND_REPLY((ARGS));
1414 /* Execute any pending command callbacks */
1415 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1418 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1419 silc_client_command_reply_free(cmd);
1422 SILC_CLIENT_CMD_REPLY_FUNC(close)
1424 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1425 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1426 SilcCommandStatus status;
1429 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1430 SILC_GET16_MSB(status, tmp);
1431 if (status != SILC_STATUS_OK) {
1432 cmd->client->ops->say(cmd->client, conn,
1433 "%s", silc_client_command_status_message(status));
1434 COMMAND_REPLY_ERROR;
1438 /* Notify application */
1439 COMMAND_REPLY((ARGS));
1441 /* Execute any pending command callbacks */
1442 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1445 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1446 silc_client_command_reply_free(cmd);
1449 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1451 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1452 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1453 SilcCommandStatus status;
1456 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1457 SILC_GET16_MSB(status, tmp);
1458 if (status != SILC_STATUS_OK) {
1459 cmd->client->ops->say(cmd->client, conn,
1460 "%s", silc_client_command_status_message(status));
1461 COMMAND_REPLY_ERROR;
1465 /* Notify application */
1466 COMMAND_REPLY((ARGS));
1468 /* Execute any pending command callbacks */
1469 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1472 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1473 silc_client_command_reply_free(cmd);
1476 /* Reply to LEAVE command. */
1478 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1480 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1481 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1482 SilcCommandStatus status;
1485 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1486 SILC_GET16_MSB(status, tmp);
1487 if (status != SILC_STATUS_OK) {
1488 cmd->client->ops->say(cmd->client, conn,
1489 "%s", silc_client_command_status_message(status));
1490 COMMAND_REPLY_ERROR;
1494 /* Notify application */
1495 COMMAND_REPLY((ARGS));
1497 /* Execute any pending command callbacks */
1498 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1501 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1502 silc_client_command_reply_free(cmd);
1505 /* Reply to USERS command. Received list of client ID's and theirs modes
1506 on the channel we requested. */
1508 SILC_CLIENT_CMD_REPLY_FUNC(users)
1510 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1511 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1512 SilcCommandStatus status;
1513 SilcIDCacheEntry id_cache = NULL;
1514 SilcChannelEntry channel;
1515 SilcChannelUser chu;
1516 SilcChannelID *channel_id = NULL;
1517 SilcBuffer client_id_list;
1518 SilcBuffer client_mode_list;
1520 unsigned int tmp_len, list_count;
1522 unsigned char **res_argv = NULL;
1523 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1525 SILC_LOG_DEBUG(("Start"));
1527 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1528 SILC_GET16_MSB(status, tmp);
1529 if (status != SILC_STATUS_OK) {
1530 cmd->client->ops->say(cmd->client, conn,
1531 "%s", silc_client_command_status_message(status));
1532 COMMAND_REPLY_ERROR;
1536 /* Get channel ID */
1537 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1540 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1544 /* Get the list count */
1545 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1548 SILC_GET32_MSB(list_count, tmp);
1550 /* Get Client ID list */
1551 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1555 client_id_list = silc_buffer_alloc(tmp_len);
1556 silc_buffer_pull_tail(client_id_list, tmp_len);
1557 silc_buffer_put(client_id_list, tmp, tmp_len);
1559 /* Get client mode list */
1560 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1564 client_mode_list = silc_buffer_alloc(tmp_len);
1565 silc_buffer_pull_tail(client_mode_list, tmp_len);
1566 silc_buffer_put(client_mode_list, tmp, tmp_len);
1568 /* Get channel entry */
1569 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1570 SILC_ID_CHANNEL, &id_cache)) {
1571 COMMAND_REPLY_ERROR;
1574 channel = (SilcChannelEntry)id_cache->context;
1576 /* Remove old client list from channel. */
1577 silc_list_start(channel->clients);
1578 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1579 silc_list_del(channel->clients, chu);
1583 /* Cache the received Client ID's and modes. This cache expires
1584 whenever server sends notify message to channel. It means two things;
1585 some user has joined or leaved the channel. XXX! */
1586 for (i = 0; i < list_count; i++) {
1587 unsigned short idp_len;
1589 SilcClientID *client_id;
1590 SilcClientEntry client;
1593 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1595 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1600 SILC_GET32_MSB(mode, client_mode_list->data);
1602 /* Check if we have this client cached already. */
1603 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1604 SILC_ID_CLIENT, &id_cache)) {
1605 /* No we don't have it, query it from the server. Assemble argument
1606 table that will be sent fr the IDENTIFY command later. */
1607 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1609 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1611 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1613 res_argv[res_argc] = client_id_list->data;
1614 res_argv_lens[res_argc] = idp_len;
1615 res_argv_types[res_argc] = res_argc + 3;
1618 /* Found the client, join it to the channel */
1619 client = (SilcClientEntry)id_cache->context;
1620 chu = silc_calloc(1, sizeof(*chu));
1621 chu->client = client;
1623 silc_list_add(channel->clients, chu);
1625 silc_free(client_id);
1629 silc_buffer_pull(client_id_list, idp_len);
1630 silc_buffer_pull(client_mode_list, 4);
1633 /* Query the client information from server if the list included clients
1634 that we don't know about. */
1638 /* Send the IDENTIFY command to server */
1639 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1640 res_argc, res_argv, res_argv_lens,
1641 res_argv_types, ++conn->cmd_ident);
1642 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1643 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1646 /* Register pending command callback. After we've received the IDENTIFY
1647 command reply we will reprocess this command reply by re-calling this
1648 USERS command reply callback. */
1649 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1650 NULL, silc_client_command_reply_users, cmd);
1652 silc_buffer_free(res_cmd);
1654 silc_free(channel_id);
1656 silc_free(res_argv);
1657 silc_free(res_argv_lens);
1658 silc_free(res_argv_types);
1662 /* Notify application */
1663 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1665 /* Execute any pending command callbacks */
1666 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1668 silc_buffer_free(client_id_list);
1669 silc_buffer_free(client_mode_list);
1673 silc_free(channel_id);
1674 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1675 silc_client_command_reply_free(cmd);
1678 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1680 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1681 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1682 SilcCommandStatus status;
1683 SilcIDCacheEntry id_cache = NULL;
1684 SilcChannelEntry channel;
1685 SilcChannelID *channel_id;
1689 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1690 SILC_GET16_MSB(status, tmp);
1691 if (status != SILC_STATUS_OK) {
1692 cmd->client->ops->say(cmd->client, conn,
1693 "%s", silc_client_command_status_message(status));
1694 COMMAND_REPLY_ERROR;
1698 /* Take Channel ID */
1699 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1703 channel_id = silc_id_payload_parse_id(tmp, len);
1707 /* Get the channel entry */
1708 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1709 SILC_ID_CHANNEL, &id_cache)) {
1710 silc_free(channel_id);
1711 COMMAND_REPLY_ERROR;
1715 channel = (SilcChannelEntry)id_cache->context;
1717 /* Get the ban list */
1718 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1720 /* Notify application */
1721 COMMAND_REPLY((ARGS, channel, tmp));
1723 /* Execute any pending command callbacks */
1724 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1727 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1728 silc_client_command_reply_free(cmd);