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,
1049 silc_hash_client_id_compare, NULL,
1051 /* No, we don't have it, add entry for it. */
1052 client_entry = silc_calloc(1, sizeof(*client_entry));
1053 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1054 silc_idcache_add(conn->client_cache, NULL, client_entry->id,
1055 (void *)client_entry, FALSE);
1057 /* Yes, we have it already */
1058 client_entry = (SilcClientEntry)id_cache->context;
1061 /* Join the client to the channel */
1062 chu = silc_calloc(1, sizeof(*chu));
1063 chu->client = client_entry;
1065 silc_list_add(channel->clients, chu);
1066 silc_free(client_id);
1068 silc_buffer_pull(client_id_list, idp_len);
1069 silc_buffer_pull(client_mode_list, 4);
1071 silc_buffer_push(client_id_list, client_id_list->data -
1072 client_id_list->head);
1073 silc_buffer_push(client_mode_list, client_mode_list->data -
1074 client_mode_list->head);
1076 /* Save channel key */
1077 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1078 silc_client_save_channel_key(conn, keyp, channel);
1080 /* Client is now joined to the channel */
1081 channel->on_channel = TRUE;
1083 /* Notify application */
1084 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1085 keyp ? keyp->head : NULL, NULL,
1086 NULL, topic, hmac, list_count, client_id_list,
1089 /* Execute any pending command callbacks */
1090 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1093 silc_buffer_free(keyp);
1094 silc_buffer_free(client_id_list);
1095 silc_buffer_free(client_mode_list);
1098 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1099 silc_client_command_reply_free(cmd);
1102 /* Received reply for MOTD command */
1104 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1106 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1107 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1108 SilcCommandStatus status;
1111 char *motd = NULL, *cp, line[256];
1113 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1114 SILC_GET16_MSB(status, tmp);
1115 if (status != SILC_STATUS_OK) {
1116 cmd->client->ops->say(cmd->client, conn,
1117 "%s", silc_client_command_status_message(status));
1118 COMMAND_REPLY_ERROR;
1122 argc = silc_argument_get_arg_num(cmd->args);
1124 COMMAND_REPLY_ERROR;
1129 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1131 COMMAND_REPLY_ERROR;
1138 if (cp[i++] == '\n') {
1139 memset(line, 0, sizeof(line));
1140 strncat(line, cp, i - 1);
1146 cmd->client->ops->say(cmd->client, conn, "%s", line);
1155 /* Notify application */
1156 COMMAND_REPLY((ARGS, motd));
1158 /* Execute any pending command callbacks */
1159 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1162 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1163 silc_client_command_reply_free(cmd);
1166 /* Received reply tot he UMODE command. Save the current user mode */
1168 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1170 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1171 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1172 SilcCommandStatus status;
1176 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1177 SILC_GET16_MSB(status, tmp);
1178 if (status != SILC_STATUS_OK) {
1179 cmd->client->ops->say(cmd->client, conn,
1180 "%s", silc_client_command_status_message(status));
1181 COMMAND_REPLY_ERROR;
1185 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1187 COMMAND_REPLY_ERROR;
1191 SILC_GET32_MSB(mode, tmp);
1192 conn->local_entry->mode = mode;
1194 /* Notify application */
1195 COMMAND_REPLY((ARGS, mode));
1197 /* Execute any pending command callbacks */
1198 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1201 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1202 silc_client_command_reply_free(cmd);
1205 /* Received reply for CMODE command. */
1207 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1209 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1210 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1211 SilcCommandStatus status;
1214 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1215 if (status != SILC_STATUS_OK) {
1216 cmd->client->ops->say(cmd->client, conn,
1217 "%s", silc_client_command_status_message(status));
1218 COMMAND_REPLY_ERROR;
1222 /* Get channel mode */
1223 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1225 COMMAND_REPLY_ERROR;
1229 /* Notify application */
1230 COMMAND_REPLY((ARGS, tmp));
1232 /* Execute any pending command callbacks */
1233 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1236 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1237 silc_client_command_reply_free(cmd);
1240 /* Received reply for CUMODE command */
1242 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1244 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1245 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1246 SilcCommandStatus status;
1247 SilcIDCacheEntry id_cache = NULL;
1248 SilcClientID *client_id;
1249 unsigned char *tmp, *id;
1252 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1253 if (status != SILC_STATUS_OK) {
1254 cmd->client->ops->say(cmd->client, conn,
1255 "%s", silc_client_command_status_message(status));
1256 COMMAND_REPLY_ERROR;
1260 /* Get channel mode */
1261 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1263 COMMAND_REPLY_ERROR;
1268 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1270 COMMAND_REPLY_ERROR;
1273 client_id = silc_id_payload_parse_id(id, len);
1275 COMMAND_REPLY_ERROR;
1279 /* Get client entry */
1280 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1282 silc_hash_client_id_compare, NULL,
1284 COMMAND_REPLY_ERROR;
1288 /* Notify application */
1289 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1290 silc_free(client_id);
1292 /* Execute any pending command callbacks */
1293 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1296 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1297 silc_client_command_reply_free(cmd);
1300 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1302 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1303 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1304 SilcCommandStatus status;
1307 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1308 SILC_GET16_MSB(status, tmp);
1309 if (status != SILC_STATUS_OK) {
1310 cmd->client->ops->say(cmd->client, conn,
1311 "%s", silc_client_command_status_message(status));
1312 COMMAND_REPLY_ERROR;
1316 /* Notify application */
1317 COMMAND_REPLY((ARGS));
1319 /* Execute any pending command callbacks */
1320 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1323 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1324 silc_client_command_reply_free(cmd);
1327 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1329 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1330 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1331 SilcCommandStatus status;
1334 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1335 SILC_GET16_MSB(status, tmp);
1336 if (status != SILC_STATUS_OK) {
1337 cmd->client->ops->say(cmd->client, conn,
1338 "%s", silc_client_command_status_message(status));
1339 COMMAND_REPLY_ERROR;
1343 /* Notify application */
1344 COMMAND_REPLY((ARGS));
1346 /* Execute any pending command callbacks */
1347 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1350 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1351 silc_client_command_reply_free(cmd);
1354 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1356 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1357 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1358 SilcCommandStatus status;
1361 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1362 SILC_GET16_MSB(status, tmp);
1363 if (status != SILC_STATUS_OK) {
1364 cmd->client->ops->say(cmd->client, conn,
1365 "%s", silc_client_command_status_message(status));
1366 COMMAND_REPLY_ERROR;
1370 /* Notify application */
1371 COMMAND_REPLY((ARGS));
1373 /* Execute any pending command callbacks */
1374 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1377 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1378 silc_client_command_reply_free(cmd);
1381 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1383 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1384 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1385 SilcCommandStatus status;
1388 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1389 SILC_GET16_MSB(status, tmp);
1390 if (status != SILC_STATUS_OK) {
1391 cmd->client->ops->say(cmd->client, conn,
1392 "%s", silc_client_command_status_message(status));
1393 COMMAND_REPLY_ERROR;
1397 /* Notify application */
1398 COMMAND_REPLY((ARGS));
1400 /* Execute any pending command callbacks */
1401 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1404 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1405 silc_client_command_reply_free(cmd);
1408 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1410 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1411 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1412 SilcCommandStatus status;
1413 SilcIDCacheEntry id_cache = NULL;
1414 SilcChannelEntry channel;
1415 SilcChannelID *channel_id;
1419 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1420 SILC_GET16_MSB(status, tmp);
1421 if (status != SILC_STATUS_OK) {
1422 cmd->client->ops->say(cmd->client, conn,
1423 "%s", silc_client_command_status_message(status));
1424 COMMAND_REPLY_ERROR;
1428 /* Take Channel ID */
1429 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1433 channel_id = silc_id_payload_parse_id(tmp, len);
1437 /* Get the channel entry */
1438 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1440 silc_free(channel_id);
1441 COMMAND_REPLY_ERROR;
1445 channel = (SilcChannelEntry)id_cache->context;
1447 /* Get the ban list */
1448 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1450 /* Notify application */
1451 COMMAND_REPLY((ARGS, channel, tmp));
1453 /* Execute any pending command callbacks */
1454 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1457 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1458 silc_client_command_reply_free(cmd);
1461 SILC_CLIENT_CMD_REPLY_FUNC(close)
1463 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1464 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1465 SilcCommandStatus status;
1468 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1469 SILC_GET16_MSB(status, tmp);
1470 if (status != SILC_STATUS_OK) {
1471 cmd->client->ops->say(cmd->client, conn,
1472 "%s", silc_client_command_status_message(status));
1473 COMMAND_REPLY_ERROR;
1477 /* Notify application */
1478 COMMAND_REPLY((ARGS));
1480 /* Execute any pending command callbacks */
1481 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1484 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1485 silc_client_command_reply_free(cmd);
1488 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1490 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1491 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1492 SilcCommandStatus status;
1495 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1496 SILC_GET16_MSB(status, tmp);
1497 if (status != SILC_STATUS_OK) {
1498 cmd->client->ops->say(cmd->client, conn,
1499 "%s", silc_client_command_status_message(status));
1500 COMMAND_REPLY_ERROR;
1504 /* Notify application */
1505 COMMAND_REPLY((ARGS));
1507 /* Execute any pending command callbacks */
1508 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1511 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1512 silc_client_command_reply_free(cmd);
1515 /* Reply to LEAVE command. */
1517 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1519 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1520 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1521 SilcCommandStatus status;
1524 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1525 SILC_GET16_MSB(status, tmp);
1526 if (status != SILC_STATUS_OK) {
1527 cmd->client->ops->say(cmd->client, conn,
1528 "%s", silc_client_command_status_message(status));
1529 COMMAND_REPLY_ERROR;
1533 /* Notify application */
1534 COMMAND_REPLY((ARGS));
1536 /* Execute any pending command callbacks */
1537 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1540 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1541 silc_client_command_reply_free(cmd);
1544 /* Reply to USERS command. Received list of client ID's and theirs modes
1545 on the channel we requested. */
1547 SILC_CLIENT_CMD_REPLY_FUNC(users)
1549 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1550 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1551 SilcCommandStatus status;
1552 SilcIDCacheEntry id_cache = NULL;
1553 SilcChannelEntry channel;
1554 SilcChannelUser chu;
1555 SilcChannelID *channel_id = NULL;
1556 SilcBuffer client_id_list;
1557 SilcBuffer client_mode_list;
1559 uint32 tmp_len, list_count;
1561 unsigned char **res_argv = NULL;
1562 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1564 SILC_LOG_DEBUG(("Start"));
1566 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1567 SILC_GET16_MSB(status, tmp);
1568 if (status != SILC_STATUS_OK) {
1569 cmd->client->ops->say(cmd->client, conn,
1570 "%s", silc_client_command_status_message(status));
1571 COMMAND_REPLY_ERROR;
1575 /* Get channel ID */
1576 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1579 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1583 /* Get the list count */
1584 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1587 SILC_GET32_MSB(list_count, tmp);
1589 /* Get Client ID list */
1590 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1594 client_id_list = silc_buffer_alloc(tmp_len);
1595 silc_buffer_pull_tail(client_id_list, tmp_len);
1596 silc_buffer_put(client_id_list, tmp, tmp_len);
1598 /* Get client mode list */
1599 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1603 client_mode_list = silc_buffer_alloc(tmp_len);
1604 silc_buffer_pull_tail(client_mode_list, tmp_len);
1605 silc_buffer_put(client_mode_list, tmp, tmp_len);
1607 /* Get channel entry */
1608 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1610 COMMAND_REPLY_ERROR;
1613 channel = (SilcChannelEntry)id_cache->context;
1615 /* Remove old client list from channel. */
1616 silc_list_start(channel->clients);
1617 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1618 silc_list_del(channel->clients, chu);
1622 /* Cache the received Client ID's and modes. This cache expires
1623 whenever server sends notify message to channel. It means two things;
1624 some user has joined or leaved the channel. XXX! */
1625 for (i = 0; i < list_count; i++) {
1628 SilcClientID *client_id;
1629 SilcClientEntry client;
1632 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1634 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1639 SILC_GET32_MSB(mode, client_mode_list->data);
1641 /* Check if we have this client cached already. */
1642 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1645 silc_hash_client_id_compare, NULL,
1647 /* No we don't have it, query it from the server. Assemble argument
1648 table that will be sent fr the IDENTIFY command later. */
1649 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1651 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1653 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1655 res_argv[res_argc] = client_id_list->data;
1656 res_argv_lens[res_argc] = idp_len;
1657 res_argv_types[res_argc] = res_argc + 3;
1660 /* Found the client, join it to the channel */
1661 client = (SilcClientEntry)id_cache->context;
1662 chu = silc_calloc(1, sizeof(*chu));
1663 chu->client = client;
1665 silc_list_add(channel->clients, chu);
1667 silc_free(client_id);
1671 silc_buffer_pull(client_id_list, idp_len);
1672 silc_buffer_pull(client_mode_list, 4);
1675 /* Query the client information from server if the list included clients
1676 that we don't know about. */
1680 /* Send the IDENTIFY command to server */
1681 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1682 res_argc, res_argv, res_argv_lens,
1683 res_argv_types, ++conn->cmd_ident);
1684 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1685 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1688 /* Register pending command callback. After we've received the IDENTIFY
1689 command reply we will reprocess this command reply by re-calling this
1690 USERS command reply callback. */
1691 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1692 NULL, silc_client_command_reply_users, cmd);
1694 silc_buffer_free(res_cmd);
1696 silc_free(channel_id);
1698 silc_free(res_argv);
1699 silc_free(res_argv_lens);
1700 silc_free(res_argv_types);
1704 /* Notify application */
1705 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1707 /* Execute any pending command callbacks */
1708 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1710 silc_buffer_free(client_id_list);
1711 silc_buffer_free(client_mode_list);
1715 silc_free(channel_id);
1716 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1717 silc_client_command_reply_free(cmd);
1720 /* Received command reply to GETKEY command. WE've received the remote
1721 client's public key. */
1723 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1725 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1726 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1727 SilcCommandStatus status;
1728 SilcIDCacheEntry id_cache;
1729 SilcIDPayload idp = NULL;
1730 SilcClientID *client_id = NULL;
1731 SilcClientEntry client_entry;
1733 unsigned char *tmp, *pk;
1737 SilcPublicKey public_key = NULL;
1739 SILC_LOG_DEBUG(("Start"));
1741 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1742 SILC_GET16_MSB(status, tmp);
1743 if (status != SILC_STATUS_OK) {
1744 cmd->client->ops->say(cmd->client, conn,
1745 "%s", silc_client_command_status_message(status));
1746 COMMAND_REPLY_ERROR;
1750 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1753 idp = silc_id_payload_parse_data(tmp, len);
1757 /* Get the public key payload */
1758 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1762 /* Decode the public key */
1764 SILC_GET16_MSB(pk_len, tmp);
1765 SILC_GET16_MSB(type, tmp + 2);
1768 if (type != SILC_SKE_PK_TYPE_SILC)
1771 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1774 id_type = silc_id_payload_get_type(idp);
1775 if (id_type == SILC_ID_CLIENT) {
1776 client_id = silc_id_payload_get_id(idp);
1778 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1781 silc_hash_client_id_compare, NULL,
1785 client_entry = (SilcClientEntry)id_cache->context;
1787 /* Notify application */
1788 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1789 } else if (id_type == SILC_ID_SERVER) {
1790 /* XXX we don't have server entries at all */
1797 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1799 silc_id_payload_free(idp);
1801 silc_pkcs_public_key_free(public_key);
1802 silc_free(client_id);
1803 silc_client_command_reply_free(cmd);