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 = NULL, 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 keyp = silc_buffer_alloc(len);
974 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
975 silc_buffer_put(keyp, tmp, len);
979 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
981 /* Save received Channel ID. This actually creates the channel */
982 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
984 silc_id_payload_free(idp);
987 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
989 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
990 cmd->client->ops->say(cmd->client, conn,
991 "Cannot join channel: Unsupported HMAC `%s'",
994 silc_free(channel_name);
999 /* Get the list count */
1000 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1003 SILC_GET32_MSB(list_count, tmp);
1005 /* Get Client ID list */
1006 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1010 client_id_list = silc_buffer_alloc(len);
1011 silc_buffer_pull_tail(client_id_list, len);
1012 silc_buffer_put(client_id_list, tmp, len);
1014 /* Get client mode list */
1015 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1019 client_mode_list = silc_buffer_alloc(len);
1020 silc_buffer_pull_tail(client_mode_list, len);
1021 silc_buffer_put(client_mode_list, tmp, len);
1023 /* Add clients we received in the reply to the channel */
1024 for (i = 0; i < list_count; i++) {
1025 unsigned short idp_len;
1027 SilcClientID *client_id;
1028 SilcClientEntry client_entry;
1031 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1033 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1038 SILC_GET32_MSB(mode, client_mode_list->data);
1040 /* Check if we have this client cached already. */
1041 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1042 SILC_ID_CLIENT, &id_cache)) {
1043 /* No, we don't have it, add entry for it. */
1044 client_entry = silc_calloc(1, sizeof(*client_entry));
1045 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1046 silc_idcache_add(conn->client_cache, NULL, 0, SILC_ID_CLIENT,
1047 client_entry->id, (void *)client_entry, FALSE, FALSE);
1049 /* Yes, we have it already */
1050 client_entry = (SilcClientEntry)id_cache->context;
1053 /* Join the client to the channel */
1054 chu = silc_calloc(1, sizeof(*chu));
1055 chu->client = client_entry;
1057 silc_list_add(channel->clients, chu);
1058 silc_free(client_id);
1060 silc_buffer_pull(client_id_list, idp_len);
1061 silc_buffer_pull(client_mode_list, 4);
1063 silc_buffer_push(client_id_list, client_id_list->data -
1064 client_id_list->head);
1065 silc_buffer_push(client_mode_list, client_mode_list->data -
1066 client_mode_list->head);
1068 /* Save channel key */
1069 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1070 silc_client_save_channel_key(conn, keyp, channel);
1072 /* Client is now joined to the channel */
1073 channel->on_channel = TRUE;
1075 /* Notify application */
1076 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1077 keyp ? keyp->head : NULL, NULL,
1078 NULL, topic, hmac, list_count, client_id_list,
1081 /* Execute any pending command callbacks */
1082 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1085 silc_buffer_free(keyp);
1086 silc_buffer_free(client_id_list);
1087 silc_buffer_free(client_mode_list);
1090 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1091 silc_client_command_reply_free(cmd);
1094 /* Received reply for MOTD command */
1096 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1098 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1099 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1100 SilcCommandStatus status;
1101 unsigned int argc, i;
1103 char *motd = NULL, *cp, line[256];
1105 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1106 SILC_GET16_MSB(status, tmp);
1107 if (status != SILC_STATUS_OK) {
1108 cmd->client->ops->say(cmd->client, conn,
1109 "%s", silc_client_command_status_message(status));
1110 COMMAND_REPLY_ERROR;
1114 argc = silc_argument_get_arg_num(cmd->args);
1116 COMMAND_REPLY_ERROR;
1121 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1123 COMMAND_REPLY_ERROR;
1130 if (cp[i++] == '\n') {
1131 memset(line, 0, sizeof(line));
1132 strncat(line, cp, i - 1);
1138 cmd->client->ops->say(cmd->client, conn, "%s", line);
1147 /* Notify application */
1148 COMMAND_REPLY((ARGS, motd));
1150 /* Execute any pending command callbacks */
1151 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1154 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1155 silc_client_command_reply_free(cmd);
1158 /* Received reply tot he UMODE command. Save the current user mode */
1160 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1162 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1163 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1164 SilcCommandStatus status;
1168 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1169 SILC_GET16_MSB(status, tmp);
1170 if (status != SILC_STATUS_OK) {
1171 cmd->client->ops->say(cmd->client, conn,
1172 "%s", silc_client_command_status_message(status));
1173 COMMAND_REPLY_ERROR;
1177 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1179 COMMAND_REPLY_ERROR;
1183 SILC_GET32_MSB(mode, tmp);
1184 conn->local_entry->mode = mode;
1186 /* Notify application */
1187 COMMAND_REPLY((ARGS, mode));
1189 /* Execute any pending command callbacks */
1190 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1193 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1194 silc_client_command_reply_free(cmd);
1197 /* Received reply for CMODE command. */
1199 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1201 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1202 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1203 SilcCommandStatus status;
1206 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1207 if (status != SILC_STATUS_OK) {
1208 cmd->client->ops->say(cmd->client, conn,
1209 "%s", silc_client_command_status_message(status));
1210 COMMAND_REPLY_ERROR;
1214 /* Get channel mode */
1215 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1217 COMMAND_REPLY_ERROR;
1221 /* Notify application */
1222 COMMAND_REPLY((ARGS, tmp));
1224 /* Execute any pending command callbacks */
1225 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1228 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1229 silc_client_command_reply_free(cmd);
1232 /* Received reply for CUMODE command */
1234 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1236 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1237 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1238 SilcCommandStatus status;
1239 SilcIDCacheEntry id_cache = NULL;
1240 SilcClientID *client_id;
1241 unsigned char *tmp, *id;
1244 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1245 if (status != SILC_STATUS_OK) {
1246 cmd->client->ops->say(cmd->client, conn,
1247 "%s", silc_client_command_status_message(status));
1248 COMMAND_REPLY_ERROR;
1252 /* Get channel mode */
1253 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1255 COMMAND_REPLY_ERROR;
1260 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1262 COMMAND_REPLY_ERROR;
1265 client_id = silc_id_payload_parse_id(id, len);
1267 COMMAND_REPLY_ERROR;
1271 /* Get client entry */
1272 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1273 SILC_ID_CLIENT, &id_cache)) {
1274 COMMAND_REPLY_ERROR;
1278 /* Notify application */
1279 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1280 silc_free(client_id);
1282 /* Execute any pending command callbacks */
1283 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1286 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1287 silc_client_command_reply_free(cmd);
1290 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1292 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1293 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1294 SilcCommandStatus status;
1297 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1298 SILC_GET16_MSB(status, tmp);
1299 if (status != SILC_STATUS_OK) {
1300 cmd->client->ops->say(cmd->client, conn,
1301 "%s", silc_client_command_status_message(status));
1302 COMMAND_REPLY_ERROR;
1306 /* Notify application */
1307 COMMAND_REPLY((ARGS));
1309 /* Execute any pending command callbacks */
1310 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1313 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1314 silc_client_command_reply_free(cmd);
1317 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1319 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1320 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1321 SilcCommandStatus status;
1324 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1325 SILC_GET16_MSB(status, tmp);
1326 if (status != SILC_STATUS_OK) {
1327 cmd->client->ops->say(cmd->client, conn,
1328 "%s", silc_client_command_status_message(status));
1329 COMMAND_REPLY_ERROR;
1333 /* Notify application */
1334 COMMAND_REPLY((ARGS));
1336 /* Execute any pending command callbacks */
1337 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1340 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1341 silc_client_command_reply_free(cmd);
1344 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1346 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1347 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1348 SilcCommandStatus status;
1351 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1352 SILC_GET16_MSB(status, tmp);
1353 if (status != SILC_STATUS_OK) {
1354 cmd->client->ops->say(cmd->client, conn,
1355 "%s", silc_client_command_status_message(status));
1356 COMMAND_REPLY_ERROR;
1360 /* Notify application */
1361 COMMAND_REPLY((ARGS));
1363 /* Execute any pending command callbacks */
1364 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1367 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1368 silc_client_command_reply_free(cmd);
1371 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1373 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1374 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1375 SilcCommandStatus status;
1378 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1379 SILC_GET16_MSB(status, tmp);
1380 if (status != SILC_STATUS_OK) {
1381 cmd->client->ops->say(cmd->client, conn,
1382 "%s", silc_client_command_status_message(status));
1383 COMMAND_REPLY_ERROR;
1387 /* Notify application */
1388 COMMAND_REPLY((ARGS));
1390 /* Execute any pending command callbacks */
1391 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1394 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1395 silc_client_command_reply_free(cmd);
1398 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1400 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1401 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1402 SilcCommandStatus status;
1405 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1406 SILC_GET16_MSB(status, tmp);
1407 if (status != SILC_STATUS_OK) {
1408 cmd->client->ops->say(cmd->client, conn,
1409 "%s", silc_client_command_status_message(status));
1410 COMMAND_REPLY_ERROR;
1414 /* Notify application */
1415 COMMAND_REPLY((ARGS));
1417 /* Execute any pending command callbacks */
1418 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1421 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1422 silc_client_command_reply_free(cmd);
1425 SILC_CLIENT_CMD_REPLY_FUNC(close)
1427 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1428 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1429 SilcCommandStatus status;
1432 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1433 SILC_GET16_MSB(status, tmp);
1434 if (status != SILC_STATUS_OK) {
1435 cmd->client->ops->say(cmd->client, conn,
1436 "%s", silc_client_command_status_message(status));
1437 COMMAND_REPLY_ERROR;
1441 /* Notify application */
1442 COMMAND_REPLY((ARGS));
1444 /* Execute any pending command callbacks */
1445 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1448 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1449 silc_client_command_reply_free(cmd);
1452 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1454 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1455 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1456 SilcCommandStatus status;
1459 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1460 SILC_GET16_MSB(status, tmp);
1461 if (status != SILC_STATUS_OK) {
1462 cmd->client->ops->say(cmd->client, conn,
1463 "%s", silc_client_command_status_message(status));
1464 COMMAND_REPLY_ERROR;
1468 /* Notify application */
1469 COMMAND_REPLY((ARGS));
1471 /* Execute any pending command callbacks */
1472 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1475 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1476 silc_client_command_reply_free(cmd);
1479 /* Reply to LEAVE command. */
1481 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1483 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1484 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1485 SilcCommandStatus status;
1488 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1489 SILC_GET16_MSB(status, tmp);
1490 if (status != SILC_STATUS_OK) {
1491 cmd->client->ops->say(cmd->client, conn,
1492 "%s", silc_client_command_status_message(status));
1493 COMMAND_REPLY_ERROR;
1497 /* Notify application */
1498 COMMAND_REPLY((ARGS));
1500 /* Execute any pending command callbacks */
1501 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1504 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1505 silc_client_command_reply_free(cmd);
1508 /* Reply to USERS command. Received list of client ID's and theirs modes
1509 on the channel we requested. */
1511 SILC_CLIENT_CMD_REPLY_FUNC(users)
1513 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1514 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1515 SilcCommandStatus status;
1516 SilcIDCacheEntry id_cache = NULL;
1517 SilcChannelEntry channel;
1518 SilcChannelUser chu;
1519 SilcChannelID *channel_id = NULL;
1520 SilcBuffer client_id_list;
1521 SilcBuffer client_mode_list;
1523 unsigned int tmp_len, list_count;
1525 unsigned char **res_argv = NULL;
1526 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1528 SILC_LOG_DEBUG(("Start"));
1530 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1531 SILC_GET16_MSB(status, tmp);
1532 if (status != SILC_STATUS_OK) {
1533 cmd->client->ops->say(cmd->client, conn,
1534 "%s", silc_client_command_status_message(status));
1535 COMMAND_REPLY_ERROR;
1539 /* Get channel ID */
1540 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1543 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1547 /* Get the list count */
1548 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1551 SILC_GET32_MSB(list_count, tmp);
1553 /* Get Client ID list */
1554 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1558 client_id_list = silc_buffer_alloc(tmp_len);
1559 silc_buffer_pull_tail(client_id_list, tmp_len);
1560 silc_buffer_put(client_id_list, tmp, tmp_len);
1562 /* Get client mode list */
1563 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1567 client_mode_list = silc_buffer_alloc(tmp_len);
1568 silc_buffer_pull_tail(client_mode_list, tmp_len);
1569 silc_buffer_put(client_mode_list, tmp, tmp_len);
1571 /* Get channel entry */
1572 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1573 SILC_ID_CHANNEL, &id_cache)) {
1574 COMMAND_REPLY_ERROR;
1577 channel = (SilcChannelEntry)id_cache->context;
1579 /* Remove old client list from channel. */
1580 silc_list_start(channel->clients);
1581 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1582 silc_list_del(channel->clients, chu);
1586 /* Cache the received Client ID's and modes. This cache expires
1587 whenever server sends notify message to channel. It means two things;
1588 some user has joined or leaved the channel. XXX! */
1589 for (i = 0; i < list_count; i++) {
1590 unsigned short idp_len;
1592 SilcClientID *client_id;
1593 SilcClientEntry client;
1596 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1598 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1603 SILC_GET32_MSB(mode, client_mode_list->data);
1605 /* Check if we have this client cached already. */
1606 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1607 SILC_ID_CLIENT, &id_cache)) {
1608 /* No we don't have it, query it from the server. Assemble argument
1609 table that will be sent fr the IDENTIFY command later. */
1610 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1612 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1614 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1616 res_argv[res_argc] = client_id_list->data;
1617 res_argv_lens[res_argc] = idp_len;
1618 res_argv_types[res_argc] = res_argc + 3;
1621 /* Found the client, join it to the channel */
1622 client = (SilcClientEntry)id_cache->context;
1623 chu = silc_calloc(1, sizeof(*chu));
1624 chu->client = client;
1626 silc_list_add(channel->clients, chu);
1628 silc_free(client_id);
1632 silc_buffer_pull(client_id_list, idp_len);
1633 silc_buffer_pull(client_mode_list, 4);
1636 /* Query the client information from server if the list included clients
1637 that we don't know about. */
1641 /* Send the IDENTIFY command to server */
1642 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1643 res_argc, res_argv, res_argv_lens,
1644 res_argv_types, ++conn->cmd_ident);
1645 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1646 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1649 /* Register pending command callback. After we've received the IDENTIFY
1650 command reply we will reprocess this command reply by re-calling this
1651 USERS command reply callback. */
1652 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1653 NULL, silc_client_command_reply_users, cmd);
1655 silc_buffer_free(res_cmd);
1657 silc_free(channel_id);
1659 silc_free(res_argv);
1660 silc_free(res_argv_lens);
1661 silc_free(res_argv_types);
1665 /* Notify application */
1666 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1668 /* Execute any pending command callbacks */
1669 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1671 silc_buffer_free(client_id_list);
1672 silc_buffer_free(client_mode_list);
1676 silc_free(channel_id);
1677 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1678 silc_client_command_reply_free(cmd);
1681 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1683 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1684 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1685 SilcCommandStatus status;
1686 SilcIDCacheEntry id_cache = NULL;
1687 SilcChannelEntry channel;
1688 SilcChannelID *channel_id;
1692 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1693 SILC_GET16_MSB(status, tmp);
1694 if (status != SILC_STATUS_OK) {
1695 cmd->client->ops->say(cmd->client, conn,
1696 "%s", silc_client_command_status_message(status));
1697 COMMAND_REPLY_ERROR;
1701 /* Take Channel ID */
1702 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1706 channel_id = silc_id_payload_parse_id(tmp, len);
1710 /* Get the channel entry */
1711 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1712 SILC_ID_CHANNEL, &id_cache)) {
1713 silc_free(channel_id);
1714 COMMAND_REPLY_ERROR;
1718 channel = (SilcChannelEntry)id_cache->context;
1720 /* Get the ban list */
1721 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1723 /* Notify application */
1724 COMMAND_REPLY((ARGS, channel, tmp));
1726 /* Execute any pending command callbacks */
1727 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1730 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1731 silc_client_command_reply_free(cmd);