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), "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" },
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_free_payload(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(conn->client_cache, (void *)client_id,
256 SILC_ID_CLIENT, &id_cache)) {
257 SILC_LOG_DEBUG(("Adding new client entry"));
259 client_entry = silc_calloc(1, sizeof(*client_entry));
260 client_entry->id = client_id;
261 silc_parse_nickname(nickname, &client_entry->nickname,
262 &client_entry->server, &client_entry->num);
263 client_entry->username = strdup(username);
265 client_entry->realname = strdup(realname);
266 client_entry->mode = mode;
268 /* Add client to cache */
269 silc_idcache_add(conn->client_cache, client_entry->nickname,
270 strlen(client_entry->nickname),
271 SILC_ID_CLIENT, client_id, (void *)client_entry,
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 id_cache->data = client_entry->nickname;
294 id_cache->data_len = strlen(client_entry->nickname);
295 silc_idcache_sort_by_data(conn->client_cache);
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(conn->client_cache, (void *)client_id,
396 SILC_ID_CLIENT, &id_cache))
397 client_entry = (SilcClientEntry)id_cache->context;
398 silc_free(client_id);
400 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
401 username = silc_argument_get_arg_type(cmd->args, 4, &len);
402 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
403 if (!nickname || !username) {
407 /* Notify application. We don't save any history information to any
408 cache. Just pass the data to the application for displaying on
410 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
412 /* Pending callbacks are not executed if this was an list entry */
413 if (status != SILC_STATUS_OK &&
414 status != SILC_STATUS_LIST_END) {
415 silc_client_command_reply_free(cmd);
419 /* Execute any pending command callbacks */
420 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
423 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
424 silc_client_command_reply_free(cmd);
428 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
429 SilcCommandStatus status)
431 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
432 SilcClientID *client_id;
433 SilcIDCacheEntry id_cache = NULL;
434 SilcClientEntry client_entry = NULL;
437 unsigned char *id_data;
438 char *nickname = NULL, *username = NULL;
440 argc = silc_argument_get_arg_num(cmd->args);
442 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
448 client_id = silc_id_payload_parse_id(id_data, len);
454 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
455 username = silc_argument_get_arg_type(cmd->args, 4, &len);
457 /* Check if we have this client cached already. */
458 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
459 SILC_ID_CLIENT, &id_cache)) {
460 SILC_LOG_DEBUG(("Adding new client entry"));
462 client_entry = silc_calloc(1, sizeof(*client_entry));
463 client_entry->id = client_id;
464 silc_parse_nickname(nickname, &client_entry->nickname,
465 &client_entry->server, &client_entry->num);
467 client_entry->username = strdup(username);
469 /* Add client to cache */
470 silc_idcache_add(conn->client_cache, client_entry->nickname,
471 strlen(client_entry->nickname),
472 SILC_ID_CLIENT, client_id, (void *)client_entry,
475 client_entry = (SilcClientEntry)id_cache->context;
476 if (client_entry->nickname)
477 silc_free(client_entry->nickname);
478 if (client_entry->server)
479 silc_free(client_entry->server);
480 if (username && client_entry->username)
481 silc_free(client_entry->username);
483 SILC_LOG_DEBUG(("Updating client entry"));
485 silc_parse_nickname(nickname, &client_entry->nickname,
486 &client_entry->server, &client_entry->num);
489 client_entry->username = strdup(username);
491 id_cache->data = client_entry->nickname;
492 id_cache->data_len = strlen(client_entry->nickname);
493 silc_idcache_sort_by_data(conn->client_cache);
495 silc_free(client_id);
498 /* Notify application */
499 COMMAND_REPLY((ARGS, client_entry, nickname, username));
502 /* Received reply for IDENTIFY command. This maybe called several times
503 for one IDENTIFY command as server may reply with list of results.
504 This is totally silent and does not print anything on screen. */
506 SILC_CLIENT_CMD_REPLY_FUNC(identify)
508 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
509 SilcCommandStatus status;
512 SILC_LOG_DEBUG(("Start"));
514 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
515 SILC_GET16_MSB(status, tmp);
516 if (status != SILC_STATUS_OK &&
517 status != SILC_STATUS_LIST_START &&
518 status != SILC_STATUS_LIST_ITEM &&
519 status != SILC_STATUS_LIST_END) {
524 /* Save one IDENTIFY entry */
525 if (status == SILC_STATUS_OK)
526 silc_client_command_reply_identify_save(cmd, status);
529 if (status == SILC_STATUS_LIST_START ||
530 status == SILC_STATUS_LIST_ITEM ||
531 status == SILC_STATUS_LIST_END)
532 silc_client_command_reply_identify_save(cmd, status);
534 /* Pending callbacks are not executed if this was an list entry */
535 if (status != SILC_STATUS_OK &&
536 status != SILC_STATUS_LIST_END) {
537 silc_client_command_reply_free(cmd);
541 /* Execute any pending command callbacks */
542 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
545 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
546 silc_client_command_reply_free(cmd);
549 /* Received reply for command NICK. If everything went without errors
550 we just received our new Client ID. */
552 SILC_CLIENT_CMD_REPLY_FUNC(nick)
554 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
555 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
556 SilcCommandStatus status;
561 SILC_LOG_DEBUG(("Start"));
563 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
564 if (status != SILC_STATUS_OK) {
565 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
566 silc_client_command_status_message(status));
571 argc = silc_argument_get_arg_num(cmd->args);
572 if (argc < 2 || argc > 2) {
573 cmd->client->ops->say(cmd->client, conn,
574 "Cannot set nickname: bad reply to command");
579 /* Take received Client ID */
580 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
581 idp = silc_id_payload_parse_data(tmp, len);
586 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
588 /* Notify application */
589 COMMAND_REPLY((ARGS, conn->local_entry));
591 /* Execute any pending command callbacks */
592 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
595 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
596 silc_client_command_reply_free(cmd);
599 /* Received reply to the LIST command. */
601 SILC_CLIENT_CMD_REPLY_FUNC(list)
603 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
604 SilcCommandStatus status;
605 unsigned char *tmp, *name, *topic;
606 uint32 usercount = 0;
608 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
609 SILC_GET16_MSB(status, tmp);
610 if (status != SILC_STATUS_OK &&
611 status != SILC_STATUS_LIST_START &&
612 status != SILC_STATUS_LIST_ITEM &&
613 status != SILC_STATUS_LIST_END) {
618 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
619 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
620 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
622 SILC_GET32_MSB(usercount, tmp);
624 /* Notify application */
625 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
627 /* Pending callbacks are not executed if this was an list entry */
628 if (status != SILC_STATUS_OK &&
629 status != SILC_STATUS_LIST_END) {
630 silc_client_command_reply_free(cmd);
634 /* Execute any pending command callbacks */
635 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
638 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
639 silc_client_command_reply_free(cmd);
642 /* Received reply to topic command. */
644 SILC_CLIENT_CMD_REPLY_FUNC(topic)
646 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
647 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
648 SilcCommandStatus status;
649 SilcChannelEntry channel;
650 SilcChannelID *channel_id = NULL;
651 SilcIDCacheEntry id_cache = NULL;
656 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
657 if (status != SILC_STATUS_OK) {
658 cmd->client->ops->say(cmd->client, conn,
659 "%s", silc_client_command_status_message(status));
661 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
662 silc_client_command_reply_free(cmd);
666 argc = silc_argument_get_arg_num(cmd->args);
667 if (argc < 1 || argc > 3) {
672 /* Take Channel ID */
673 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
678 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
682 channel_id = silc_id_payload_parse_id(tmp, len);
686 /* Get the channel entry */
687 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
688 SILC_ID_CHANNEL, &id_cache)) {
689 silc_free(channel_id);
694 channel = (SilcChannelEntry)id_cache->context;
696 cmd->client->ops->say(cmd->client, conn,
697 "Topic on channel %s: %s", channel->channel_name,
700 /* Notify application */
701 COMMAND_REPLY((ARGS, channel, topic));
703 /* Execute any pending command callbacks */
704 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
707 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
708 silc_client_command_reply_free(cmd);
711 /* Received reply to invite command. */
713 SILC_CLIENT_CMD_REPLY_FUNC(invite)
715 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
716 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
717 SilcCommandStatus status;
718 SilcChannelEntry channel;
719 SilcChannelID *channel_id;
720 SilcIDCacheEntry id_cache;
724 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
725 SILC_GET16_MSB(status, tmp);
726 if (status != SILC_STATUS_OK) {
727 cmd->client->ops->say(cmd->client, conn,
728 "%s", silc_client_command_status_message(status));
730 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
731 silc_client_command_reply_free(cmd);
735 /* Take Channel ID */
736 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
740 channel_id = silc_id_payload_parse_id(tmp, len);
744 /* Get the channel entry */
745 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
746 SILC_ID_CHANNEL, &id_cache)) {
747 silc_free(channel_id);
752 channel = (SilcChannelEntry)id_cache->context;
754 /* Get the invite list */
755 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
757 /* Notify application */
758 COMMAND_REPLY((ARGS, channel, tmp));
760 /* Execute any pending command callbacks */
761 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
764 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
765 silc_client_command_reply_free(cmd);
768 /* Received reply to the KILL command. */
770 SILC_CLIENT_CMD_REPLY_FUNC(kill)
772 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
773 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
774 SilcCommandStatus status;
777 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
778 SILC_GET16_MSB(status, tmp);
779 if (status != SILC_STATUS_OK) {
780 cmd->client->ops->say(cmd->client, conn,
781 "%s", silc_client_command_status_message(status));
786 /* Notify application */
787 COMMAND_REPLY((ARGS));
789 /* Execute any pending command callbacks */
790 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
793 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
794 silc_client_command_reply_free(cmd);
797 /* Received reply to INFO command. We receive the server ID and some
798 information about the server user requested. */
800 SILC_CLIENT_CMD_REPLY_FUNC(info)
802 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
803 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
804 SilcClient client = cmd->client;
805 SilcCommandStatus status;
808 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
809 SILC_GET16_MSB(status, tmp);
810 if (status != SILC_STATUS_OK) {
811 cmd->client->ops->say(cmd->client, conn,
812 "%s", silc_client_command_status_message(status));
814 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
815 silc_client_command_reply_free(cmd);
820 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
824 /* XXX save server id */
826 /* Get server name */
827 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
831 /* Get server info */
832 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
836 client->ops->say(cmd->client, conn, "Info: %s", tmp);
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,
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,
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,
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,
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,
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,
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,
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(conn->client_cache, (void *)client_id,
1045 SILC_ID_CLIENT, &id_cache)) {
1046 /* No, we don't have it, add entry for it. */
1047 client_entry = silc_calloc(1, sizeof(*client_entry));
1048 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1049 silc_idcache_add(conn->client_cache, NULL, 0, SILC_ID_CLIENT,
1050 client_entry->id, (void *)client_entry, FALSE, FALSE);
1052 /* Yes, we have it already */
1053 client_entry = (SilcClientEntry)id_cache->context;
1056 /* Join the client to the channel */
1057 chu = silc_calloc(1, sizeof(*chu));
1058 chu->client = client_entry;
1060 silc_list_add(channel->clients, chu);
1061 silc_free(client_id);
1063 silc_buffer_pull(client_id_list, idp_len);
1064 silc_buffer_pull(client_mode_list, 4);
1066 silc_buffer_push(client_id_list, client_id_list->data -
1067 client_id_list->head);
1068 silc_buffer_push(client_mode_list, client_mode_list->data -
1069 client_mode_list->head);
1071 /* Save channel key */
1072 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1073 silc_client_save_channel_key(conn, keyp, channel);
1075 /* Client is now joined to the channel */
1076 channel->on_channel = TRUE;
1078 /* Notify application */
1079 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1080 keyp ? keyp->head : NULL, NULL,
1081 NULL, topic, hmac, list_count, client_id_list,
1084 /* Execute any pending command callbacks */
1085 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1088 silc_buffer_free(keyp);
1089 silc_buffer_free(client_id_list);
1090 silc_buffer_free(client_mode_list);
1093 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1094 silc_client_command_reply_free(cmd);
1097 /* Received reply for MOTD command */
1099 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1101 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1102 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1103 SilcCommandStatus status;
1106 char *motd = NULL, *cp, line[256];
1108 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1109 SILC_GET16_MSB(status, tmp);
1110 if (status != SILC_STATUS_OK) {
1111 cmd->client->ops->say(cmd->client, conn,
1112 "%s", silc_client_command_status_message(status));
1113 COMMAND_REPLY_ERROR;
1117 argc = silc_argument_get_arg_num(cmd->args);
1119 COMMAND_REPLY_ERROR;
1124 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1126 COMMAND_REPLY_ERROR;
1133 if (cp[i++] == '\n') {
1134 memset(line, 0, sizeof(line));
1135 strncat(line, cp, i - 1);
1141 cmd->client->ops->say(cmd->client, conn, "%s", line);
1150 /* Notify application */
1151 COMMAND_REPLY((ARGS, motd));
1153 /* Execute any pending command callbacks */
1154 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1157 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1158 silc_client_command_reply_free(cmd);
1161 /* Received reply tot he UMODE command. Save the current user mode */
1163 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1165 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1166 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1167 SilcCommandStatus status;
1171 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1172 SILC_GET16_MSB(status, tmp);
1173 if (status != SILC_STATUS_OK) {
1174 cmd->client->ops->say(cmd->client, conn,
1175 "%s", silc_client_command_status_message(status));
1176 COMMAND_REPLY_ERROR;
1180 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1182 COMMAND_REPLY_ERROR;
1186 SILC_GET32_MSB(mode, tmp);
1187 conn->local_entry->mode = mode;
1189 /* Notify application */
1190 COMMAND_REPLY((ARGS, mode));
1192 /* Execute any pending command callbacks */
1193 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1196 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1197 silc_client_command_reply_free(cmd);
1200 /* Received reply for CMODE command. */
1202 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1204 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1205 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1206 SilcCommandStatus status;
1209 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1210 if (status != SILC_STATUS_OK) {
1211 cmd->client->ops->say(cmd->client, conn,
1212 "%s", silc_client_command_status_message(status));
1213 COMMAND_REPLY_ERROR;
1217 /* Get channel mode */
1218 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1220 COMMAND_REPLY_ERROR;
1224 /* Notify application */
1225 COMMAND_REPLY((ARGS, tmp));
1227 /* Execute any pending command callbacks */
1228 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1231 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1232 silc_client_command_reply_free(cmd);
1235 /* Received reply for CUMODE command */
1237 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1239 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1240 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1241 SilcCommandStatus status;
1242 SilcIDCacheEntry id_cache = NULL;
1243 SilcClientID *client_id;
1244 unsigned char *tmp, *id;
1247 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1248 if (status != SILC_STATUS_OK) {
1249 cmd->client->ops->say(cmd->client, conn,
1250 "%s", silc_client_command_status_message(status));
1251 COMMAND_REPLY_ERROR;
1255 /* Get channel mode */
1256 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1258 COMMAND_REPLY_ERROR;
1263 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1265 COMMAND_REPLY_ERROR;
1268 client_id = silc_id_payload_parse_id(id, len);
1270 COMMAND_REPLY_ERROR;
1274 /* Get client entry */
1275 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1276 SILC_ID_CLIENT, &id_cache)) {
1277 COMMAND_REPLY_ERROR;
1281 /* Notify application */
1282 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1283 silc_free(client_id);
1285 /* Execute any pending command callbacks */
1286 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1289 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1290 silc_client_command_reply_free(cmd);
1293 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1295 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1296 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1297 SilcCommandStatus status;
1300 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1301 SILC_GET16_MSB(status, tmp);
1302 if (status != SILC_STATUS_OK) {
1303 cmd->client->ops->say(cmd->client, conn,
1304 "%s", silc_client_command_status_message(status));
1305 COMMAND_REPLY_ERROR;
1309 /* Notify application */
1310 COMMAND_REPLY((ARGS));
1312 /* Execute any pending command callbacks */
1313 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1316 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1317 silc_client_command_reply_free(cmd);
1320 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1322 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1323 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1324 SilcCommandStatus status;
1327 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1328 SILC_GET16_MSB(status, tmp);
1329 if (status != SILC_STATUS_OK) {
1330 cmd->client->ops->say(cmd->client, conn,
1331 "%s", silc_client_command_status_message(status));
1332 COMMAND_REPLY_ERROR;
1336 /* Notify application */
1337 COMMAND_REPLY((ARGS));
1339 /* Execute any pending command callbacks */
1340 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1343 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1344 silc_client_command_reply_free(cmd);
1347 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1349 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1350 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1351 SilcCommandStatus status;
1354 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1355 SILC_GET16_MSB(status, tmp);
1356 if (status != SILC_STATUS_OK) {
1357 cmd->client->ops->say(cmd->client, conn,
1358 "%s", silc_client_command_status_message(status));
1359 COMMAND_REPLY_ERROR;
1363 /* Notify application */
1364 COMMAND_REPLY((ARGS));
1366 /* Execute any pending command callbacks */
1367 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1370 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1371 silc_client_command_reply_free(cmd);
1374 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1376 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1377 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1378 SilcCommandStatus status;
1381 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1382 SILC_GET16_MSB(status, tmp);
1383 if (status != SILC_STATUS_OK) {
1384 cmd->client->ops->say(cmd->client, conn,
1385 "%s", silc_client_command_status_message(status));
1386 COMMAND_REPLY_ERROR;
1390 /* Notify application */
1391 COMMAND_REPLY((ARGS));
1393 /* Execute any pending command callbacks */
1394 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1397 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1398 silc_client_command_reply_free(cmd);
1401 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1403 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1404 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1405 SilcCommandStatus status;
1406 SilcIDCacheEntry id_cache = NULL;
1407 SilcChannelEntry channel;
1408 SilcChannelID *channel_id;
1412 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1413 SILC_GET16_MSB(status, tmp);
1414 if (status != SILC_STATUS_OK) {
1415 cmd->client->ops->say(cmd->client, conn,
1416 "%s", silc_client_command_status_message(status));
1417 COMMAND_REPLY_ERROR;
1421 /* Take Channel ID */
1422 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1426 channel_id = silc_id_payload_parse_id(tmp, len);
1430 /* Get the channel entry */
1431 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1432 SILC_ID_CHANNEL, &id_cache)) {
1433 silc_free(channel_id);
1434 COMMAND_REPLY_ERROR;
1438 channel = (SilcChannelEntry)id_cache->context;
1440 /* Get the ban list */
1441 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1443 /* Notify application */
1444 COMMAND_REPLY((ARGS, channel, tmp));
1446 /* Execute any pending command callbacks */
1447 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1450 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1451 silc_client_command_reply_free(cmd);
1454 SILC_CLIENT_CMD_REPLY_FUNC(close)
1456 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1457 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1458 SilcCommandStatus status;
1461 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1462 SILC_GET16_MSB(status, tmp);
1463 if (status != SILC_STATUS_OK) {
1464 cmd->client->ops->say(cmd->client, conn,
1465 "%s", silc_client_command_status_message(status));
1466 COMMAND_REPLY_ERROR;
1470 /* Notify application */
1471 COMMAND_REPLY((ARGS));
1473 /* Execute any pending command callbacks */
1474 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1477 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1478 silc_client_command_reply_free(cmd);
1481 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
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_SHUTDOWN);
1504 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1505 silc_client_command_reply_free(cmd);
1508 /* Reply to LEAVE command. */
1510 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1512 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1513 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1514 SilcCommandStatus status;
1517 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1518 SILC_GET16_MSB(status, tmp);
1519 if (status != SILC_STATUS_OK) {
1520 cmd->client->ops->say(cmd->client, conn,
1521 "%s", silc_client_command_status_message(status));
1522 COMMAND_REPLY_ERROR;
1526 /* Notify application */
1527 COMMAND_REPLY((ARGS));
1529 /* Execute any pending command callbacks */
1530 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1533 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1534 silc_client_command_reply_free(cmd);
1537 /* Reply to USERS command. Received list of client ID's and theirs modes
1538 on the channel we requested. */
1540 SILC_CLIENT_CMD_REPLY_FUNC(users)
1542 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1543 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1544 SilcCommandStatus status;
1545 SilcIDCacheEntry id_cache = NULL;
1546 SilcChannelEntry channel;
1547 SilcChannelUser chu;
1548 SilcChannelID *channel_id = NULL;
1549 SilcBuffer client_id_list;
1550 SilcBuffer client_mode_list;
1552 uint32 tmp_len, list_count;
1554 unsigned char **res_argv = NULL;
1555 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1557 SILC_LOG_DEBUG(("Start"));
1559 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1560 SILC_GET16_MSB(status, tmp);
1561 if (status != SILC_STATUS_OK) {
1562 cmd->client->ops->say(cmd->client, conn,
1563 "%s", silc_client_command_status_message(status));
1564 COMMAND_REPLY_ERROR;
1568 /* Get channel ID */
1569 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1572 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1576 /* Get the list count */
1577 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1580 SILC_GET32_MSB(list_count, tmp);
1582 /* Get Client ID list */
1583 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1587 client_id_list = silc_buffer_alloc(tmp_len);
1588 silc_buffer_pull_tail(client_id_list, tmp_len);
1589 silc_buffer_put(client_id_list, tmp, tmp_len);
1591 /* Get client mode list */
1592 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1596 client_mode_list = silc_buffer_alloc(tmp_len);
1597 silc_buffer_pull_tail(client_mode_list, tmp_len);
1598 silc_buffer_put(client_mode_list, tmp, tmp_len);
1600 /* Get channel entry */
1601 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1602 SILC_ID_CHANNEL, &id_cache)) {
1603 COMMAND_REPLY_ERROR;
1606 channel = (SilcChannelEntry)id_cache->context;
1608 /* Remove old client list from channel. */
1609 silc_list_start(channel->clients);
1610 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1611 silc_list_del(channel->clients, chu);
1615 /* Cache the received Client ID's and modes. This cache expires
1616 whenever server sends notify message to channel. It means two things;
1617 some user has joined or leaved the channel. XXX! */
1618 for (i = 0; i < list_count; i++) {
1621 SilcClientID *client_id;
1622 SilcClientEntry client;
1625 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1627 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1632 SILC_GET32_MSB(mode, client_mode_list->data);
1634 /* Check if we have this client cached already. */
1635 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1636 SILC_ID_CLIENT, &id_cache)) {
1637 /* No we don't have it, query it from the server. Assemble argument
1638 table that will be sent fr the IDENTIFY command later. */
1639 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1641 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1643 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1645 res_argv[res_argc] = client_id_list->data;
1646 res_argv_lens[res_argc] = idp_len;
1647 res_argv_types[res_argc] = res_argc + 3;
1650 /* Found the client, join it to the channel */
1651 client = (SilcClientEntry)id_cache->context;
1652 chu = silc_calloc(1, sizeof(*chu));
1653 chu->client = client;
1655 silc_list_add(channel->clients, chu);
1657 silc_free(client_id);
1661 silc_buffer_pull(client_id_list, idp_len);
1662 silc_buffer_pull(client_mode_list, 4);
1665 /* Query the client information from server if the list included clients
1666 that we don't know about. */
1670 /* Send the IDENTIFY command to server */
1671 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1672 res_argc, res_argv, res_argv_lens,
1673 res_argv_types, ++conn->cmd_ident);
1674 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1675 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1678 /* Register pending command callback. After we've received the IDENTIFY
1679 command reply we will reprocess this command reply by re-calling this
1680 USERS command reply callback. */
1681 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1682 NULL, silc_client_command_reply_users, cmd);
1684 silc_buffer_free(res_cmd);
1686 silc_free(channel_id);
1688 silc_free(res_argv);
1689 silc_free(res_argv_lens);
1690 silc_free(res_argv_types);
1694 /* Notify application */
1695 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1697 /* Execute any pending command callbacks */
1698 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1700 silc_buffer_free(client_id_list);
1701 silc_buffer_free(client_mode_list);
1705 silc_free(channel_id);
1706 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1707 silc_client_command_reply_free(cmd);
1710 /* Received command reply to GETKEY command. WE've received the remote
1711 client's public key. */
1713 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1715 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1716 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1717 SilcCommandStatus status;
1718 SilcIDCacheEntry id_cache;
1719 SilcIDPayload idp = NULL;
1720 SilcClientID *client_id = NULL;
1721 SilcClientEntry client_entry;
1723 unsigned char *tmp, *pk;
1727 SilcPublicKey public_key = NULL;
1729 SILC_LOG_DEBUG(("Start"));
1731 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1732 SILC_GET16_MSB(status, tmp);
1733 if (status != SILC_STATUS_OK) {
1734 cmd->client->ops->say(cmd->client, conn,
1735 "%s", silc_client_command_status_message(status));
1736 COMMAND_REPLY_ERROR;
1740 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1743 idp = silc_id_payload_parse_data(tmp, len);
1747 /* Get the public key payload */
1748 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1752 /* Decode the public key */
1754 SILC_GET16_MSB(pk_len, tmp);
1755 SILC_GET16_MSB(type, tmp + 2);
1758 if (type != SILC_SKE_PK_TYPE_SILC)
1761 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1764 id_type = silc_id_payload_get_type(idp);
1765 if (id_type == SILC_ID_CLIENT) {
1766 client_id = silc_id_payload_get_id(idp);
1768 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1769 SILC_ID_CLIENT, &id_cache))
1772 client_entry = (SilcClientEntry)id_cache->context;
1774 /* Notify application */
1775 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1776 } else if (id_type == SILC_ID_SERVER) {
1777 /* XXX we don't have server entries at all */
1784 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1786 silc_id_payload_free(idp);
1788 silc_pkcs_public_key_free(public_key);
1789 silc_free(client_id);
1790 silc_client_command_reply_free(cmd);