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_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, "Cannot set nickname: %s",
568 silc_client_command_status_message(status));
573 argc = silc_argument_get_arg_num(cmd->args);
574 if (argc < 2 || argc > 2) {
575 cmd->client->ops->say(cmd->client, conn,
576 "Cannot set nickname: bad reply to command");
581 /* Take received Client ID */
582 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
583 idp = silc_id_payload_parse_data(tmp, len);
588 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
590 /* Notify application */
591 COMMAND_REPLY((ARGS, conn->local_entry));
593 /* Execute any pending command callbacks */
594 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
597 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
598 silc_client_command_reply_free(cmd);
601 /* Received reply to the LIST command. */
603 SILC_CLIENT_CMD_REPLY_FUNC(list)
605 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
606 SilcCommandStatus status;
607 unsigned char *tmp, *name, *topic;
608 uint32 usercount = 0;
610 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
611 SILC_GET16_MSB(status, tmp);
612 if (status != SILC_STATUS_OK &&
613 status != SILC_STATUS_LIST_START &&
614 status != SILC_STATUS_LIST_ITEM &&
615 status != SILC_STATUS_LIST_END) {
620 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
621 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
622 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
624 SILC_GET32_MSB(usercount, tmp);
626 /* Notify application */
627 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
629 /* Pending callbacks are not executed if this was an list entry */
630 if (status != SILC_STATUS_OK &&
631 status != SILC_STATUS_LIST_END) {
632 silc_client_command_reply_free(cmd);
636 /* Execute any pending command callbacks */
637 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
640 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
641 silc_client_command_reply_free(cmd);
644 /* Received reply to topic command. */
646 SILC_CLIENT_CMD_REPLY_FUNC(topic)
648 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
649 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
650 SilcCommandStatus status;
651 SilcChannelEntry channel;
652 SilcChannelID *channel_id = NULL;
653 SilcIDCacheEntry id_cache = NULL;
658 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
659 if (status != SILC_STATUS_OK) {
660 cmd->client->ops->say(cmd->client, conn,
661 "%s", silc_client_command_status_message(status));
663 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
664 silc_client_command_reply_free(cmd);
668 argc = silc_argument_get_arg_num(cmd->args);
669 if (argc < 1 || argc > 3) {
674 /* Take Channel ID */
675 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
680 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
684 channel_id = silc_id_payload_parse_id(tmp, len);
688 /* Get the channel entry */
689 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
691 silc_free(channel_id);
696 channel = (SilcChannelEntry)id_cache->context;
698 cmd->client->ops->say(cmd->client, conn,
699 "Topic on channel %s: %s", channel->channel_name,
702 /* Notify application */
703 COMMAND_REPLY((ARGS, channel, topic));
705 /* Execute any pending command callbacks */
706 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
709 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
710 silc_client_command_reply_free(cmd);
713 /* Received reply to invite command. */
715 SILC_CLIENT_CMD_REPLY_FUNC(invite)
717 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
718 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
719 SilcCommandStatus status;
720 SilcChannelEntry channel;
721 SilcChannelID *channel_id;
722 SilcIDCacheEntry id_cache;
726 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
727 SILC_GET16_MSB(status, tmp);
728 if (status != SILC_STATUS_OK) {
729 cmd->client->ops->say(cmd->client, conn,
730 "%s", silc_client_command_status_message(status));
732 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
733 silc_client_command_reply_free(cmd);
737 /* Take Channel ID */
738 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
742 channel_id = silc_id_payload_parse_id(tmp, len);
746 /* Get the channel entry */
747 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
749 silc_free(channel_id);
754 channel = (SilcChannelEntry)id_cache->context;
756 /* Get the invite list */
757 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
759 /* Notify application */
760 COMMAND_REPLY((ARGS, channel, tmp));
762 /* Execute any pending command callbacks */
763 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
766 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
767 silc_client_command_reply_free(cmd);
770 /* Received reply to the KILL command. */
772 SILC_CLIENT_CMD_REPLY_FUNC(kill)
774 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
775 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
776 SilcCommandStatus status;
779 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
780 SILC_GET16_MSB(status, tmp);
781 if (status != SILC_STATUS_OK) {
782 cmd->client->ops->say(cmd->client, conn,
783 "%s", silc_client_command_status_message(status));
788 /* Notify application */
789 COMMAND_REPLY((ARGS));
791 /* Execute any pending command callbacks */
792 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
795 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
796 silc_client_command_reply_free(cmd);
799 /* Received reply to INFO command. We receive the server ID and some
800 information about the server user requested. */
802 SILC_CLIENT_CMD_REPLY_FUNC(info)
804 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
805 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
806 SilcClient client = cmd->client;
807 SilcCommandStatus status;
810 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
811 SILC_GET16_MSB(status, tmp);
812 if (status != SILC_STATUS_OK) {
813 cmd->client->ops->say(cmd->client, conn,
814 "%s", silc_client_command_status_message(status));
816 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
817 silc_client_command_reply_free(cmd);
822 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
826 /* XXX save server id */
828 /* Get server name */
829 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
833 /* Get server info */
834 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
838 client->ops->say(cmd->client, conn, "Info: %s", tmp);
840 /* Notify application */
841 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
843 /* Execute any pending command callbacks */
844 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
847 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
848 silc_client_command_reply_free(cmd);
851 /* Received reply to PING command. The reply time is shown to user. */
853 SILC_CLIENT_CMD_REPLY_FUNC(ping)
855 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
856 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
857 SilcCommandStatus status;
860 time_t diff, curtime;
862 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
863 if (status != SILC_STATUS_OK) {
864 cmd->client->ops->say(cmd->client, conn,
865 "%s", silc_client_command_status_message(status));
870 curtime = time(NULL);
871 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
872 cmd->packet->src_id_type);
878 for (i = 0; i < conn->ping_count; i++) {
879 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
880 diff = curtime - conn->ping[i].start_time;
881 cmd->client->ops->say(cmd->client, conn,
882 "Ping reply from %s: %d second%s",
883 conn->ping[i].dest_name, diff,
884 diff == 1 ? "" : "s");
886 conn->ping[i].start_time = 0;
887 silc_free(conn->ping[i].dest_id);
888 conn->ping[i].dest_id = NULL;
889 silc_free(conn->ping[i].dest_name);
890 conn->ping[i].dest_name = NULL;
897 /* Notify application */
898 COMMAND_REPLY((ARGS));
900 /* Execute any pending command callbacks */
901 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
904 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
905 silc_client_command_reply_free(cmd);
908 /* Received reply for JOIN command. */
910 SILC_CLIENT_CMD_REPLY_FUNC(join)
912 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
913 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
914 SilcCommandStatus status;
915 SilcIDPayload idp = NULL;
916 SilcChannelEntry channel;
917 SilcIDCacheEntry id_cache = NULL;
919 uint32 argc, mode, len, list_count;
920 char *topic, *tmp, *channel_name = NULL, *hmac;
921 SilcBuffer keyp = NULL, client_id_list, client_mode_list;
924 SILC_LOG_DEBUG(("Start"));
926 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
927 if (status != SILC_STATUS_OK) {
928 cmd->client->ops->say(cmd->client, conn,
929 "%s", silc_client_command_status_message(status));
934 argc = silc_argument_get_arg_num(cmd->args);
935 if (argc < 7 || argc > 14) {
936 cmd->client->ops->say(cmd->client, conn,
937 "Cannot join channel: Bad reply packet");
942 /* Get channel name */
943 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
945 cmd->client->ops->say(cmd->client, conn,
946 "Cannot join channel: Bad reply packet");
950 channel_name = strdup(tmp);
953 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
955 cmd->client->ops->say(cmd->client, conn,
956 "Cannot join channel: Bad reply packet");
958 silc_free(channel_name);
961 idp = silc_id_payload_parse_data(tmp, len);
964 silc_free(channel_name);
968 /* Get channel mode */
969 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
971 SILC_GET32_MSB(mode, tmp);
975 /* Get channel key */
976 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
978 keyp = silc_buffer_alloc(len);
979 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
980 silc_buffer_put(keyp, tmp, len);
984 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
986 /* Save received Channel ID. This actually creates the channel */
987 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
989 silc_id_payload_free(idp);
992 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
994 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
995 cmd->client->ops->say(cmd->client, conn,
996 "Cannot join channel: Unsupported HMAC `%s'",
999 silc_free(channel_name);
1004 /* Get the list count */
1005 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1008 SILC_GET32_MSB(list_count, tmp);
1010 /* Get Client ID list */
1011 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1015 client_id_list = silc_buffer_alloc(len);
1016 silc_buffer_pull_tail(client_id_list, len);
1017 silc_buffer_put(client_id_list, tmp, len);
1019 /* Get client mode list */
1020 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1024 client_mode_list = silc_buffer_alloc(len);
1025 silc_buffer_pull_tail(client_mode_list, len);
1026 silc_buffer_put(client_mode_list, tmp, len);
1028 /* Add clients we received in the reply to the channel */
1029 for (i = 0; i < list_count; i++) {
1032 SilcClientID *client_id;
1033 SilcClientEntry client_entry;
1036 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1038 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1043 SILC_GET32_MSB(mode, client_mode_list->data);
1045 /* Check if we have this client cached already. */
1046 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1048 silc_hash_client_id_compare, NULL,
1050 /* No, we don't have it, add entry for it. */
1051 client_entry = silc_calloc(1, sizeof(*client_entry));
1052 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1053 silc_idcache_add(conn->client_cache, NULL, client_entry->id,
1054 (void *)client_entry, FALSE);
1056 /* Yes, we have it already */
1057 client_entry = (SilcClientEntry)id_cache->context;
1060 /* Join the client to the channel */
1061 chu = silc_calloc(1, sizeof(*chu));
1062 chu->client = client_entry;
1064 silc_list_add(channel->clients, chu);
1065 silc_free(client_id);
1067 silc_buffer_pull(client_id_list, idp_len);
1068 silc_buffer_pull(client_mode_list, 4);
1070 silc_buffer_push(client_id_list, client_id_list->data -
1071 client_id_list->head);
1072 silc_buffer_push(client_mode_list, client_mode_list->data -
1073 client_mode_list->head);
1075 /* Save channel key */
1076 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1077 silc_client_save_channel_key(conn, keyp, channel);
1079 /* Client is now joined to the channel */
1080 channel->on_channel = TRUE;
1082 /* Notify application */
1083 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1084 keyp ? keyp->head : NULL, NULL,
1085 NULL, topic, hmac, list_count, client_id_list,
1088 /* Execute any pending command callbacks */
1089 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1092 silc_buffer_free(keyp);
1093 silc_buffer_free(client_id_list);
1094 silc_buffer_free(client_mode_list);
1097 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1098 silc_client_command_reply_free(cmd);
1101 /* Received reply for MOTD command */
1103 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1105 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1106 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1107 SilcCommandStatus status;
1110 char *motd = NULL, *cp, line[256];
1112 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1113 SILC_GET16_MSB(status, tmp);
1114 if (status != SILC_STATUS_OK) {
1115 cmd->client->ops->say(cmd->client, conn,
1116 "%s", silc_client_command_status_message(status));
1117 COMMAND_REPLY_ERROR;
1121 argc = silc_argument_get_arg_num(cmd->args);
1123 COMMAND_REPLY_ERROR;
1128 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1130 COMMAND_REPLY_ERROR;
1137 if (cp[i++] == '\n') {
1138 memset(line, 0, sizeof(line));
1139 strncat(line, cp, i - 1);
1145 cmd->client->ops->say(cmd->client, conn, "%s", line);
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,
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;
1213 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1214 if (status != SILC_STATUS_OK) {
1215 cmd->client->ops->say(cmd->client, conn,
1216 "%s", silc_client_command_status_message(status));
1217 COMMAND_REPLY_ERROR;
1221 /* Get channel mode */
1222 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1224 COMMAND_REPLY_ERROR;
1228 /* Notify application */
1229 COMMAND_REPLY((ARGS, tmp));
1231 /* Execute any pending command callbacks */
1232 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1235 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1236 silc_client_command_reply_free(cmd);
1239 /* Received reply for CUMODE command */
1241 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1243 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1244 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1245 SilcCommandStatus status;
1246 SilcIDCacheEntry id_cache = NULL;
1247 SilcClientID *client_id;
1248 unsigned char *tmp, *id;
1251 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1252 if (status != SILC_STATUS_OK) {
1253 cmd->client->ops->say(cmd->client, conn,
1254 "%s", silc_client_command_status_message(status));
1255 COMMAND_REPLY_ERROR;
1259 /* Get channel mode */
1260 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1262 COMMAND_REPLY_ERROR;
1267 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1269 COMMAND_REPLY_ERROR;
1272 client_id = silc_id_payload_parse_id(id, len);
1274 COMMAND_REPLY_ERROR;
1278 /* Get client entry */
1279 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1281 silc_hash_client_id_compare, NULL,
1283 COMMAND_REPLY_ERROR;
1287 /* Notify application */
1288 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1289 silc_free(client_id);
1291 /* Execute any pending command callbacks */
1292 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1295 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1296 silc_client_command_reply_free(cmd);
1299 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1301 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1302 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1303 SilcCommandStatus status;
1306 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1307 SILC_GET16_MSB(status, tmp);
1308 if (status != SILC_STATUS_OK) {
1309 cmd->client->ops->say(cmd->client, conn,
1310 "%s", silc_client_command_status_message(status));
1311 COMMAND_REPLY_ERROR;
1315 /* Notify application */
1316 COMMAND_REPLY((ARGS));
1318 /* Execute any pending command callbacks */
1319 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1322 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1323 silc_client_command_reply_free(cmd);
1326 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1328 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1329 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1330 SilcCommandStatus status;
1333 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1334 SILC_GET16_MSB(status, tmp);
1335 if (status != SILC_STATUS_OK) {
1336 cmd->client->ops->say(cmd->client, conn,
1337 "%s", silc_client_command_status_message(status));
1338 COMMAND_REPLY_ERROR;
1342 /* Notify application */
1343 COMMAND_REPLY((ARGS));
1345 /* Execute any pending command callbacks */
1346 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1349 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1350 silc_client_command_reply_free(cmd);
1353 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1355 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1356 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1357 SilcCommandStatus status;
1360 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1361 SILC_GET16_MSB(status, tmp);
1362 if (status != SILC_STATUS_OK) {
1363 cmd->client->ops->say(cmd->client, conn,
1364 "%s", silc_client_command_status_message(status));
1365 COMMAND_REPLY_ERROR;
1369 /* Notify application */
1370 COMMAND_REPLY((ARGS));
1372 /* Execute any pending command callbacks */
1373 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1376 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1377 silc_client_command_reply_free(cmd);
1380 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1382 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1383 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1384 SilcCommandStatus status;
1387 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1388 SILC_GET16_MSB(status, tmp);
1389 if (status != SILC_STATUS_OK) {
1390 cmd->client->ops->say(cmd->client, conn,
1391 "%s", silc_client_command_status_message(status));
1392 COMMAND_REPLY_ERROR;
1396 /* Notify application */
1397 COMMAND_REPLY((ARGS));
1399 /* Execute any pending command callbacks */
1400 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1403 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1404 silc_client_command_reply_free(cmd);
1407 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1409 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1410 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1411 SilcCommandStatus status;
1412 SilcIDCacheEntry id_cache = NULL;
1413 SilcChannelEntry channel;
1414 SilcChannelID *channel_id;
1418 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1419 SILC_GET16_MSB(status, tmp);
1420 if (status != SILC_STATUS_OK) {
1421 cmd->client->ops->say(cmd->client, conn,
1422 "%s", silc_client_command_status_message(status));
1423 COMMAND_REPLY_ERROR;
1427 /* Take Channel ID */
1428 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1432 channel_id = silc_id_payload_parse_id(tmp, len);
1436 /* Get the channel entry */
1437 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1439 silc_free(channel_id);
1440 COMMAND_REPLY_ERROR;
1444 channel = (SilcChannelEntry)id_cache->context;
1446 /* Get the ban list */
1447 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1449 /* Notify application */
1450 COMMAND_REPLY((ARGS, channel, tmp));
1452 /* Execute any pending command callbacks */
1453 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1456 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1457 silc_client_command_reply_free(cmd);
1460 SILC_CLIENT_CMD_REPLY_FUNC(close)
1462 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1463 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1464 SilcCommandStatus status;
1467 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1468 SILC_GET16_MSB(status, tmp);
1469 if (status != SILC_STATUS_OK) {
1470 cmd->client->ops->say(cmd->client, conn,
1471 "%s", silc_client_command_status_message(status));
1472 COMMAND_REPLY_ERROR;
1476 /* Notify application */
1477 COMMAND_REPLY((ARGS));
1479 /* Execute any pending command callbacks */
1480 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1483 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1484 silc_client_command_reply_free(cmd);
1487 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1489 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1490 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1491 SilcCommandStatus status;
1494 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1495 SILC_GET16_MSB(status, tmp);
1496 if (status != SILC_STATUS_OK) {
1497 cmd->client->ops->say(cmd->client, conn,
1498 "%s", silc_client_command_status_message(status));
1499 COMMAND_REPLY_ERROR;
1503 /* Notify application */
1504 COMMAND_REPLY((ARGS));
1506 /* Execute any pending command callbacks */
1507 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1510 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1511 silc_client_command_reply_free(cmd);
1514 /* Reply to LEAVE command. */
1516 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1518 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1519 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1520 SilcCommandStatus status;
1523 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1524 SILC_GET16_MSB(status, tmp);
1525 if (status != SILC_STATUS_OK) {
1526 cmd->client->ops->say(cmd->client, conn,
1527 "%s", silc_client_command_status_message(status));
1528 COMMAND_REPLY_ERROR;
1532 /* Notify application */
1533 COMMAND_REPLY((ARGS));
1535 /* Execute any pending command callbacks */
1536 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1539 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1540 silc_client_command_reply_free(cmd);
1543 /* Reply to USERS command. Received list of client ID's and theirs modes
1544 on the channel we requested. */
1546 SILC_CLIENT_CMD_REPLY_FUNC(users)
1548 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1549 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1550 SilcCommandStatus status;
1551 SilcIDCacheEntry id_cache = NULL;
1552 SilcChannelEntry channel;
1553 SilcChannelUser chu;
1554 SilcChannelID *channel_id = NULL;
1555 SilcBuffer client_id_list;
1556 SilcBuffer client_mode_list;
1558 uint32 tmp_len, list_count;
1560 unsigned char **res_argv = NULL;
1561 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1563 SILC_LOG_DEBUG(("Start"));
1565 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1566 SILC_GET16_MSB(status, tmp);
1567 if (status != SILC_STATUS_OK) {
1568 cmd->client->ops->say(cmd->client, conn,
1569 "%s", silc_client_command_status_message(status));
1570 COMMAND_REPLY_ERROR;
1574 /* Get channel ID */
1575 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1578 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1582 /* Get the list count */
1583 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1586 SILC_GET32_MSB(list_count, tmp);
1588 /* Get Client ID list */
1589 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1593 client_id_list = silc_buffer_alloc(tmp_len);
1594 silc_buffer_pull_tail(client_id_list, tmp_len);
1595 silc_buffer_put(client_id_list, tmp, tmp_len);
1597 /* Get client mode list */
1598 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1602 client_mode_list = silc_buffer_alloc(tmp_len);
1603 silc_buffer_pull_tail(client_mode_list, tmp_len);
1604 silc_buffer_put(client_mode_list, tmp, tmp_len);
1606 /* Get channel entry */
1607 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1609 COMMAND_REPLY_ERROR;
1612 channel = (SilcChannelEntry)id_cache->context;
1614 /* Remove old client list from channel. */
1615 silc_list_start(channel->clients);
1616 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1617 silc_list_del(channel->clients, chu);
1621 /* Cache the received Client ID's and modes. This cache expires
1622 whenever server sends notify message to channel. It means two things;
1623 some user has joined or leaved the channel. XXX! */
1624 for (i = 0; i < list_count; i++) {
1627 SilcClientID *client_id;
1628 SilcClientEntry client;
1631 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1633 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1638 SILC_GET32_MSB(mode, client_mode_list->data);
1640 /* Check if we have this client cached already. */
1641 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1643 silc_hash_client_id_compare, NULL,
1645 /* No we don't have it, query it from the server. Assemble argument
1646 table that will be sent fr the IDENTIFY command later. */
1647 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1649 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1651 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1653 res_argv[res_argc] = client_id_list->data;
1654 res_argv_lens[res_argc] = idp_len;
1655 res_argv_types[res_argc] = res_argc + 3;
1658 /* Found the client, join it to the channel */
1659 client = (SilcClientEntry)id_cache->context;
1660 chu = silc_calloc(1, sizeof(*chu));
1661 chu->client = client;
1663 silc_list_add(channel->clients, chu);
1665 silc_free(client_id);
1669 silc_buffer_pull(client_id_list, idp_len);
1670 silc_buffer_pull(client_mode_list, 4);
1673 /* Query the client information from server if the list included clients
1674 that we don't know about. */
1678 /* Send the IDENTIFY command to server */
1679 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1680 res_argc, res_argv, res_argv_lens,
1681 res_argv_types, ++conn->cmd_ident);
1682 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1683 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1686 /* Register pending command callback. After we've received the IDENTIFY
1687 command reply we will reprocess this command reply by re-calling this
1688 USERS command reply callback. */
1689 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1690 NULL, silc_client_command_reply_users, cmd);
1692 silc_buffer_free(res_cmd);
1694 silc_free(channel_id);
1696 silc_free(res_argv);
1697 silc_free(res_argv_lens);
1698 silc_free(res_argv_types);
1702 /* Notify application */
1703 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1705 /* Execute any pending command callbacks */
1706 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1708 silc_buffer_free(client_id_list);
1709 silc_buffer_free(client_mode_list);
1713 silc_free(channel_id);
1714 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1715 silc_client_command_reply_free(cmd);
1718 /* Received command reply to GETKEY command. WE've received the remote
1719 client's public key. */
1721 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1723 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1724 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1725 SilcCommandStatus status;
1726 SilcIDCacheEntry id_cache;
1727 SilcIDPayload idp = NULL;
1728 SilcClientID *client_id = NULL;
1729 SilcClientEntry client_entry;
1731 unsigned char *tmp, *pk;
1735 SilcPublicKey public_key = NULL;
1737 SILC_LOG_DEBUG(("Start"));
1739 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1740 SILC_GET16_MSB(status, tmp);
1741 if (status != SILC_STATUS_OK) {
1742 cmd->client->ops->say(cmd->client, conn,
1743 "%s", silc_client_command_status_message(status));
1744 COMMAND_REPLY_ERROR;
1748 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1751 idp = silc_id_payload_parse_data(tmp, len);
1755 /* Get the public key payload */
1756 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1760 /* Decode the public key */
1762 SILC_GET16_MSB(pk_len, tmp);
1763 SILC_GET16_MSB(type, tmp + 2);
1766 if (type != SILC_SKE_PK_TYPE_SILC)
1769 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1772 id_type = silc_id_payload_get_type(idp);
1773 if (id_type == SILC_ID_CLIENT) {
1774 client_id = silc_id_payload_get_id(idp);
1776 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1778 silc_hash_client_id_compare, NULL,
1782 client_entry = (SilcClientEntry)id_cache->context;
1784 /* Notify application */
1785 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1786 } else if (id_type == SILC_ID_SERVER) {
1787 /* XXX we don't have server entries at all */
1794 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1796 silc_id_payload_free(idp);
1798 silc_pkcs_public_key_free(public_key);
1799 silc_free(client_id);
1800 silc_client_command_reply_free(cmd);