5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 * Command reply functions are "the otherside" of the command functions.
22 * Reply to a command sent by server is handled by these functions.
24 * The arguments received from server are also passed to the calling
25 * application through command_reply client operation. The arguments are
26 * exactly same and in same order as the server sent it. However, ID's are
27 * not sent to the application. Instead, corresponding ID entry is sent
28 * to the application. For example, instead of sending Client ID the
29 * corresponding SilcClientEntry is sent to the application. The case is
30 * same with for example Channel ID's. This way application has all the
31 * necessary data already in hand without redundant searching. If ID is
32 * received but ID entry does not exist, NULL is sent.
36 #include "clientlibincludes.h"
37 #include "client_internal.h"
39 /* Client command reply list. */
40 SilcClientCommandReply silc_command_reply_list[] =
42 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
43 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
44 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
45 SILC_CLIENT_CMD_REPLY(nick, NICK),
46 SILC_CLIENT_CMD_REPLY(list, LIST),
47 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
48 SILC_CLIENT_CMD_REPLY(invite, INVITE),
49 SILC_CLIENT_CMD_REPLY(kill, KILL),
50 SILC_CLIENT_CMD_REPLY(info, INFO),
51 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
52 SILC_CLIENT_CMD_REPLY(ping, PING),
53 SILC_CLIENT_CMD_REPLY(oper, OPER),
54 SILC_CLIENT_CMD_REPLY(join, JOIN),
55 SILC_CLIENT_CMD_REPLY(motd, MOTD),
56 SILC_CLIENT_CMD_REPLY(umode, UMODE),
57 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
58 SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
59 SILC_CLIENT_CMD_REPLY(kick, KICK),
60 SILC_CLIENT_CMD_REPLY(ban, BAN),
61 SILC_CLIENT_CMD_REPLY(close, CLOSE),
62 SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN),
63 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
64 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
65 SILC_CLIENT_CMD_REPLY(users, USERS),
66 SILC_CLIENT_CMD_REPLY(getkey, GETKEY),
71 const SilcCommandStatusMessage silc_command_status_messages[] = {
73 { STAT(NO_SUCH_NICK), "There was no such nickname" },
74 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
75 { STAT(NO_SUCH_SERVER), "No such server" },
76 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
77 { STAT(NO_RECIPIENT), "No recipient given" },
78 { STAT(UNKNOWN_COMMAND), "Unknown command" },
79 { STAT(WILDCARDS), "Unknown command" },
80 { STAT(NO_CLIENT_ID), "No Client ID given" },
81 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
82 { STAT(NO_SERVER_ID), "No Server ID given" },
83 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
84 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
85 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
86 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
87 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
88 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
89 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
90 { STAT(USER_ON_CHANNEL), "User already on the channel" },
91 { STAT(NOT_REGISTERED), "You have not registered" },
92 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
93 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
94 { STAT(PERM_DENIED), "Permission denied" },
95 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
96 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
97 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
98 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
99 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
100 { STAT(UNKNOWN_MODE), "Unknown mode" },
101 { STAT(NOT_YOU), "Cannot change mode for other users" },
102 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
103 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
104 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
105 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
106 { STAT(BAD_NICKNAME), "Bad nickname" },
107 { STAT(BAD_CHANNEL), "Bad channel name" },
108 { STAT(AUTH_FAILED), "Authentication failed" },
109 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
110 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
114 /* Command reply operation that is called at the end of all command replys.
115 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
116 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
117 #define ARGS cmd->client, cmd->sock->user_data, \
118 cmd->payload, TRUE, silc_command_get(cmd->payload), status
120 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
121 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
122 cmd->sock->user_data, cmd->payload, FALSE, \
123 silc_command_get(cmd->payload), status)
125 /* Process received command reply. */
127 void silc_client_command_reply_process(SilcClient client,
128 SilcSocketConnection sock,
129 SilcPacketContext *packet)
131 SilcBuffer buffer = packet->buffer;
132 SilcClientCommandReply *cmd;
133 SilcClientCommandReplyContext ctx;
134 SilcCommandPayload payload;
138 /* Get command reply payload from packet */
139 payload = silc_command_payload_parse(buffer);
141 /* Silently ignore bad reply packet */
142 SILC_LOG_DEBUG(("Bad command reply packet"));
146 /* Allocate command reply context. This must be free'd by the
147 command reply routine receiving it. */
148 ctx = silc_calloc(1, sizeof(*ctx));
149 ctx->client = client;
151 ctx->payload = payload;
152 ctx->args = silc_command_get_args(ctx->payload);
153 ctx->packet = packet;
154 ident = silc_command_get_ident(ctx->payload);
156 /* Check for pending commands and mark to be exeucted */
157 silc_client_command_pending_check(sock->user_data, ctx,
158 silc_command_get(ctx->payload), ident);
160 /* Execute command reply */
161 command = silc_command_get(ctx->payload);
162 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
163 if (cmd->cmd == command)
166 if (cmd == NULL || !cmd->cb) {
174 /* Returns status message string */
176 char *silc_client_command_status_message(SilcCommandStatus status)
180 for (i = 0; silc_command_status_messages[i].message; i++) {
181 if (silc_command_status_messages[i].status == status)
185 if (silc_command_status_messages[i].message == NULL)
188 return silc_command_status_messages[i].message;
191 /* Free command reply context and its internals. */
193 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
196 silc_command_payload_free(cmd->payload);
202 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
203 SilcCommandStatus status)
205 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
206 SilcClientID *client_id;
207 SilcIDCacheEntry id_cache = NULL;
208 SilcClientEntry client_entry = NULL;
211 unsigned char *id_data, *tmp;
212 char *nickname = NULL, *username = NULL;
213 char *realname = NULL;
214 uint32 idle = 0, mode = 0;
215 SilcBuffer channels = NULL;
217 argc = silc_argument_get_arg_num(cmd->args);
219 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
225 client_id = silc_id_payload_parse_id(id_data, len);
231 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
232 username = silc_argument_get_arg_type(cmd->args, 4, &len);
233 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
234 if (!nickname || !username || !realname) {
239 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
241 channels = silc_buffer_alloc(len);
242 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
243 silc_buffer_put(channels, tmp, len);
246 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
248 SILC_GET32_MSB(mode, tmp);
250 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
252 SILC_GET32_MSB(idle, tmp);
254 /* Check if we have this client cached already. */
255 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
257 silc_hash_client_id_compare, NULL,
259 SILC_LOG_DEBUG(("Adding new client entry"));
261 silc_client_add_client(cmd->client, conn, nickname, username, realname,
264 client_entry = (SilcClientEntry)id_cache->context;
265 silc_client_update_client(cmd->client, conn, client_entry,
266 nickname, username, realname, mode);
267 silc_free(client_id);
270 /* Notify application */
272 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
273 channels, mode, idle));
276 silc_buffer_free(channels);
279 /* Received reply for WHOIS command. This maybe called several times
280 for one WHOIS command as server may reply with list of results. */
282 SILC_CLIENT_CMD_REPLY_FUNC(whois)
284 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
285 SilcCommandStatus status;
288 SILC_LOG_DEBUG(("Start"));
290 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
291 SILC_GET16_MSB(status, tmp);
292 if (status != SILC_STATUS_OK &&
293 status != SILC_STATUS_LIST_START &&
294 status != SILC_STATUS_LIST_ITEM &&
295 status != SILC_STATUS_LIST_END) {
300 /* Display one whois reply */
301 if (status == SILC_STATUS_OK)
302 silc_client_command_reply_whois_save(cmd, status);
305 if (status == SILC_STATUS_LIST_START ||
306 status == SILC_STATUS_LIST_ITEM ||
307 status == SILC_STATUS_LIST_END)
308 silc_client_command_reply_whois_save(cmd, status);
310 /* Pending callbacks are not executed if this was an list entry */
311 if (status != SILC_STATUS_OK &&
312 status != SILC_STATUS_LIST_END) {
313 silc_client_command_reply_free(cmd);
317 /* Execute any pending command callbacks */
318 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
321 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
322 silc_client_command_reply_free(cmd);
325 /* Received reply for WHOWAS command. */
327 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
329 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
330 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
331 SilcCommandStatus status;
332 SilcClientID *client_id;
333 SilcIDCacheEntry id_cache = NULL;
334 SilcClientEntry client_entry = NULL;
336 unsigned char *id_data, *tmp;
337 char *nickname, *username;
338 char *realname = NULL;
340 SILC_LOG_DEBUG(("Start"));
342 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
343 SILC_GET16_MSB(status, tmp);
344 if (status != SILC_STATUS_OK &&
345 status != SILC_STATUS_LIST_START &&
346 status != SILC_STATUS_LIST_ITEM &&
347 status != SILC_STATUS_LIST_END) {
352 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
358 client_id = silc_id_payload_parse_id(id_data, len);
364 /* Get the client entry, if exists */
365 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
367 silc_hash_client_id_compare, NULL,
369 client_entry = (SilcClientEntry)id_cache->context;
370 silc_free(client_id);
372 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
373 username = silc_argument_get_arg_type(cmd->args, 4, &len);
374 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
375 if (!nickname || !username) {
379 /* Notify application. We don't save any history information to any
380 cache. Just pass the data to the application for displaying on
382 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
384 /* Pending callbacks are not executed if this was an list entry */
385 if (status != SILC_STATUS_OK &&
386 status != SILC_STATUS_LIST_END) {
387 silc_client_command_reply_free(cmd);
391 /* Execute any pending command callbacks */
392 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
395 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
396 silc_client_command_reply_free(cmd);
400 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
401 SilcCommandStatus status)
403 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
404 SilcClient client = cmd->client;
405 SilcClientID *client_id = NULL;
406 SilcServerID *server_id = NULL;
407 SilcChannelID *channel_id = NULL;
408 SilcIDCacheEntry id_cache = NULL;
409 SilcClientEntry client_entry;
410 SilcServerEntry server_entry;
411 SilcChannelEntry channel_entry;
414 unsigned char *id_data;
415 char *name = NULL, *info = NULL;
416 SilcIDPayload idp = NULL;
419 argc = silc_argument_get_arg_num(cmd->args);
421 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
426 idp = silc_id_payload_parse_data(id_data, len);
432 name = silc_argument_get_arg_type(cmd->args, 3, &len);
433 info = silc_argument_get_arg_type(cmd->args, 4, &len);
435 id_type = silc_id_payload_get_type(idp);
439 client_id = silc_id_payload_get_id(idp);
441 SILC_LOG_DEBUG(("Received client information"));
443 /* Check if we have this client cached already. */
444 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
447 silc_hash_client_id_compare, NULL,
449 SILC_LOG_DEBUG(("Adding new client entry"));
451 silc_client_add_client(cmd->client, conn, name, info, NULL,
452 silc_id_dup(client_id, id_type), 0);
454 client_entry = (SilcClientEntry)id_cache->context;
455 silc_client_update_client(cmd->client, conn, client_entry,
456 name, info, NULL, 0);
459 /* Notify application */
460 COMMAND_REPLY((ARGS, client_entry, name, info));
464 server_id = silc_id_payload_get_id(idp);
466 SILC_LOG_DEBUG(("Received server information"));
468 /* Check if we have this server cached already. */
469 if (!silc_idcache_find_by_id_one(conn->server_cache,
470 (void *)server_id, &id_cache)) {
471 SILC_LOG_DEBUG(("Adding new server entry"));
473 server_entry = silc_calloc(1, sizeof(*server_entry));
474 server_entry->server_id = silc_id_dup(server_id, id_type);
476 server_entry->server_name = strdup(name);
478 server_entry->server_info = strdup(info);
480 /* Add server to cache */
481 silc_idcache_add(conn->server_cache, server_entry->server_name,
482 server_entry->server_id, (void *)server_entry, FALSE);
484 server_entry = (SilcServerEntry)id_cache->context;
487 /* Notify application */
488 COMMAND_REPLY((ARGS, server_entry, name, info));
491 case SILC_ID_CHANNEL:
492 channel_id = silc_id_payload_get_id(idp);
494 SILC_LOG_DEBUG(("Received channel information"));
496 /* Check if we have this channel cached already. */
497 if (!silc_idcache_find_by_id_one(conn->channel_cache,
498 (void *)channel_id, &id_cache)) {
502 SILC_LOG_DEBUG(("Adding new channel entry"));
503 channel_entry = silc_client_new_channel_id(client, conn->sock,
504 strdup(name), 0, idp);
506 channel_entry = (SilcChannelEntry)id_cache->context;
509 /* Notify application */
510 COMMAND_REPLY((ARGS, channel_entry, name, info));
514 silc_id_payload_free(idp);
515 silc_free(client_id);
516 silc_free(server_id);
517 silc_free(channel_id);
520 /* Received reply for IDENTIFY command. This maybe called several times
521 for one IDENTIFY command as server may reply with list of results.
522 This is totally silent and does not print anything on screen. */
524 SILC_CLIENT_CMD_REPLY_FUNC(identify)
526 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
527 SilcCommandStatus status;
530 SILC_LOG_DEBUG(("Start"));
532 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
533 SILC_GET16_MSB(status, tmp);
534 if (status != SILC_STATUS_OK &&
535 status != SILC_STATUS_LIST_START &&
536 status != SILC_STATUS_LIST_ITEM &&
537 status != SILC_STATUS_LIST_END) {
542 /* Save one IDENTIFY entry */
543 if (status == SILC_STATUS_OK)
544 silc_client_command_reply_identify_save(cmd, status);
547 if (status == SILC_STATUS_LIST_START ||
548 status == SILC_STATUS_LIST_ITEM ||
549 status == SILC_STATUS_LIST_END)
550 silc_client_command_reply_identify_save(cmd, status);
552 /* Pending callbacks are not executed if this was an list entry */
553 if (status != SILC_STATUS_OK &&
554 status != SILC_STATUS_LIST_END) {
555 silc_client_command_reply_free(cmd);
559 /* Execute any pending command callbacks */
560 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
563 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
564 silc_client_command_reply_free(cmd);
567 /* Received reply for command NICK. If everything went without errors
568 we just received our new Client ID. */
570 SILC_CLIENT_CMD_REPLY_FUNC(nick)
572 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
573 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
574 SilcCommandStatus status;
579 SILC_LOG_DEBUG(("Start"));
581 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
582 if (status != SILC_STATUS_OK) {
583 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
584 "Cannot set nickname: %s",
585 silc_client_command_status_message(status));
590 argc = silc_argument_get_arg_num(cmd->args);
591 if (argc < 2 || argc > 2) {
592 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
593 "Cannot set nickname: bad reply to command");
598 /* Take received Client ID */
599 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
600 idp = silc_id_payload_parse_data(tmp, len);
605 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
607 /* Notify application */
608 COMMAND_REPLY((ARGS, conn->local_entry));
610 /* Execute any pending command callbacks */
611 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
614 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
615 silc_client_command_reply_free(cmd);
618 /* Received reply to the LIST command. */
620 SILC_CLIENT_CMD_REPLY_FUNC(list)
622 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
623 SilcCommandStatus status;
624 unsigned char *tmp, *name, *topic;
625 uint32 usercount = 0;
627 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
628 SILC_GET16_MSB(status, tmp);
629 if (status != SILC_STATUS_OK &&
630 status != SILC_STATUS_LIST_START &&
631 status != SILC_STATUS_LIST_ITEM &&
632 status != SILC_STATUS_LIST_END) {
637 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
638 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
639 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
641 SILC_GET32_MSB(usercount, tmp);
643 /* Notify application */
644 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
646 /* Pending callbacks are not executed if this was an list entry */
647 if (status != SILC_STATUS_OK &&
648 status != SILC_STATUS_LIST_END) {
649 silc_client_command_reply_free(cmd);
653 /* Execute any pending command callbacks */
654 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
657 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
658 silc_client_command_reply_free(cmd);
661 /* Received reply to topic command. */
663 SILC_CLIENT_CMD_REPLY_FUNC(topic)
665 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
666 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
667 SilcCommandStatus status;
668 SilcChannelEntry channel;
669 SilcChannelID *channel_id = NULL;
670 SilcIDCacheEntry id_cache = NULL;
675 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
676 if (status != SILC_STATUS_OK) {
677 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
678 "%s", silc_client_command_status_message(status));
680 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
681 silc_client_command_reply_free(cmd);
685 argc = silc_argument_get_arg_num(cmd->args);
686 if (argc < 1 || argc > 3) {
691 /* Take Channel ID */
692 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
697 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
701 channel_id = silc_id_payload_parse_id(tmp, len);
705 /* Get the channel entry */
706 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
708 silc_free(channel_id);
713 channel = (SilcChannelEntry)id_cache->context;
715 /* Notify application */
716 COMMAND_REPLY((ARGS, channel, topic));
718 /* Execute any pending command callbacks */
719 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
722 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
723 silc_client_command_reply_free(cmd);
726 /* Received reply to invite command. */
728 SILC_CLIENT_CMD_REPLY_FUNC(invite)
730 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
731 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
732 SilcCommandStatus status;
733 SilcChannelEntry channel;
734 SilcChannelID *channel_id;
735 SilcIDCacheEntry id_cache;
739 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
740 SILC_GET16_MSB(status, tmp);
741 if (status != SILC_STATUS_OK) {
742 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
743 "%s", silc_client_command_status_message(status));
745 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
746 silc_client_command_reply_free(cmd);
750 /* Take Channel ID */
751 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
755 channel_id = silc_id_payload_parse_id(tmp, len);
759 /* Get the channel entry */
760 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
762 silc_free(channel_id);
767 channel = (SilcChannelEntry)id_cache->context;
769 /* Get the invite list */
770 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
772 /* Notify application */
773 COMMAND_REPLY((ARGS, channel, tmp));
775 /* Execute any pending command callbacks */
776 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
779 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
780 silc_client_command_reply_free(cmd);
783 /* Received reply to the KILL command. */
785 SILC_CLIENT_CMD_REPLY_FUNC(kill)
787 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
788 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
789 SilcCommandStatus status;
792 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
793 SILC_GET16_MSB(status, tmp);
794 if (status != SILC_STATUS_OK) {
795 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
796 "%s", silc_client_command_status_message(status));
801 /* Notify application */
802 COMMAND_REPLY((ARGS));
804 /* Execute any pending command callbacks */
805 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
808 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
809 silc_client_command_reply_free(cmd);
812 /* Received reply to INFO command. We receive the server ID and some
813 information about the server user requested. */
815 SILC_CLIENT_CMD_REPLY_FUNC(info)
817 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
818 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
819 SilcCommandStatus status;
821 SilcIDCacheEntry id_cache;
822 SilcServerEntry server;
823 SilcServerID *server_id = NULL;
824 char *server_name, *server_info;
827 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
828 SILC_GET16_MSB(status, tmp);
829 if (status != SILC_STATUS_OK) {
830 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
831 "%s", silc_client_command_status_message(status));
833 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
834 silc_client_command_reply_free(cmd);
839 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
843 server_id = silc_id_payload_parse_id(tmp, len);
847 /* Get server name */
848 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
852 /* Get server info */
853 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
857 /* See whether we have this server cached. If not create it. */
858 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
860 SILC_LOG_DEBUG(("New server entry"));
862 server = silc_calloc(1, sizeof(*server));
863 server->server_name = strdup(server_name);
864 server->server_info = strdup(server_info);
865 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
867 /* Add it to the cache */
868 silc_idcache_add(conn->server_cache, server->server_name,
869 server->server_id, (void *)server, FALSE);
871 server = (SilcServerEntry)id_cache->context;
874 /* Notify application */
875 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
877 /* Execute any pending command callbacks */
878 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
882 silc_free(server_id);
883 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
884 silc_client_command_reply_free(cmd);
887 /* Received reply to PING command. The reply time is shown to user. */
889 SILC_CLIENT_CMD_REPLY_FUNC(ping)
891 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
892 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
893 SilcCommandStatus status;
896 time_t diff, curtime;
898 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
899 if (status != SILC_STATUS_OK) {
900 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
901 "%s", silc_client_command_status_message(status));
906 curtime = time(NULL);
907 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
908 cmd->packet->src_id_type);
914 for (i = 0; i < conn->ping_count; i++) {
915 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
916 diff = curtime - conn->ping[i].start_time;
917 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
918 "Ping reply from %s: %d second%s",
919 conn->ping[i].dest_name, diff,
920 diff == 1 ? "" : "s");
922 conn->ping[i].start_time = 0;
923 silc_free(conn->ping[i].dest_id);
924 conn->ping[i].dest_id = NULL;
925 silc_free(conn->ping[i].dest_name);
926 conn->ping[i].dest_name = NULL;
933 /* Notify application */
934 COMMAND_REPLY((ARGS));
936 /* Execute any pending command callbacks */
937 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
940 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
941 silc_client_command_reply_free(cmd);
944 /* Received reply for JOIN command. */
946 SILC_CLIENT_CMD_REPLY_FUNC(join)
948 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
949 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
950 SilcCommandStatus status;
951 SilcIDPayload idp = NULL;
952 SilcChannelEntry channel;
953 SilcIDCacheEntry id_cache = NULL;
955 uint32 argc, mode, len, list_count;
956 char *topic, *tmp, *channel_name = NULL, *hmac;
957 SilcBuffer keyp = NULL, client_id_list, client_mode_list;
960 SILC_LOG_DEBUG(("Start"));
962 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
963 if (status != SILC_STATUS_OK) {
964 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
965 "%s", silc_client_command_status_message(status));
970 argc = silc_argument_get_arg_num(cmd->args);
971 if (argc < 7 || argc > 14) {
972 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
973 "Cannot join channel: Bad reply packet");
978 /* Get channel name */
979 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
981 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
982 "Cannot join channel: Bad reply packet");
986 channel_name = strdup(tmp);
989 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
991 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
992 "Cannot join channel: Bad reply packet");
994 silc_free(channel_name);
997 idp = silc_id_payload_parse_data(tmp, len);
1000 silc_free(channel_name);
1004 /* Get channel mode */
1005 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1007 SILC_GET32_MSB(mode, tmp);
1011 /* Get channel key */
1012 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1014 keyp = silc_buffer_alloc(len);
1015 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1016 silc_buffer_put(keyp, tmp, len);
1020 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1022 /* Save received Channel ID. This actually creates the channel */
1023 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
1025 silc_id_payload_free(idp);
1027 conn->current_channel = channel;
1030 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1032 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1033 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1034 "Cannot join channel: Unsupported HMAC `%s'",
1036 COMMAND_REPLY_ERROR;
1037 silc_free(channel_name);
1042 /* Get the list count */
1043 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1046 SILC_GET32_MSB(list_count, tmp);
1048 /* Get Client ID list */
1049 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1053 client_id_list = silc_buffer_alloc(len);
1054 silc_buffer_pull_tail(client_id_list, len);
1055 silc_buffer_put(client_id_list, tmp, len);
1057 /* Get client mode list */
1058 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1062 client_mode_list = silc_buffer_alloc(len);
1063 silc_buffer_pull_tail(client_mode_list, len);
1064 silc_buffer_put(client_mode_list, tmp, len);
1066 /* Add clients we received in the reply to the channel */
1067 for (i = 0; i < list_count; i++) {
1070 SilcClientID *client_id;
1071 SilcClientEntry client_entry;
1074 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1076 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1081 SILC_GET32_MSB(mode, client_mode_list->data);
1083 /* Check if we have this client cached already. */
1084 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1087 silc_hash_client_id_compare, NULL,
1089 /* No, we don't have it, add entry for it. */
1091 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1092 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1094 /* Yes, we have it already */
1095 client_entry = (SilcClientEntry)id_cache->context;
1098 /* Join the client to the channel */
1099 chu = silc_calloc(1, sizeof(*chu));
1100 chu->client = client_entry;
1102 silc_list_add(channel->clients, chu);
1103 silc_free(client_id);
1105 silc_buffer_pull(client_id_list, idp_len);
1106 silc_buffer_pull(client_mode_list, 4);
1108 silc_buffer_push(client_id_list, client_id_list->data -
1109 client_id_list->head);
1110 silc_buffer_push(client_mode_list, client_mode_list->data -
1111 client_mode_list->head);
1113 /* Save channel key */
1114 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1115 silc_client_save_channel_key(conn, keyp, channel);
1117 /* Client is now joined to the channel */
1118 channel->on_channel = TRUE;
1120 /* Notify application */
1121 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1122 keyp ? keyp->head : NULL, NULL,
1123 NULL, topic, hmac, list_count, client_id_list,
1126 /* Execute any pending command callbacks */
1127 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1130 silc_buffer_free(keyp);
1131 silc_buffer_free(client_id_list);
1132 silc_buffer_free(client_mode_list);
1135 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1136 silc_client_command_reply_free(cmd);
1139 /* Received reply for MOTD command */
1141 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1143 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1144 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1145 SilcCommandStatus status;
1148 char *motd = NULL, *cp, line[256];
1150 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1151 SILC_GET16_MSB(status, tmp);
1152 if (status != SILC_STATUS_OK) {
1153 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1154 "%s", silc_client_command_status_message(status));
1155 COMMAND_REPLY_ERROR;
1159 argc = silc_argument_get_arg_num(cmd->args);
1161 COMMAND_REPLY_ERROR;
1166 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1168 COMMAND_REPLY_ERROR;
1175 if (cp[i++] == '\n') {
1176 memset(line, 0, sizeof(line));
1177 strncat(line, cp, i - 1);
1183 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1193 /* Notify application */
1194 COMMAND_REPLY((ARGS, motd));
1196 /* Execute any pending command callbacks */
1197 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1200 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1201 silc_client_command_reply_free(cmd);
1204 /* Received reply tot he UMODE command. Save the current user mode */
1206 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1208 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1209 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1210 SilcCommandStatus status;
1214 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1215 SILC_GET16_MSB(status, tmp);
1216 if (status != SILC_STATUS_OK) {
1217 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1218 "%s", silc_client_command_status_message(status));
1219 COMMAND_REPLY_ERROR;
1223 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1225 COMMAND_REPLY_ERROR;
1229 SILC_GET32_MSB(mode, tmp);
1230 conn->local_entry->mode = mode;
1232 /* Notify application */
1233 COMMAND_REPLY((ARGS, mode));
1235 /* Execute any pending command callbacks */
1236 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1239 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1240 silc_client_command_reply_free(cmd);
1243 /* Received reply for CMODE command. */
1245 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1247 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1248 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1249 SilcCommandStatus status;
1252 SilcIDCacheEntry id_cache;
1253 SilcChannelID *channel_id;
1254 SilcChannelEntry channel;
1257 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1258 if (status != SILC_STATUS_OK) {
1259 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1260 "%s", silc_client_command_status_message(status));
1261 COMMAND_REPLY_ERROR;
1265 /* Take Channel ID */
1266 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1269 channel_id = silc_id_payload_parse_id(tmp, len);
1273 /* Get the channel entry */
1274 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1276 silc_free(channel_id);
1277 COMMAND_REPLY_ERROR;
1281 channel = (SilcChannelEntry)id_cache->context;
1283 /* Get channel mode */
1284 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1286 silc_free(channel_id);
1287 COMMAND_REPLY_ERROR;
1292 SILC_GET32_MSB(mode, tmp);
1293 channel->mode = mode;
1295 /* Notify application */
1296 COMMAND_REPLY((ARGS, channel, mode));
1297 silc_free(channel_id);
1299 /* Execute any pending command callbacks */
1300 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1303 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1304 silc_client_command_reply_free(cmd);
1307 /* Received reply for CUMODE command */
1309 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1311 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1312 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1313 SilcCommandStatus status;
1314 SilcIDCacheEntry id_cache = NULL;
1315 SilcClientID *client_id;
1316 SilcChannelID *channel_id;
1317 SilcClientEntry client_entry;
1318 SilcChannelEntry channel;
1319 SilcChannelUser chu;
1320 unsigned char *tmp, *id;
1323 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1324 if (status != SILC_STATUS_OK) {
1325 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1326 "%s", silc_client_command_status_message(status));
1327 COMMAND_REPLY_ERROR;
1331 /* Get channel mode */
1332 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1334 COMMAND_REPLY_ERROR;
1338 /* Take Channel ID */
1339 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1342 channel_id = silc_id_payload_parse_id(tmp, len);
1346 /* Get the channel entry */
1347 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1349 silc_free(channel_id);
1350 COMMAND_REPLY_ERROR;
1354 channel = (SilcChannelEntry)id_cache->context;
1357 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1359 silc_free(channel_id);
1360 COMMAND_REPLY_ERROR;
1363 client_id = silc_id_payload_parse_id(id, len);
1365 silc_free(channel_id);
1366 COMMAND_REPLY_ERROR;
1370 /* Get client entry */
1371 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1373 silc_hash_client_id_compare, NULL,
1375 silc_free(channel_id);
1376 silc_free(client_id);
1377 COMMAND_REPLY_ERROR;
1381 client_entry = (SilcClientEntry)id_cache->context;
1384 SILC_GET32_MSB(mode, tmp);
1385 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1386 if (chu->client == client_entry) {
1392 /* Notify application */
1393 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1394 silc_free(client_id);
1395 silc_free(channel_id);
1397 /* Execute any pending command callbacks */
1398 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1401 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1402 silc_client_command_reply_free(cmd);
1405 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1407 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1408 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1409 SilcCommandStatus status;
1412 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1413 SILC_GET16_MSB(status, tmp);
1414 if (status != SILC_STATUS_OK) {
1415 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1416 "%s", silc_client_command_status_message(status));
1417 COMMAND_REPLY_ERROR;
1421 /* Notify application */
1422 COMMAND_REPLY((ARGS));
1424 /* Execute any pending command callbacks */
1425 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1428 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1429 silc_client_command_reply_free(cmd);
1432 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1434 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1435 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1436 SilcCommandStatus status;
1439 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1440 SILC_GET16_MSB(status, tmp);
1441 if (status != SILC_STATUS_OK) {
1442 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1443 "%s", silc_client_command_status_message(status));
1444 COMMAND_REPLY_ERROR;
1448 /* Notify application */
1449 COMMAND_REPLY((ARGS));
1451 /* Execute any pending command callbacks */
1452 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1455 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1456 silc_client_command_reply_free(cmd);
1459 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1461 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1462 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1463 SilcCommandStatus status;
1466 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1467 SILC_GET16_MSB(status, tmp);
1468 if (status != SILC_STATUS_OK) {
1469 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1470 "%s", silc_client_command_status_message(status));
1471 COMMAND_REPLY_ERROR;
1475 /* Notify application */
1476 COMMAND_REPLY((ARGS));
1478 /* Execute any pending command callbacks */
1479 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1482 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1483 silc_client_command_reply_free(cmd);
1486 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1488 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1489 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1490 SilcCommandStatus status;
1493 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1494 SILC_GET16_MSB(status, tmp);
1495 if (status != SILC_STATUS_OK) {
1496 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1497 "%s", silc_client_command_status_message(status));
1498 COMMAND_REPLY_ERROR;
1502 /* Notify application */
1503 COMMAND_REPLY((ARGS));
1505 /* Execute any pending command callbacks */
1506 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1509 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1510 silc_client_command_reply_free(cmd);
1513 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1515 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1516 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1517 SilcCommandStatus status;
1518 SilcIDCacheEntry id_cache = NULL;
1519 SilcChannelEntry channel;
1520 SilcChannelID *channel_id;
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, SILC_CLIENT_MESSAGE_ERROR,
1528 "%s", silc_client_command_status_message(status));
1529 COMMAND_REPLY_ERROR;
1533 /* Take Channel ID */
1534 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1538 channel_id = silc_id_payload_parse_id(tmp, len);
1542 /* Get the channel entry */
1543 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1545 silc_free(channel_id);
1546 COMMAND_REPLY_ERROR;
1550 channel = (SilcChannelEntry)id_cache->context;
1552 /* Get the ban list */
1553 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1555 /* Notify application */
1556 COMMAND_REPLY((ARGS, channel, tmp));
1558 /* Execute any pending command callbacks */
1559 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1562 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1563 silc_client_command_reply_free(cmd);
1566 SILC_CLIENT_CMD_REPLY_FUNC(close)
1568 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1569 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1570 SilcCommandStatus status;
1573 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1574 SILC_GET16_MSB(status, tmp);
1575 if (status != SILC_STATUS_OK) {
1576 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1577 "%s", silc_client_command_status_message(status));
1578 COMMAND_REPLY_ERROR;
1582 /* Notify application */
1583 COMMAND_REPLY((ARGS));
1585 /* Execute any pending command callbacks */
1586 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1589 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1590 silc_client_command_reply_free(cmd);
1593 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1595 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1596 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1597 SilcCommandStatus status;
1600 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1601 SILC_GET16_MSB(status, tmp);
1602 if (status != SILC_STATUS_OK) {
1603 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1604 "%s", silc_client_command_status_message(status));
1605 COMMAND_REPLY_ERROR;
1609 /* Notify application */
1610 COMMAND_REPLY((ARGS));
1612 /* Execute any pending command callbacks */
1613 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1616 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1617 silc_client_command_reply_free(cmd);
1620 /* Reply to LEAVE command. */
1622 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1624 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1625 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1626 SilcCommandStatus status;
1629 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1630 SILC_GET16_MSB(status, tmp);
1631 if (status != SILC_STATUS_OK) {
1632 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1633 "%s", silc_client_command_status_message(status));
1634 COMMAND_REPLY_ERROR;
1638 /* Notify application */
1639 COMMAND_REPLY((ARGS));
1641 /* Execute any pending command callbacks */
1642 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1645 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1646 silc_client_command_reply_free(cmd);
1649 /* Reply to USERS command. Received list of client ID's and theirs modes
1650 on the channel we requested. */
1652 SILC_CLIENT_CMD_REPLY_FUNC(users)
1654 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1655 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1656 SilcCommandStatus status;
1657 SilcIDCacheEntry id_cache = NULL;
1658 SilcChannelEntry channel;
1659 SilcChannelUser chu;
1660 SilcChannelID *channel_id = NULL;
1661 SilcBuffer client_id_list;
1662 SilcBuffer client_mode_list;
1664 uint32 tmp_len, list_count;
1666 unsigned char **res_argv = NULL;
1667 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1669 SILC_LOG_DEBUG(("Start"));
1671 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1672 SILC_GET16_MSB(status, tmp);
1673 if (status != SILC_STATUS_OK) {
1674 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1675 "%s", silc_client_command_status_message(status));
1676 COMMAND_REPLY_ERROR;
1680 /* Get channel ID */
1681 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1683 COMMAND_REPLY_ERROR;
1686 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1688 COMMAND_REPLY_ERROR;
1692 /* Get the list count */
1693 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1695 COMMAND_REPLY_ERROR;
1698 SILC_GET32_MSB(list_count, tmp);
1700 /* Get Client ID list */
1701 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1703 COMMAND_REPLY_ERROR;
1707 client_id_list = silc_buffer_alloc(tmp_len);
1708 silc_buffer_pull_tail(client_id_list, tmp_len);
1709 silc_buffer_put(client_id_list, tmp, tmp_len);
1711 /* Get client mode list */
1712 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1714 COMMAND_REPLY_ERROR;
1718 client_mode_list = silc_buffer_alloc(tmp_len);
1719 silc_buffer_pull_tail(client_mode_list, tmp_len);
1720 silc_buffer_put(client_mode_list, tmp, tmp_len);
1722 /* Get channel entry */
1723 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1725 /* Resolve the channel from server */
1726 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1728 /* Register pending command callback. After we've received the channel
1729 information we will reprocess this command reply by re-calling this
1730 USERS command reply callback. */
1731 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1732 NULL, silc_client_command_reply_users, cmd);
1735 channel = (SilcChannelEntry)id_cache->context;
1738 /* Remove old client list from channel. */
1739 silc_list_start(channel->clients);
1740 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1741 silc_list_del(channel->clients, chu);
1745 /* Cache the received Client ID's and modes. */
1746 for (i = 0; i < list_count; i++) {
1749 SilcClientID *client_id;
1750 SilcClientEntry client;
1753 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1755 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1760 SILC_GET32_MSB(mode, client_mode_list->data);
1762 /* Check if we have this client cached already. */
1764 silc_idcache_find_by_id_one_ext(conn->client_cache,
1767 silc_hash_client_id_compare, NULL,
1770 if (!id_cache || !((SilcClientEntry)id_cache->context)->username) {
1771 /* No we don't have it (or it is incomplete in information), query
1772 it from the server. Assemble argument table that will be sent
1773 for the WHOIS command later. */
1774 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1776 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1778 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1780 res_argv[res_argc] = client_id_list->data;
1781 res_argv_lens[res_argc] = idp_len;
1782 res_argv_types[res_argc] = res_argc + 3;
1785 /* Found the client, join it to the channel */
1786 client = (SilcClientEntry)id_cache->context;
1787 chu = silc_calloc(1, sizeof(*chu));
1788 chu->client = client;
1790 silc_list_add(channel->clients, chu);
1792 silc_free(client_id);
1796 silc_buffer_pull(client_id_list, idp_len);
1797 silc_buffer_pull(client_mode_list, 4);
1800 /* Query the client information from server if the list included clients
1801 that we don't know about. */
1805 /* Send the WHOIS command to server */
1806 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1807 res_argc, res_argv, res_argv_lens,
1808 res_argv_types, ++conn->cmd_ident);
1809 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1810 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1813 /* Register pending command callback. After we've received the WHOIS
1814 command reply we will reprocess this command reply by re-calling this
1815 USERS command reply callback. */
1816 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1817 NULL, silc_client_command_reply_users, cmd);
1819 silc_buffer_free(res_cmd);
1821 silc_free(channel_id);
1823 silc_free(res_argv);
1824 silc_free(res_argv_lens);
1825 silc_free(res_argv_types);
1829 /* Notify application */
1830 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1832 /* Execute any pending command callbacks */
1833 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1835 silc_buffer_free(client_id_list);
1836 silc_buffer_free(client_mode_list);
1840 silc_free(channel_id);
1841 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1842 silc_client_command_reply_free(cmd);
1845 /* Received command reply to GETKEY command. WE've received the remote
1846 client's public key. */
1848 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1850 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1851 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1852 SilcCommandStatus status;
1853 SilcIDCacheEntry id_cache;
1854 SilcIDPayload idp = NULL;
1855 SilcClientID *client_id = NULL;
1856 SilcClientEntry client_entry;
1857 SilcServerID *server_id = NULL;
1858 SilcServerEntry server_entry;
1860 unsigned char *tmp, *pk;
1864 SilcPublicKey public_key = NULL;
1866 SILC_LOG_DEBUG(("Start"));
1868 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1869 SILC_GET16_MSB(status, tmp);
1870 if (status != SILC_STATUS_OK) {
1871 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1872 "%s", silc_client_command_status_message(status));
1873 COMMAND_REPLY_ERROR;
1877 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1880 idp = silc_id_payload_parse_data(tmp, len);
1884 /* Get the public key payload */
1885 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1887 /* Decode the public key */
1888 SILC_GET16_MSB(pk_len, tmp);
1889 SILC_GET16_MSB(type, tmp + 2);
1892 if (type != SILC_SKE_PK_TYPE_SILC)
1895 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1899 id_type = silc_id_payload_get_type(idp);
1900 if (id_type == SILC_ID_CLIENT) {
1901 /* Received client's public key */
1902 client_id = silc_id_payload_get_id(idp);
1903 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1906 silc_hash_client_id_compare, NULL,
1910 client_entry = (SilcClientEntry)id_cache->context;
1912 /* Notify application */
1913 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1914 } else if (id_type == SILC_ID_SERVER) {
1915 /* Received server's public key */
1916 server_id = silc_id_payload_get_id(idp);
1917 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1921 server_entry = (SilcServerEntry)id_cache->context;
1923 /* Notify application */
1924 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1928 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1930 silc_id_payload_free(idp);
1932 silc_pkcs_public_key_free(public_key);
1933 silc_free(client_id);
1934 silc_free(server_id);
1935 silc_client_command_reply_free(cmd);