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(ban, BAN),
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(getkey, GETKEY),
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), "There was no such client" },
86 { STAT(NO_SUCH_CHANNEL_ID),"There was no such channel" },
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" },
110 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
114 /* Command reply operation that is called at the end of all command replys.
115 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
116 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
117 #define ARGS cmd->client, cmd->sock->user_data, \
118 cmd->payload, TRUE, silc_command_get(cmd->payload), status
120 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
121 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
122 cmd->sock->user_data, cmd->payload, FALSE, \
123 silc_command_get(cmd->payload), status)
125 /* Process received command reply. */
127 void silc_client_command_reply_process(SilcClient client,
128 SilcSocketConnection sock,
129 SilcPacketContext *packet)
131 SilcBuffer buffer = packet->buffer;
132 SilcClientCommandReply *cmd;
133 SilcClientCommandReplyContext ctx;
134 SilcCommandPayload payload;
138 /* Get command reply payload from packet */
139 payload = silc_command_payload_parse(buffer);
141 /* Silently ignore bad reply packet */
142 SILC_LOG_DEBUG(("Bad command reply packet"));
146 /* Allocate command reply context. This must be free'd by the
147 command reply routine receiving it. */
148 ctx = silc_calloc(1, sizeof(*ctx));
149 ctx->client = client;
151 ctx->payload = payload;
152 ctx->args = silc_command_get_args(ctx->payload);
153 ctx->packet = packet;
154 ident = silc_command_get_ident(ctx->payload);
156 /* Check for pending commands and mark to be exeucted */
157 silc_client_command_pending_check(sock->user_data, ctx,
158 silc_command_get(ctx->payload), ident);
160 /* Execute command reply */
161 command = silc_command_get(ctx->payload);
162 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
163 if (cmd->cmd == command)
166 if (cmd == NULL || !cmd->cb) {
174 /* Returns status message string */
176 char *silc_client_command_status_message(SilcCommandStatus status)
180 for (i = 0; silc_command_status_messages[i].message; i++) {
181 if (silc_command_status_messages[i].status == status)
185 if (silc_command_status_messages[i].message == NULL)
188 return silc_command_status_messages[i].message;
191 /* Free command reply context and its internals. */
193 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
196 silc_command_payload_free(cmd->payload);
202 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
203 SilcCommandStatus status)
205 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
206 SilcClientID *client_id;
207 SilcIDCacheEntry id_cache = NULL;
208 SilcClientEntry client_entry = NULL;
211 unsigned char *id_data, *tmp;
212 char *nickname = NULL, *username = NULL;
213 char *realname = NULL;
214 uint32 idle = 0, mode = 0;
215 SilcBuffer channels = NULL;
217 argc = silc_argument_get_arg_num(cmd->args);
219 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
225 client_id = silc_id_payload_parse_id(id_data, len);
231 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
232 username = silc_argument_get_arg_type(cmd->args, 4, &len);
233 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
234 if (!nickname || !username || !realname) {
239 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
241 channels = silc_buffer_alloc(len);
242 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
243 silc_buffer_put(channels, tmp, len);
246 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
248 SILC_GET32_MSB(mode, tmp);
250 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
252 SILC_GET32_MSB(idle, tmp);
254 /* Check if we have this client cached already. */
255 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
257 silc_hash_client_id_compare, NULL,
259 SILC_LOG_DEBUG(("Adding new client entry"));
261 client_entry = silc_calloc(1, sizeof(*client_entry));
262 client_entry->id = client_id;
263 silc_parse_nickname(nickname, &client_entry->nickname,
264 &client_entry->server, &client_entry->num);
265 client_entry->username = strdup(username);
267 client_entry->realname = strdup(realname);
268 client_entry->mode = mode;
270 /* Add client to cache */
271 silc_idcache_add(conn->client_cache, client_entry->nickname,
272 client_id, (void *)client_entry, FALSE);
274 client_entry = (SilcClientEntry)id_cache->context;
275 if (client_entry->nickname)
276 silc_free(client_entry->nickname);
277 if (client_entry->server)
278 silc_free(client_entry->server);
279 if (client_entry->username)
280 silc_free(client_entry->username);
281 if (client_entry->realname)
282 silc_free(client_entry->realname);
283 client_entry->mode = mode;
285 SILC_LOG_DEBUG(("Updating client entry"));
287 silc_parse_nickname(nickname, &client_entry->nickname,
288 &client_entry->server, &client_entry->num);
289 client_entry->username = strdup(username);
291 client_entry->realname = strdup(realname);
293 /* Remove the old cache entry and create a new one */
294 silc_idcache_del_by_context(conn->client_cache, client_entry);
295 silc_idcache_add(conn->client_cache, client_entry->nickname,
296 client_entry->id, client_entry, FALSE);
297 silc_free(client_id);
300 /* Notify application */
302 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
303 channels, mode, idle));
306 silc_buffer_free(channels);
309 /* Received reply for WHOIS command. This maybe called several times
310 for one WHOIS command as server may reply with list of results. */
312 SILC_CLIENT_CMD_REPLY_FUNC(whois)
314 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
315 SilcCommandStatus status;
318 SILC_LOG_DEBUG(("Start"));
320 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
321 SILC_GET16_MSB(status, tmp);
322 if (status != SILC_STATUS_OK &&
323 status != SILC_STATUS_LIST_START &&
324 status != SILC_STATUS_LIST_ITEM &&
325 status != SILC_STATUS_LIST_END) {
330 /* Display one whois reply */
331 if (status == SILC_STATUS_OK)
332 silc_client_command_reply_whois_save(cmd, status);
335 if (status == SILC_STATUS_LIST_START ||
336 status == SILC_STATUS_LIST_ITEM ||
337 status == SILC_STATUS_LIST_END)
338 silc_client_command_reply_whois_save(cmd, status);
340 /* Pending callbacks are not executed if this was an list entry */
341 if (status != SILC_STATUS_OK &&
342 status != SILC_STATUS_LIST_END) {
343 silc_client_command_reply_free(cmd);
347 /* Execute any pending command callbacks */
348 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
351 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
352 silc_client_command_reply_free(cmd);
355 /* Received reply for WHOWAS command. */
357 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
359 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
360 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
361 SilcCommandStatus status;
362 SilcClientID *client_id;
363 SilcIDCacheEntry id_cache = NULL;
364 SilcClientEntry client_entry = NULL;
366 unsigned char *id_data, *tmp;
367 char *nickname, *username;
368 char *realname = NULL;
370 SILC_LOG_DEBUG(("Start"));
372 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
373 SILC_GET16_MSB(status, tmp);
374 if (status != SILC_STATUS_OK &&
375 status != SILC_STATUS_LIST_START &&
376 status != SILC_STATUS_LIST_ITEM &&
377 status != SILC_STATUS_LIST_END) {
382 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
388 client_id = silc_id_payload_parse_id(id_data, len);
394 /* Get the client entry, if exists */
395 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
397 silc_hash_client_id_compare, NULL,
399 client_entry = (SilcClientEntry)id_cache->context;
400 silc_free(client_id);
402 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
403 username = silc_argument_get_arg_type(cmd->args, 4, &len);
404 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
405 if (!nickname || !username) {
409 /* Notify application. We don't save any history information to any
410 cache. Just pass the data to the application for displaying on
412 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
414 /* Pending callbacks are not executed if this was an list entry */
415 if (status != SILC_STATUS_OK &&
416 status != SILC_STATUS_LIST_END) {
417 silc_client_command_reply_free(cmd);
421 /* Execute any pending command callbacks */
422 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
425 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
426 silc_client_command_reply_free(cmd);
430 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
431 SilcCommandStatus status)
433 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
434 SilcClientID *client_id;
435 SilcIDCacheEntry id_cache = NULL;
436 SilcClientEntry client_entry = NULL;
439 unsigned char *id_data;
440 char *nickname = NULL, *username = NULL;
442 argc = silc_argument_get_arg_num(cmd->args);
444 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
450 client_id = silc_id_payload_parse_id(id_data, len);
456 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
457 username = silc_argument_get_arg_type(cmd->args, 4, &len);
459 /* Check if we have this client cached already. */
460 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
462 silc_hash_client_id_compare, NULL,
464 SILC_LOG_DEBUG(("Adding new client entry"));
466 client_entry = silc_calloc(1, sizeof(*client_entry));
467 client_entry->id = client_id;
468 silc_parse_nickname(nickname, &client_entry->nickname,
469 &client_entry->server, &client_entry->num);
471 client_entry->username = strdup(username);
473 /* Add client to cache */
474 silc_idcache_add(conn->client_cache, client_entry->nickname,
475 client_id, (void *)client_entry, FALSE);
477 client_entry = (SilcClientEntry)id_cache->context;
478 if (client_entry->nickname)
479 silc_free(client_entry->nickname);
480 if (client_entry->server)
481 silc_free(client_entry->server);
482 if (username && client_entry->username)
483 silc_free(client_entry->username);
485 SILC_LOG_DEBUG(("Updating client entry"));
487 silc_parse_nickname(nickname, &client_entry->nickname,
488 &client_entry->server, &client_entry->num);
491 client_entry->username = strdup(username);
493 /* Remove the old cache entry and create a new one */
494 silc_idcache_del_by_context(conn->client_cache, client_entry);
495 silc_idcache_add(conn->client_cache, client_entry->nickname,
496 client_entry->id, client_entry, FALSE);
497 silc_free(client_id);
500 /* Notify application */
501 COMMAND_REPLY((ARGS, client_entry, nickname, username));
504 /* Received reply for IDENTIFY command. This maybe called several times
505 for one IDENTIFY command as server may reply with list of results.
506 This is totally silent and does not print anything on screen. */
508 SILC_CLIENT_CMD_REPLY_FUNC(identify)
510 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
511 SilcCommandStatus status;
514 SILC_LOG_DEBUG(("Start"));
516 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
517 SILC_GET16_MSB(status, tmp);
518 if (status != SILC_STATUS_OK &&
519 status != SILC_STATUS_LIST_START &&
520 status != SILC_STATUS_LIST_ITEM &&
521 status != SILC_STATUS_LIST_END) {
526 /* Save one IDENTIFY entry */
527 if (status == SILC_STATUS_OK)
528 silc_client_command_reply_identify_save(cmd, status);
531 if (status == SILC_STATUS_LIST_START ||
532 status == SILC_STATUS_LIST_ITEM ||
533 status == SILC_STATUS_LIST_END)
534 silc_client_command_reply_identify_save(cmd, status);
536 /* Pending callbacks are not executed if this was an list entry */
537 if (status != SILC_STATUS_OK &&
538 status != SILC_STATUS_LIST_END) {
539 silc_client_command_reply_free(cmd);
543 /* Execute any pending command callbacks */
544 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
547 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
548 silc_client_command_reply_free(cmd);
551 /* Received reply for command NICK. If everything went without errors
552 we just received our new Client ID. */
554 SILC_CLIENT_CMD_REPLY_FUNC(nick)
556 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
557 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
558 SilcCommandStatus status;
563 SILC_LOG_DEBUG(("Start"));
565 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
566 if (status != SILC_STATUS_OK) {
567 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
568 "Cannot set nickname: %s",
569 silc_client_command_status_message(status));
574 argc = silc_argument_get_arg_num(cmd->args);
575 if (argc < 2 || argc > 2) {
576 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
577 "Cannot set nickname: bad reply to command");
582 /* Take received Client ID */
583 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
584 idp = silc_id_payload_parse_data(tmp, len);
589 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
591 /* Notify application */
592 COMMAND_REPLY((ARGS, conn->local_entry));
594 /* Execute any pending command callbacks */
595 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
598 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
599 silc_client_command_reply_free(cmd);
602 /* Received reply to the LIST command. */
604 SILC_CLIENT_CMD_REPLY_FUNC(list)
606 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
607 SilcCommandStatus status;
608 unsigned char *tmp, *name, *topic;
609 uint32 usercount = 0;
611 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
612 SILC_GET16_MSB(status, tmp);
613 if (status != SILC_STATUS_OK &&
614 status != SILC_STATUS_LIST_START &&
615 status != SILC_STATUS_LIST_ITEM &&
616 status != SILC_STATUS_LIST_END) {
621 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
622 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
623 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
625 SILC_GET32_MSB(usercount, tmp);
627 /* Notify application */
628 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
630 /* Pending callbacks are not executed if this was an list entry */
631 if (status != SILC_STATUS_OK &&
632 status != SILC_STATUS_LIST_END) {
633 silc_client_command_reply_free(cmd);
637 /* Execute any pending command callbacks */
638 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
641 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
642 silc_client_command_reply_free(cmd);
645 /* Received reply to topic command. */
647 SILC_CLIENT_CMD_REPLY_FUNC(topic)
649 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
650 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
651 SilcCommandStatus status;
652 SilcChannelEntry channel;
653 SilcChannelID *channel_id = NULL;
654 SilcIDCacheEntry id_cache = NULL;
659 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
660 if (status != SILC_STATUS_OK) {
661 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
662 "%s", silc_client_command_status_message(status));
664 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
665 silc_client_command_reply_free(cmd);
669 argc = silc_argument_get_arg_num(cmd->args);
670 if (argc < 1 || argc > 3) {
675 /* Take Channel ID */
676 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
681 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
685 channel_id = silc_id_payload_parse_id(tmp, len);
689 /* Get the channel entry */
690 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
692 silc_free(channel_id);
697 channel = (SilcChannelEntry)id_cache->context;
699 /* Notify application */
700 COMMAND_REPLY((ARGS, channel, topic));
702 /* Execute any pending command callbacks */
703 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
706 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
707 silc_client_command_reply_free(cmd);
710 /* Received reply to invite command. */
712 SILC_CLIENT_CMD_REPLY_FUNC(invite)
714 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
715 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
716 SilcCommandStatus status;
717 SilcChannelEntry channel;
718 SilcChannelID *channel_id;
719 SilcIDCacheEntry id_cache;
723 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
724 SILC_GET16_MSB(status, tmp);
725 if (status != SILC_STATUS_OK) {
726 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
727 "%s", silc_client_command_status_message(status));
729 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
730 silc_client_command_reply_free(cmd);
734 /* Take Channel ID */
735 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
739 channel_id = silc_id_payload_parse_id(tmp, len);
743 /* Get the channel entry */
744 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
746 silc_free(channel_id);
751 channel = (SilcChannelEntry)id_cache->context;
753 /* Get the invite list */
754 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
756 /* Notify application */
757 COMMAND_REPLY((ARGS, channel, tmp));
759 /* Execute any pending command callbacks */
760 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
763 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
764 silc_client_command_reply_free(cmd);
767 /* Received reply to the KILL command. */
769 SILC_CLIENT_CMD_REPLY_FUNC(kill)
771 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
772 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
773 SilcCommandStatus status;
776 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
777 SILC_GET16_MSB(status, tmp);
778 if (status != SILC_STATUS_OK) {
779 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
780 "%s", silc_client_command_status_message(status));
785 /* Notify application */
786 COMMAND_REPLY((ARGS));
788 /* Execute any pending command callbacks */
789 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
792 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
793 silc_client_command_reply_free(cmd);
796 /* Received reply to INFO command. We receive the server ID and some
797 information about the server user requested. */
799 SILC_CLIENT_CMD_REPLY_FUNC(info)
801 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
802 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
803 SilcClient client = cmd->client;
804 SilcCommandStatus status;
807 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
808 SILC_GET16_MSB(status, tmp);
809 if (status != SILC_STATUS_OK) {
810 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
811 "%s", silc_client_command_status_message(status));
813 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
814 silc_client_command_reply_free(cmd);
819 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
823 /* XXX save server id */
825 /* Get server name */
826 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
830 /* Get server info */
831 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
835 client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
838 /* Notify application */
839 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
841 /* Execute any pending command callbacks */
842 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
845 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
846 silc_client_command_reply_free(cmd);
849 /* Received reply to PING command. The reply time is shown to user. */
851 SILC_CLIENT_CMD_REPLY_FUNC(ping)
853 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
854 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
855 SilcCommandStatus status;
858 time_t diff, curtime;
860 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
861 if (status != SILC_STATUS_OK) {
862 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
863 "%s", silc_client_command_status_message(status));
868 curtime = time(NULL);
869 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
870 cmd->packet->src_id_type);
876 for (i = 0; i < conn->ping_count; i++) {
877 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
878 diff = curtime - conn->ping[i].start_time;
879 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
880 "Ping reply from %s: %d second%s",
881 conn->ping[i].dest_name, diff,
882 diff == 1 ? "" : "s");
884 conn->ping[i].start_time = 0;
885 silc_free(conn->ping[i].dest_id);
886 conn->ping[i].dest_id = NULL;
887 silc_free(conn->ping[i].dest_name);
888 conn->ping[i].dest_name = NULL;
895 /* Notify application */
896 COMMAND_REPLY((ARGS));
898 /* Execute any pending command callbacks */
899 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
902 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
903 silc_client_command_reply_free(cmd);
906 /* Received reply for JOIN command. */
908 SILC_CLIENT_CMD_REPLY_FUNC(join)
910 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
911 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
912 SilcCommandStatus status;
913 SilcIDPayload idp = NULL;
914 SilcChannelEntry channel;
915 SilcIDCacheEntry id_cache = NULL;
917 uint32 argc, mode, len, list_count;
918 char *topic, *tmp, *channel_name = NULL, *hmac;
919 SilcBuffer keyp = NULL, client_id_list, client_mode_list;
922 SILC_LOG_DEBUG(("Start"));
924 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
925 if (status != SILC_STATUS_OK) {
926 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
927 "%s", silc_client_command_status_message(status));
932 argc = silc_argument_get_arg_num(cmd->args);
933 if (argc < 7 || argc > 14) {
934 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
935 "Cannot join channel: Bad reply packet");
940 /* Get channel name */
941 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
943 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
944 "Cannot join channel: Bad reply packet");
948 channel_name = strdup(tmp);
951 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
953 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
954 "Cannot join channel: Bad reply packet");
956 silc_free(channel_name);
959 idp = silc_id_payload_parse_data(tmp, len);
962 silc_free(channel_name);
966 /* Get channel mode */
967 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
969 SILC_GET32_MSB(mode, tmp);
973 /* Get channel key */
974 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
976 keyp = silc_buffer_alloc(len);
977 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
978 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, SILC_CLIENT_MESSAGE_ERROR,
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++) {
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_ext(conn->client_cache,
1047 silc_hash_client_id_compare, NULL,
1049 /* No, we don't have it, add entry for it. */
1050 client_entry = silc_calloc(1, sizeof(*client_entry));
1051 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1052 silc_idcache_add(conn->client_cache, NULL, client_entry->id,
1053 (void *)client_entry, FALSE);
1055 /* Yes, we have it already */
1056 client_entry = (SilcClientEntry)id_cache->context;
1059 /* Join the client to the channel */
1060 chu = silc_calloc(1, sizeof(*chu));
1061 chu->client = client_entry;
1063 silc_list_add(channel->clients, chu);
1064 silc_free(client_id);
1066 silc_buffer_pull(client_id_list, idp_len);
1067 silc_buffer_pull(client_mode_list, 4);
1069 silc_buffer_push(client_id_list, client_id_list->data -
1070 client_id_list->head);
1071 silc_buffer_push(client_mode_list, client_mode_list->data -
1072 client_mode_list->head);
1074 /* Save channel key */
1075 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1076 silc_client_save_channel_key(conn, keyp, channel);
1078 /* Client is now joined to the channel */
1079 channel->on_channel = TRUE;
1081 /* Notify application */
1082 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1083 keyp ? keyp->head : NULL, NULL,
1084 NULL, topic, hmac, list_count, client_id_list,
1087 /* Execute any pending command callbacks */
1088 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1091 silc_buffer_free(keyp);
1092 silc_buffer_free(client_id_list);
1093 silc_buffer_free(client_mode_list);
1096 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1097 silc_client_command_reply_free(cmd);
1100 /* Received reply for MOTD command */
1102 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1104 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1105 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1106 SilcCommandStatus status;
1109 char *motd = NULL, *cp, line[256];
1111 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1112 SILC_GET16_MSB(status, tmp);
1113 if (status != SILC_STATUS_OK) {
1114 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1115 "%s", silc_client_command_status_message(status));
1116 COMMAND_REPLY_ERROR;
1120 argc = silc_argument_get_arg_num(cmd->args);
1122 COMMAND_REPLY_ERROR;
1127 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1129 COMMAND_REPLY_ERROR;
1136 if (cp[i++] == '\n') {
1137 memset(line, 0, sizeof(line));
1138 strncat(line, cp, i - 1);
1144 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1154 /* Notify application */
1155 COMMAND_REPLY((ARGS, motd));
1157 /* Execute any pending command callbacks */
1158 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1161 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1162 silc_client_command_reply_free(cmd);
1165 /* Received reply tot he UMODE command. Save the current user mode */
1167 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1169 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1170 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1171 SilcCommandStatus status;
1175 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1176 SILC_GET16_MSB(status, tmp);
1177 if (status != SILC_STATUS_OK) {
1178 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1179 "%s", silc_client_command_status_message(status));
1180 COMMAND_REPLY_ERROR;
1184 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1186 COMMAND_REPLY_ERROR;
1190 SILC_GET32_MSB(mode, tmp);
1191 conn->local_entry->mode = mode;
1193 /* Notify application */
1194 COMMAND_REPLY((ARGS, mode));
1196 /* Execute any pending command callbacks */
1197 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1200 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1201 silc_client_command_reply_free(cmd);
1204 /* Received reply for CMODE command. */
1206 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1208 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1209 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1210 SilcCommandStatus status;
1214 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1215 if (status != SILC_STATUS_OK) {
1216 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1217 "%s", silc_client_command_status_message(status));
1218 COMMAND_REPLY_ERROR;
1222 /* Get channel mode */
1223 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1225 COMMAND_REPLY_ERROR;
1229 SILC_GET32_MSB(mode, tmp);
1231 /* Notify application */
1232 COMMAND_REPLY((ARGS, mode));
1234 /* Execute any pending command callbacks */
1235 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1238 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1239 silc_client_command_reply_free(cmd);
1242 /* Received reply for CUMODE command */
1244 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1246 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1247 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1248 SilcCommandStatus status;
1249 SilcIDCacheEntry id_cache = NULL;
1250 SilcClientID *client_id;
1251 unsigned char *tmp, *id;
1254 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1255 if (status != SILC_STATUS_OK) {
1256 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1257 "%s", silc_client_command_status_message(status));
1258 COMMAND_REPLY_ERROR;
1262 /* Get channel mode */
1263 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1265 COMMAND_REPLY_ERROR;
1270 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1272 COMMAND_REPLY_ERROR;
1275 client_id = silc_id_payload_parse_id(id, len);
1277 COMMAND_REPLY_ERROR;
1281 /* Get client entry */
1282 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1284 silc_hash_client_id_compare, NULL,
1286 COMMAND_REPLY_ERROR;
1290 SILC_GET32_MSB(mode, tmp);
1292 /* Notify application */
1293 COMMAND_REPLY((ARGS, mode, (SilcClientEntry)id_cache->context));
1294 silc_free(client_id);
1296 /* Execute any pending command callbacks */
1297 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1300 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1301 silc_client_command_reply_free(cmd);
1304 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1306 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1307 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1308 SilcCommandStatus status;
1311 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1312 SILC_GET16_MSB(status, tmp);
1313 if (status != SILC_STATUS_OK) {
1314 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1315 "%s", silc_client_command_status_message(status));
1316 COMMAND_REPLY_ERROR;
1320 /* Notify application */
1321 COMMAND_REPLY((ARGS));
1323 /* Execute any pending command callbacks */
1324 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1327 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1328 silc_client_command_reply_free(cmd);
1331 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1333 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1334 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1335 SilcCommandStatus status;
1338 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1339 SILC_GET16_MSB(status, tmp);
1340 if (status != SILC_STATUS_OK) {
1341 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1342 "%s", silc_client_command_status_message(status));
1343 COMMAND_REPLY_ERROR;
1347 /* Notify application */
1348 COMMAND_REPLY((ARGS));
1350 /* Execute any pending command callbacks */
1351 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1354 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1355 silc_client_command_reply_free(cmd);
1358 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1360 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1361 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1362 SilcCommandStatus status;
1365 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1366 SILC_GET16_MSB(status, tmp);
1367 if (status != SILC_STATUS_OK) {
1368 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1369 "%s", silc_client_command_status_message(status));
1370 COMMAND_REPLY_ERROR;
1374 /* Notify application */
1375 COMMAND_REPLY((ARGS));
1377 /* Execute any pending command callbacks */
1378 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1381 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1382 silc_client_command_reply_free(cmd);
1385 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1387 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1388 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1389 SilcCommandStatus status;
1392 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1393 SILC_GET16_MSB(status, tmp);
1394 if (status != SILC_STATUS_OK) {
1395 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1396 "%s", silc_client_command_status_message(status));
1397 COMMAND_REPLY_ERROR;
1401 /* Notify application */
1402 COMMAND_REPLY((ARGS));
1404 /* Execute any pending command callbacks */
1405 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1408 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1409 silc_client_command_reply_free(cmd);
1412 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1414 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1415 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1416 SilcCommandStatus status;
1417 SilcIDCacheEntry id_cache = NULL;
1418 SilcChannelEntry channel;
1419 SilcChannelID *channel_id;
1423 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1424 SILC_GET16_MSB(status, tmp);
1425 if (status != SILC_STATUS_OK) {
1426 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1427 "%s", silc_client_command_status_message(status));
1428 COMMAND_REPLY_ERROR;
1432 /* Take Channel ID */
1433 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1437 channel_id = silc_id_payload_parse_id(tmp, len);
1441 /* Get the channel entry */
1442 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1444 silc_free(channel_id);
1445 COMMAND_REPLY_ERROR;
1449 channel = (SilcChannelEntry)id_cache->context;
1451 /* Get the ban list */
1452 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1454 /* Notify application */
1455 COMMAND_REPLY((ARGS, channel, tmp));
1457 /* Execute any pending command callbacks */
1458 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1461 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1462 silc_client_command_reply_free(cmd);
1465 SILC_CLIENT_CMD_REPLY_FUNC(close)
1467 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1468 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1469 SilcCommandStatus status;
1472 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1473 SILC_GET16_MSB(status, tmp);
1474 if (status != SILC_STATUS_OK) {
1475 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1476 "%s", silc_client_command_status_message(status));
1477 COMMAND_REPLY_ERROR;
1481 /* Notify application */
1482 COMMAND_REPLY((ARGS));
1484 /* Execute any pending command callbacks */
1485 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1488 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1489 silc_client_command_reply_free(cmd);
1492 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1494 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1495 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1496 SilcCommandStatus status;
1499 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1500 SILC_GET16_MSB(status, tmp);
1501 if (status != SILC_STATUS_OK) {
1502 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1503 "%s", silc_client_command_status_message(status));
1504 COMMAND_REPLY_ERROR;
1508 /* Notify application */
1509 COMMAND_REPLY((ARGS));
1511 /* Execute any pending command callbacks */
1512 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1515 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1516 silc_client_command_reply_free(cmd);
1519 /* Reply to LEAVE command. */
1521 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1523 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1524 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1525 SilcCommandStatus status;
1528 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1529 SILC_GET16_MSB(status, tmp);
1530 if (status != SILC_STATUS_OK) {
1531 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1532 "%s", silc_client_command_status_message(status));
1533 COMMAND_REPLY_ERROR;
1537 /* Notify application */
1538 COMMAND_REPLY((ARGS));
1540 /* Execute any pending command callbacks */
1541 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1544 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1545 silc_client_command_reply_free(cmd);
1548 /* Reply to USERS command. Received list of client ID's and theirs modes
1549 on the channel we requested. */
1551 SILC_CLIENT_CMD_REPLY_FUNC(users)
1553 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1554 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1555 SilcCommandStatus status;
1556 SilcIDCacheEntry id_cache = NULL;
1557 SilcChannelEntry channel;
1558 SilcChannelUser chu;
1559 SilcChannelID *channel_id = NULL;
1560 SilcBuffer client_id_list;
1561 SilcBuffer client_mode_list;
1563 uint32 tmp_len, list_count;
1565 unsigned char **res_argv = NULL;
1566 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1568 SILC_LOG_DEBUG(("Start"));
1570 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1571 SILC_GET16_MSB(status, tmp);
1572 if (status != SILC_STATUS_OK) {
1573 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1574 "%s", silc_client_command_status_message(status));
1575 COMMAND_REPLY_ERROR;
1579 /* Get channel ID */
1580 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1583 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1587 /* Get the list count */
1588 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1591 SILC_GET32_MSB(list_count, tmp);
1593 /* Get Client ID list */
1594 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1598 client_id_list = silc_buffer_alloc(tmp_len);
1599 silc_buffer_pull_tail(client_id_list, tmp_len);
1600 silc_buffer_put(client_id_list, tmp, tmp_len);
1602 /* Get client mode list */
1603 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1607 client_mode_list = silc_buffer_alloc(tmp_len);
1608 silc_buffer_pull_tail(client_mode_list, tmp_len);
1609 silc_buffer_put(client_mode_list, tmp, tmp_len);
1611 /* Get channel entry */
1612 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1614 COMMAND_REPLY_ERROR;
1617 channel = (SilcChannelEntry)id_cache->context;
1619 /* Remove old client list from channel. */
1620 silc_list_start(channel->clients);
1621 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1622 silc_list_del(channel->clients, chu);
1626 /* Cache the received Client ID's and modes. This cache expires
1627 whenever server sends notify message to channel. It means two things;
1628 some user has joined or leaved the channel. XXX! */
1629 for (i = 0; i < list_count; i++) {
1632 SilcClientID *client_id;
1633 SilcClientEntry client;
1636 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1638 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1643 SILC_GET32_MSB(mode, client_mode_list->data);
1645 /* Check if we have this client cached already. */
1647 silc_idcache_find_by_id_one_ext(conn->client_cache,
1650 silc_hash_client_id_compare, NULL,
1653 if (!id_cache || !((SilcClientEntry)id_cache->context)->username) {
1654 /* No we don't have it (or it is incomplete in information), query
1655 it from the server. Assemble argument table that will be sent
1656 for the WHOIS command later. */
1657 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1659 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1661 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1663 res_argv[res_argc] = client_id_list->data;
1664 res_argv_lens[res_argc] = idp_len;
1665 res_argv_types[res_argc] = res_argc + 3;
1668 /* Found the client, join it to the channel */
1669 client = (SilcClientEntry)id_cache->context;
1670 chu = silc_calloc(1, sizeof(*chu));
1671 chu->client = client;
1673 silc_list_add(channel->clients, chu);
1675 silc_free(client_id);
1679 silc_buffer_pull(client_id_list, idp_len);
1680 silc_buffer_pull(client_mode_list, 4);
1683 /* Query the client information from server if the list included clients
1684 that we don't know about. */
1688 /* Send the WHOIS command to server */
1689 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1690 res_argc, res_argv, res_argv_lens,
1691 res_argv_types, ++conn->cmd_ident);
1692 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1693 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1696 /* Register pending command callback. After we've received the WHOIS
1697 command reply we will reprocess this command reply by re-calling this
1698 USERS command reply callback. */
1699 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1700 NULL, silc_client_command_reply_users, cmd);
1702 silc_buffer_free(res_cmd);
1704 silc_free(channel_id);
1706 silc_free(res_argv);
1707 silc_free(res_argv_lens);
1708 silc_free(res_argv_types);
1712 /* Notify application */
1713 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1715 /* Execute any pending command callbacks */
1716 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1718 silc_buffer_free(client_id_list);
1719 silc_buffer_free(client_mode_list);
1723 silc_free(channel_id);
1724 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1725 silc_client_command_reply_free(cmd);
1728 /* Received command reply to GETKEY command. WE've received the remote
1729 client's public key. */
1731 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1733 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1734 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1735 SilcCommandStatus status;
1736 SilcIDCacheEntry id_cache;
1737 SilcIDPayload idp = NULL;
1738 SilcClientID *client_id = NULL;
1739 SilcClientEntry client_entry;
1741 unsigned char *tmp, *pk;
1745 SilcPublicKey public_key = NULL;
1747 SILC_LOG_DEBUG(("Start"));
1749 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1750 SILC_GET16_MSB(status, tmp);
1751 if (status != SILC_STATUS_OK) {
1752 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1753 "%s", silc_client_command_status_message(status));
1754 COMMAND_REPLY_ERROR;
1758 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1761 idp = silc_id_payload_parse_data(tmp, len);
1765 /* Get the public key payload */
1766 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1770 /* Decode the public key */
1772 SILC_GET16_MSB(pk_len, tmp);
1773 SILC_GET16_MSB(type, tmp + 2);
1776 if (type != SILC_SKE_PK_TYPE_SILC)
1779 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1782 id_type = silc_id_payload_get_type(idp);
1783 if (id_type == SILC_ID_CLIENT) {
1784 client_id = silc_id_payload_get_id(idp);
1786 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1789 silc_hash_client_id_compare, NULL,
1793 client_entry = (SilcClientEntry)id_cache->context;
1795 /* Notify application */
1796 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1797 } else if (id_type == SILC_ID_SERVER) {
1798 /* XXX we don't have server entries at all */
1805 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1807 silc_id_payload_free(idp);
1809 silc_pkcs_public_key_free(public_key);
1810 silc_free(client_id);
1811 silc_client_command_reply_free(cmd);