5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 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.
35 #include "silcincludes.h"
36 #include "silcclient.h"
37 #include "client_internal.h"
39 const SilcStatusMessage silc_command_status_messages[] = {
41 { STAT(NO_SUCH_NICK), "There was no such nickname" },
42 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
43 { STAT(NO_SUCH_SERVER), "There was no such server" },
44 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
45 { STAT(NO_RECIPIENT), "No recipient given" },
46 { STAT(UNKNOWN_COMMAND), "Unknown command" },
47 { STAT(WILDCARDS), "Unknown command" },
48 { STAT(NO_CLIENT_ID), "No Client ID given" },
49 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
50 { STAT(NO_SERVER_ID), "No Server ID given" },
51 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
52 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
53 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
54 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
55 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
56 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
57 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
58 { STAT(USER_ON_CHANNEL), "User already on the channel" },
59 { STAT(NOT_REGISTERED), "You have not registered" },
60 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
61 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
62 { STAT(PERM_DENIED), "Permission denied" },
63 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
64 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
65 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
66 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
67 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
68 { STAT(UNKNOWN_MODE), "Unknown mode" },
69 { STAT(NOT_YOU), "Cannot change mode for other users" },
70 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
71 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
72 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
73 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
74 { STAT(BAD_NICKNAME), "Bad nickname" },
75 { STAT(BAD_CHANNEL), "Bad channel name" },
76 { STAT(AUTH_FAILED), "Authentication failed" },
77 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
78 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
83 #define SAY cmd->client->internal->ops->say
85 /* All functions that call the COMMAND_CHECK_STATUS macro must have
88 #define COMMAND_CHECK_STATUS \
90 SILC_LOG_DEBUG(("Start")); \
91 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
92 COMMAND_REPLY_ERROR; \
97 /* Process received command reply. */
99 void silc_client_command_reply_process(SilcClient client,
100 SilcSocketConnection sock,
101 SilcPacketContext *packet)
103 SilcBuffer buffer = packet->buffer;
104 SilcClientCommand cmd;
105 SilcClientCommandReplyContext ctx;
106 SilcCommandPayload payload;
108 SilcCommandCb reply = NULL;
110 /* Get command reply payload from packet */
111 payload = silc_command_payload_parse(buffer->data, buffer->len);
113 /* Silently ignore bad reply packet */
114 SILC_LOG_DEBUG(("Bad command reply packet"));
118 /* Allocate command reply context. This must be free'd by the
119 command reply routine receiving it. */
120 ctx = silc_calloc(1, sizeof(*ctx));
121 ctx->client = client;
123 ctx->payload = payload;
124 ctx->args = silc_command_get_args(ctx->payload);
125 ctx->packet = packet;
126 ctx->ident = silc_command_get_ident(ctx->payload);
127 silc_command_get_status(ctx->payload, &ctx->status, &ctx->error);
129 /* Check for pending commands and mark to be exeucted */
131 silc_client_command_pending_check(sock->user_data, ctx,
132 silc_command_get(ctx->payload),
133 ctx->ident, &ctx->callbacks_count);
135 /* Execute command reply */
137 command = silc_command_get(ctx->payload);
139 /* Try to find matching the command identifier */
140 silc_list_start(client->internal->commands);
141 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
142 if (cmd->cmd == command && !cmd->ident)
144 if (cmd->cmd == command && cmd->ident == ctx->ident) {
145 (*cmd->reply)((void *)ctx, NULL);
150 if (cmd == SILC_LIST_END) {
152 /* No specific identifier for command reply, call first one found */
159 /* Returns status message string */
161 char *silc_client_status_message(SilcStatus status)
165 for (i = 0; silc_command_status_messages[i].message; i++) {
166 if (silc_command_status_messages[i].status == status)
170 if (silc_command_status_messages[i].message == NULL)
173 return silc_command_status_messages[i].message;
176 /* Free command reply context and its internals. */
178 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
181 silc_command_payload_free(cmd->payload);
187 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
191 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
192 SilcClientID *client_id;
193 SilcClientEntry client_entry = NULL;
195 unsigned char *id_data, *tmp;
196 char *nickname = NULL, *username = NULL;
197 char *realname = NULL;
198 SilcUInt32 idle = 0, mode = 0;
199 SilcBufferStruct channels, ch_user_modes;
200 bool has_channels = FALSE, has_user_modes = FALSE;
201 unsigned char *fingerprint;
202 SilcUInt32 fingerprint_len;
204 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
211 client_id = silc_id_payload_parse_id(id_data, len, NULL);
218 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
219 username = silc_argument_get_arg_type(cmd->args, 4, &len);
220 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
221 if (!nickname || !username || !realname) {
227 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
229 silc_buffer_set(&channels, tmp, len);
233 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
235 SILC_GET32_MSB(mode, tmp);
237 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
239 SILC_GET32_MSB(idle, tmp);
241 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
243 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
245 silc_buffer_set(&ch_user_modes, tmp, len);
246 has_user_modes = TRUE;
249 /* Check if we have this client cached already. */
250 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
252 SILC_LOG_DEBUG(("Adding new client entry"));
254 silc_client_add_client(cmd->client, conn, nickname, username, realname,
257 silc_client_update_client(cmd->client, conn, client_entry,
258 nickname, username, realname, mode);
259 silc_free(client_id);
262 if (fingerprint && !client_entry->fingerprint) {
263 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
264 client_entry->fingerprint_len = fingerprint_len;
267 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
268 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
270 /* Notify application */
271 if (!cmd->callbacks_count && notify)
272 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
273 has_channels ? &channels : NULL, mode, idle,
274 fingerprint, has_user_modes ? &ch_user_modes : NULL));
277 /* Received reply for WHOIS command. This maybe called several times
278 for one WHOIS command as server may reply with list of results. */
280 SILC_CLIENT_CMD_REPLY_FUNC(whois)
282 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
283 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
285 COMMAND_CHECK_STATUS;
287 /* Save WHOIS info */
288 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
290 /* Pending callbacks are not executed if this was an list entry */
291 if (cmd->status != SILC_STATUS_OK &&
292 cmd->status != SILC_STATUS_LIST_END) {
293 silc_client_command_reply_free(cmd);
298 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
300 /* If we received notify for invalid ID we'll remove the ID if we
302 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
303 SilcClientEntry client_entry;
306 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
309 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
311 client_entry = silc_client_get_client_by_id(cmd->client, conn,
314 silc_client_del_client(cmd->client, conn, client_entry);
315 silc_free(client_id);
320 silc_client_command_reply_free(cmd);
323 /* Received reply for WHOWAS command. */
325 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
327 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
328 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
329 SilcClientID *client_id;
330 SilcClientEntry client_entry = NULL;
332 unsigned char *id_data;
333 char *nickname, *username;
334 char *realname = NULL;
336 COMMAND_CHECK_STATUS;
338 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
344 client_id = silc_id_payload_parse_id(id_data, len, NULL);
350 /* Get the client entry, if exists */
351 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
352 silc_free(client_id);
354 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
355 username = silc_argument_get_arg_type(cmd->args, 4, &len);
356 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
357 if (!nickname || !username) {
362 /* Notify application. We don't save any history information to any
363 cache. Just pass the data to the application for displaying on
365 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
367 /* Pending callbacks are not executed if this was an list entry */
368 if (cmd->status != SILC_STATUS_OK &&
369 cmd->status != SILC_STATUS_LIST_END) {
370 silc_client_command_reply_free(cmd);
375 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
376 silc_client_command_reply_free(cmd);
380 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
384 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
385 SilcClient client = cmd->client;
386 SilcClientID *client_id = NULL;
387 SilcServerID *server_id = NULL;
388 SilcChannelID *channel_id = NULL;
389 SilcClientEntry client_entry;
390 SilcServerEntry server_entry;
391 SilcChannelEntry channel_entry;
393 unsigned char *id_data;
394 char *name = NULL, *info = NULL;
395 SilcIDPayload idp = NULL;
398 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
404 idp = silc_id_payload_parse(id_data, len);
411 name = silc_argument_get_arg_type(cmd->args, 3, &len);
412 info = silc_argument_get_arg_type(cmd->args, 4, &len);
414 id_type = silc_id_payload_get_type(idp);
418 client_id = silc_id_payload_get_id(idp);
420 SILC_LOG_DEBUG(("Received client information"));
422 /* Check if we have this client cached already. */
423 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
425 SILC_LOG_DEBUG(("Adding new client entry"));
427 silc_client_add_client(cmd->client, conn, name, info, NULL,
428 silc_id_dup(client_id, id_type), 0);
430 silc_client_update_client(cmd->client, conn, client_entry,
431 name, info, NULL, 0);
434 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
435 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
437 /* Notify application */
439 COMMAND_REPLY((ARGS, client_entry, name, info));
443 server_id = silc_id_payload_get_id(idp);
445 SILC_LOG_DEBUG(("Received server information"));
447 /* Check if we have this server cached already. */
448 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
450 SILC_LOG_DEBUG(("Adding new server entry"));
451 server_entry = silc_client_add_server(cmd->client, conn, name, info,
452 silc_id_dup(server_id, id_type));
460 /* Notify application */
462 COMMAND_REPLY((ARGS, server_entry, name, info));
465 case SILC_ID_CHANNEL:
466 channel_id = silc_id_payload_get_id(idp);
468 SILC_LOG_DEBUG(("Received channel information"));
470 /* Check if we have this channel cached already. */
471 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
472 if (!channel_entry) {
476 /* Add new channel entry */
477 channel_entry = silc_client_add_channel(client, conn, name, 0,
482 /* Notify application */
484 COMMAND_REPLY((ARGS, channel_entry, name, info));
488 silc_id_payload_free(idp);
489 silc_free(client_id);
490 silc_free(server_id);
491 silc_free(channel_id);
494 /* Received reply for IDENTIFY command. This maybe called several times
495 for one IDENTIFY command as server may reply with list of results.
496 This is totally silent and does not print anything on screen. */
498 SILC_CLIENT_CMD_REPLY_FUNC(identify)
500 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
501 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
503 COMMAND_CHECK_STATUS;
505 /* Save IDENTIFY info */
506 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
508 /* Pending callbacks are not executed if this was an list entry */
509 if (cmd->status != SILC_STATUS_OK &&
510 cmd->status != SILC_STATUS_LIST_END) {
511 silc_client_command_reply_free(cmd);
516 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
518 /* If we received notify for invalid ID we'll remove the ID if we
520 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
521 SilcClientEntry client_entry;
524 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
527 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
529 client_entry = silc_client_get_client_by_id(cmd->client, conn,
532 silc_client_del_client(cmd->client, conn, client_entry);
533 silc_free(client_id);
538 silc_client_command_reply_free(cmd);
541 /* Received reply for command NICK. If everything went without errors
542 we just received our new Client ID. */
544 SILC_CLIENT_CMD_REPLY_FUNC(nick)
546 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
547 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
550 SilcUInt32 argc, len;
552 SILC_LOG_DEBUG(("Start"));
554 if (cmd->error != SILC_STATUS_OK) {
555 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
556 "Cannot set nickname: %s",
557 silc_client_status_message(cmd->error));
562 argc = silc_argument_get_arg_num(cmd->args);
563 if (argc < 2 || argc > 2) {
564 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
565 "Cannot set nickname: bad reply to command");
570 /* Take received Client ID */
571 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
572 idp = silc_id_payload_parse(tmp, len);
577 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
579 /* Notify application */
580 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
581 COMMAND_REPLY((ARGS, conn->local_entry));
582 silc_client_command_reply_free(cmd);
586 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
587 silc_client_command_reply_free(cmd);
590 /* Received reply to the LIST command. */
592 SILC_CLIENT_CMD_REPLY_FUNC(list)
594 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
595 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
596 unsigned char *tmp, *name, *topic;
597 SilcUInt32 usercount = 0, len;
598 SilcChannelID *channel_id = NULL;
599 SilcChannelEntry channel_entry;
601 COMMAND_CHECK_STATUS;
603 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
609 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
615 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 /* Check whether the channel exists, and add it to cache if it doesn't. */
627 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
629 if (!channel_entry) {
630 /* Add new channel entry */
631 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
633 if (!channel_entry) {
640 /* Notify application */
641 COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount));
643 /* Pending callbacks are not executed if this was an list entry */
644 if (cmd->status != SILC_STATUS_OK &&
645 cmd->status != SILC_STATUS_LIST_END) {
646 silc_client_command_reply_free(cmd);
651 silc_free(channel_id);
652 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
653 silc_client_command_reply_free(cmd);
656 /* Received reply to topic command. */
658 SILC_CLIENT_CMD_REPLY_FUNC(topic)
660 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
661 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
662 SilcChannelEntry channel;
663 SilcChannelID *channel_id = NULL;
666 SilcUInt32 argc, len;
668 if (cmd->error != SILC_STATUS_OK) {
669 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
670 "%s", silc_client_status_message(cmd->error));
675 argc = silc_argument_get_arg_num(cmd->args);
676 if (argc < 1 || argc > 3) {
681 /* Take Channel ID */
682 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
687 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
691 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
695 /* Get the channel entry */
696 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
698 silc_free(channel_id);
703 /* Notify application */
704 COMMAND_REPLY((ARGS, channel, topic));
707 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
708 silc_client_command_reply_free(cmd);
711 /* Received reply to invite command. */
713 SILC_CLIENT_CMD_REPLY_FUNC(invite)
715 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
716 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
717 SilcChannelEntry channel;
718 SilcChannelID *channel_id;
722 if (cmd->error != SILC_STATUS_OK) {
723 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
724 "%s", silc_client_status_message(cmd->error));
729 /* Take Channel ID */
730 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
734 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
738 /* Get the channel entry */
739 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
741 silc_free(channel_id);
746 /* Get the invite list */
747 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
749 /* Notify application */
750 COMMAND_REPLY((ARGS, channel, tmp));
753 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
754 silc_client_command_reply_free(cmd);
757 /* Received reply to the KILL command. */
759 SILC_CLIENT_CMD_REPLY_FUNC(kill)
761 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
762 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
764 if (cmd->error != SILC_STATUS_OK) {
765 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
766 "%s", silc_client_status_message(cmd->error));
771 /* Notify application */
772 COMMAND_REPLY((ARGS));
775 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
776 silc_client_command_reply_free(cmd);
779 /* Received reply to INFO command. We receive the server ID and some
780 information about the server user requested. */
782 SILC_CLIENT_CMD_REPLY_FUNC(info)
784 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
785 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
787 SilcServerEntry server;
788 SilcServerID *server_id = NULL;
789 char *server_name, *server_info;
792 SILC_LOG_DEBUG(("Start"));
794 if (cmd->error != SILC_STATUS_OK) {
795 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
796 silc_client_status_message(cmd->error));
802 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
806 server_id = silc_id_payload_parse_id(tmp, len, NULL);
810 /* Get server name */
811 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
815 /* Get server info */
816 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
820 /* See whether we have this server cached. If not create it. */
821 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
823 SILC_LOG_DEBUG(("New server entry"));
824 server = silc_client_add_server(cmd->client, conn, server_name,
826 silc_id_dup(server_id, SILC_ID_SERVER));
831 /* Notify application */
832 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
835 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
836 silc_free(server_id);
837 silc_client_command_reply_free(cmd);
840 /* Received reply to PING command. The reply time is shown to user. */
842 SILC_CLIENT_CMD_REPLY_FUNC(ping)
844 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
845 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
848 time_t diff, curtime;
850 if (cmd->error != SILC_STATUS_OK) {
851 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
852 "%s", silc_client_status_message(cmd->error));
857 curtime = time(NULL);
858 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
859 cmd->packet->src_id_type);
860 if (!id || !conn->ping) {
865 for (i = 0; i < conn->ping_count; i++) {
866 if (!conn->ping[i].dest_id)
868 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
869 diff = curtime - conn->ping[i].start_time;
870 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
871 "Ping reply from %s: %d second%s",
872 conn->ping[i].dest_name, diff,
873 diff == 1 ? "" : "s");
875 conn->ping[i].start_time = 0;
876 silc_free(conn->ping[i].dest_id);
877 conn->ping[i].dest_id = NULL;
878 silc_free(conn->ping[i].dest_name);
879 conn->ping[i].dest_name = NULL;
886 /* Notify application */
887 COMMAND_REPLY((ARGS));
890 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
891 silc_client_command_reply_free(cmd);
894 /* Received reply for JOIN command. */
896 SILC_CLIENT_CMD_REPLY_FUNC(join)
898 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
899 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
900 SilcChannelEntry channel;
902 SilcChannelID *channel_id;
903 SilcUInt32 argc, mode = 0, len, list_count;
904 char *topic, *tmp, *channel_name = NULL, *hmac;
905 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
908 SILC_LOG_DEBUG(("Start"));
910 if (cmd->error != SILC_STATUS_OK) {
911 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
912 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
913 "%s", silc_client_status_message(cmd->error));
918 argc = silc_argument_get_arg_num(cmd->args);
919 if (argc < 7 || argc > 14) {
920 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
921 "Cannot join channel: Bad reply packet");
926 /* Get channel name */
927 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
929 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
930 "Cannot join channel: Bad reply packet");
937 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
939 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
940 "Cannot join channel: Bad reply packet");
944 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
950 /* Get channel mode */
951 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
953 SILC_GET32_MSB(mode, tmp);
955 /* Get channel key */
956 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
958 keyp = silc_buffer_alloc(len);
959 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
960 silc_buffer_put(keyp, tmp, len);
964 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
966 /* Check whether we have this channel entry already. */
967 channel = silc_client_get_channel(cmd->client, conn, channel_name);
969 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
970 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
972 /* Create new channel entry */
973 channel = silc_client_add_channel(cmd->client, conn, channel_name,
977 conn->current_channel = channel;
980 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
982 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
983 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
984 "Cannot join channel: Unsupported HMAC `%s'", hmac);
990 /* Get the list count */
991 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
994 SILC_GET32_MSB(list_count, tmp);
996 /* Get Client ID list */
997 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1001 client_id_list = silc_buffer_alloc(len);
1002 silc_buffer_pull_tail(client_id_list, len);
1003 silc_buffer_put(client_id_list, tmp, len);
1005 /* Get client mode list */
1006 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1010 client_mode_list = silc_buffer_alloc(len);
1011 silc_buffer_pull_tail(client_mode_list, len);
1012 silc_buffer_put(client_mode_list, tmp, len);
1014 /* Add clients we received in the reply to the channel */
1015 for (i = 0; i < list_count; i++) {
1018 SilcClientID *client_id;
1019 SilcClientEntry client_entry;
1022 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1024 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1029 SILC_GET32_MSB(mode, client_mode_list->data);
1031 /* Check if we have this client cached already. */
1032 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1033 if (!client_entry) {
1034 /* No, we don't have it, add entry for it. */
1036 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1037 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1040 /* Join client to the channel */
1041 if (!silc_client_on_channel(channel, client_entry)) {
1042 chu = silc_calloc(1, sizeof(*chu));
1043 chu->client = client_entry;
1044 chu->channel = channel;
1046 silc_hash_table_add(channel->user_list, client_entry, chu);
1047 silc_hash_table_add(client_entry->channels, channel, chu);
1050 silc_free(client_id);
1051 silc_buffer_pull(client_id_list, idp_len);
1052 silc_buffer_pull(client_mode_list, 4);
1054 silc_buffer_push(client_id_list, client_id_list->data -
1055 client_id_list->head);
1056 silc_buffer_push(client_mode_list, client_mode_list->data -
1057 client_mode_list->head);
1059 /* Save channel key */
1060 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1061 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1063 /* Notify application */
1064 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1065 keyp ? keyp->head : NULL, NULL,
1066 NULL, topic, hmac, list_count, client_id_list,
1070 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1071 silc_client_command_reply_free(cmd);
1074 silc_buffer_free(keyp);
1076 silc_buffer_free(client_id_list);
1077 if (client_mode_list)
1078 silc_buffer_free(client_mode_list);
1081 /* Received reply for MOTD command */
1083 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1085 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1086 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1088 char *motd = NULL, *cp, line[256];
1090 if (cmd->error != SILC_STATUS_OK) {
1091 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1092 "%s", silc_client_status_message(cmd->error));
1093 COMMAND_REPLY_ERROR;
1097 argc = silc_argument_get_arg_num(cmd->args);
1099 COMMAND_REPLY_ERROR;
1104 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1106 COMMAND_REPLY_ERROR;
1113 if (cp[i++] == '\n') {
1114 memset(line, 0, sizeof(line));
1115 strncat(line, cp, i - 1);
1121 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1130 /* Notify application */
1131 COMMAND_REPLY((ARGS, motd));
1134 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1135 silc_client_command_reply_free(cmd);
1138 /* Received reply tot he UMODE command. Save the current user mode */
1140 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1142 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1143 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1147 if (cmd->error != SILC_STATUS_OK) {
1148 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1149 "%s", silc_client_status_message(cmd->error));
1150 COMMAND_REPLY_ERROR;
1154 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1156 COMMAND_REPLY_ERROR;
1160 SILC_GET32_MSB(mode, tmp);
1161 conn->local_entry->mode = mode;
1163 /* Notify application */
1164 COMMAND_REPLY((ARGS, mode));
1167 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1168 silc_client_command_reply_free(cmd);
1171 /* Received reply for CMODE command. */
1173 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1175 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1176 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1179 SilcChannelID *channel_id;
1180 SilcChannelEntry channel;
1183 if (cmd->error != SILC_STATUS_OK) {
1184 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1185 "%s", silc_client_status_message(cmd->error));
1186 COMMAND_REPLY_ERROR;
1190 /* Take Channel ID */
1191 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1194 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1198 /* Get the channel entry */
1199 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1201 silc_free(channel_id);
1202 COMMAND_REPLY_ERROR;
1206 /* Get channel mode */
1207 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1209 silc_free(channel_id);
1210 COMMAND_REPLY_ERROR;
1215 SILC_GET32_MSB(mode, tmp);
1216 channel->mode = mode;
1218 /* Notify application */
1219 COMMAND_REPLY((ARGS, channel, mode));
1221 silc_free(channel_id);
1224 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1225 silc_client_command_reply_free(cmd);
1228 /* Received reply for CUMODE command */
1230 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1232 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1233 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1234 SilcClientID *client_id;
1235 SilcChannelID *channel_id;
1236 SilcClientEntry client_entry;
1237 SilcChannelEntry channel;
1238 SilcChannelUser chu;
1239 unsigned char *modev, *tmp, *id;
1240 SilcUInt32 len, mode;
1242 if (cmd->error != SILC_STATUS_OK) {
1243 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1244 "%s", silc_client_status_message(cmd->error));
1245 COMMAND_REPLY_ERROR;
1249 /* Get channel mode */
1250 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1252 COMMAND_REPLY_ERROR;
1256 /* Take Channel ID */
1257 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1260 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1264 /* Get the channel entry */
1265 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1267 silc_free(channel_id);
1268 COMMAND_REPLY_ERROR;
1273 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1275 silc_free(channel_id);
1276 COMMAND_REPLY_ERROR;
1279 client_id = silc_id_payload_parse_id(id, len, NULL);
1281 silc_free(channel_id);
1282 COMMAND_REPLY_ERROR;
1286 /* Get client entry */
1287 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1288 if (!client_entry) {
1289 silc_free(channel_id);
1290 silc_free(client_id);
1291 COMMAND_REPLY_ERROR;
1296 SILC_GET32_MSB(mode, modev);
1297 chu = silc_client_on_channel(channel, client_entry);
1301 /* Notify application */
1302 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1303 silc_free(client_id);
1304 silc_free(channel_id);
1307 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1308 silc_client_command_reply_free(cmd);
1311 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1313 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1314 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1316 if (cmd->error != SILC_STATUS_OK) {
1317 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1318 "%s", silc_client_status_message(cmd->error));
1319 COMMAND_REPLY_ERROR;
1323 /* Notify application */
1324 COMMAND_REPLY((ARGS));
1327 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1328 silc_client_command_reply_free(cmd);
1331 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1333 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1334 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1336 if (cmd->error != SILC_STATUS_OK) {
1337 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1338 "%s", silc_client_status_message(cmd->error));
1339 COMMAND_REPLY_ERROR;
1343 /* Notify application */
1344 COMMAND_REPLY((ARGS));
1347 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1348 silc_client_command_reply_free(cmd);
1351 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1353 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1354 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1356 if (cmd->error != SILC_STATUS_OK) {
1357 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1358 "%s", silc_client_status_message(cmd->error));
1359 COMMAND_REPLY_ERROR;
1363 /* Notify application */
1364 COMMAND_REPLY((ARGS));
1367 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1368 silc_client_command_reply_free(cmd);
1371 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1373 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1374 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1377 if (cmd->error != SILC_STATUS_OK) {
1378 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1379 "%s", silc_client_status_message(cmd->error));
1380 COMMAND_REPLY_ERROR;
1384 /* Notify application */
1385 COMMAND_REPLY((ARGS));
1387 /* Generate the detachment data and deliver it to the client in the
1388 detach client operation */
1389 detach = silc_client_get_detach_data(cmd->client, conn);
1391 cmd->client->internal->ops->detach(cmd->client, conn,
1392 detach->data, detach->len);
1393 silc_buffer_free(detach);
1397 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1398 silc_client_command_reply_free(cmd);
1401 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1403 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1404 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1405 SilcChannelEntry channel;
1406 SilcChannelID *channel_id;
1410 if (cmd->error != SILC_STATUS_OK) {
1411 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1412 "%s", silc_client_status_message(cmd->error));
1413 COMMAND_REPLY_ERROR;
1417 /* Take Channel ID */
1418 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1422 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1426 /* Get the channel entry */
1427 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1429 silc_free(channel_id);
1430 COMMAND_REPLY_ERROR;
1434 /* Get the ban list */
1435 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1437 /* Notify application */
1438 COMMAND_REPLY((ARGS, channel, tmp));
1441 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1442 silc_client_command_reply_free(cmd);
1445 /* Reply to LEAVE command. */
1447 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1449 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1450 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1451 SilcChannelID *channel_id;
1452 SilcChannelEntry channel = NULL;
1456 if (cmd->error != SILC_STATUS_OK) {
1457 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1458 "%s", silc_client_status_message(cmd->error));
1459 COMMAND_REPLY_ERROR;
1463 /* From protocol version 1.1 we get the channel ID of the left channel */
1464 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1466 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1470 /* Get the channel entry */
1471 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1473 silc_free(channel_id);
1474 COMMAND_REPLY_ERROR;
1478 silc_free(channel_id);
1481 /* Notify application */
1482 COMMAND_REPLY((ARGS, channel));
1485 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1486 silc_client_command_reply_free(cmd);
1489 /* Channel resolving callback for USERS command reply. */
1491 static void silc_client_command_reply_users_cb(SilcClient client,
1492 SilcClientConnection conn,
1493 SilcChannelEntry *channels,
1494 SilcUInt32 channels_count,
1497 if (!channels_count) {
1498 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1499 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1501 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1502 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1503 "%s", silc_client_status_message(cmd->error));
1504 COMMAND_REPLY_ERROR;
1505 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1506 silc_client_command_reply_free(cmd);
1510 silc_client_command_reply_users(context, NULL);
1514 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1517 SilcGetChannelCallback get_channel,
1518 SilcCommandCb get_clients)
1520 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1521 SilcChannelEntry channel;
1522 SilcClientEntry client_entry;
1523 SilcChannelUser chu;
1524 SilcChannelID *channel_id = NULL;
1525 SilcBufferStruct client_id_list, client_mode_list;
1527 SilcUInt32 tmp_len, list_count;
1529 unsigned char **res_argv = NULL;
1530 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1531 bool wait_res = FALSE;
1533 SILC_LOG_DEBUG(("Start"));
1535 /* Get channel ID */
1536 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1538 COMMAND_REPLY_ERROR;
1541 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1543 COMMAND_REPLY_ERROR;
1547 /* Get the list count */
1548 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1550 COMMAND_REPLY_ERROR;
1553 SILC_GET32_MSB(list_count, tmp);
1555 /* Get Client ID list */
1556 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1558 COMMAND_REPLY_ERROR;
1561 silc_buffer_set(&client_id_list, tmp, tmp_len);
1563 /* Get client mode list */
1564 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1566 COMMAND_REPLY_ERROR;
1569 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1571 /* Get channel entry */
1572 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1574 /* Resolve the channel from server */
1575 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1577 silc_free(channel_id);
1581 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1583 /* Cache the received Client ID's and modes. */
1584 for (i = 0; i < list_count; i++) {
1587 SilcClientID *client_id;
1590 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1592 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1597 SILC_GET32_MSB(mode, client_mode_list.data);
1599 /* Check if we have this client cached already. */
1600 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1601 if (!client_entry || !client_entry->username || !client_entry->realname) {
1603 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1604 /* Attach to this resolving and wait until it finishes */
1605 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1606 client_entry->resolve_cmd_ident,
1610 silc_buffer_pull(&client_id_list, idp_len);
1611 silc_buffer_pull(&client_mode_list, 4);
1614 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1615 client_entry->resolve_cmd_ident = conn->cmd_ident + 1;
1618 /* No we don't have it (or it is incomplete in information), query
1619 it from the server. Assemble argument table that will be sent
1620 for the WHOIS command later. */
1621 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1623 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1625 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1627 res_argv[res_argc] = client_id_list.data;
1628 res_argv_lens[res_argc] = idp_len;
1629 res_argv_types[res_argc] = res_argc + 3;
1632 if (!silc_client_on_channel(channel, client_entry)) {
1633 chu = silc_calloc(1, sizeof(*chu));
1634 chu->client = client_entry;
1636 chu->channel = channel;
1637 silc_hash_table_add(channel->user_list, client_entry, chu);
1638 silc_hash_table_add(client_entry->channels, channel, chu);
1642 silc_free(client_id);
1643 silc_buffer_pull(&client_id_list, idp_len);
1644 silc_buffer_pull(&client_mode_list, 4);
1647 /* Query the client information from server if the list included clients
1648 that we don't know about. */
1652 /* Send the WHOIS command to server */
1653 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1654 silc_client_command_reply_whois_i, 0,
1656 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1657 res_argc, res_argv, res_argv_lens,
1658 res_argv_types, conn->cmd_ident);
1659 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1660 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1663 /* Register pending command callback. After we've received the WHOIS
1664 command reply we will reprocess this command reply by re-calling this
1665 USERS command reply callback. */
1666 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1669 silc_buffer_free(res_cmd);
1670 silc_free(channel_id);
1671 silc_free(res_argv);
1672 silc_free(res_argv_lens);
1673 silc_free(res_argv_types);
1680 silc_buffer_push(&client_id_list, (client_id_list.data -
1681 client_id_list.head));
1682 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1683 client_mode_list.head));
1685 /* Notify application */
1687 COMMAND_REPLY((ARGS, channel, list_count, &client_id_list,
1688 &client_mode_list));
1691 silc_free(channel_id);
1695 /* Reply to USERS command. Received list of client ID's and theirs modes
1696 on the channel we requested. */
1698 SILC_CLIENT_CMD_REPLY_FUNC(users)
1700 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1701 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1703 SILC_LOG_DEBUG(("Start"));
1705 if (cmd->error != SILC_STATUS_OK) {
1706 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1707 "%s", silc_client_status_message(cmd->error));
1708 COMMAND_REPLY_ERROR;
1712 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
1713 silc_client_command_reply_users_cb,
1714 silc_client_command_reply_users))
1718 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1719 silc_client_command_reply_free(cmd);
1722 /* Received command reply to GETKEY command. WE've received the remote
1723 client's public key. */
1725 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1727 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1728 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1729 SilcIDPayload idp = NULL;
1730 SilcClientID *client_id = NULL;
1731 SilcClientEntry client_entry;
1732 SilcServerID *server_id = NULL;
1733 SilcServerEntry server_entry;
1735 unsigned char *tmp, *pk;
1739 SilcPublicKey public_key = NULL;
1741 SILC_LOG_DEBUG(("Start"));
1743 if (cmd->error != SILC_STATUS_OK) {
1744 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1745 "%s", silc_client_status_message(cmd->error));
1746 COMMAND_REPLY_ERROR;
1750 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1752 COMMAND_REPLY_ERROR;
1755 idp = silc_id_payload_parse(tmp, len);
1757 COMMAND_REPLY_ERROR;
1761 /* Get the public key payload */
1762 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1764 /* Decode the public key */
1765 SILC_GET16_MSB(pk_len, tmp);
1766 SILC_GET16_MSB(type, tmp + 2);
1769 if (type == SILC_SKE_PK_TYPE_SILC)
1770 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 /* Received client's public key */
1777 client_id = silc_id_payload_get_id(idp);
1778 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1779 if (!client_entry) {
1780 COMMAND_REPLY_ERROR;
1784 /* Notify application */
1785 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1786 } else if (id_type == SILC_ID_SERVER) {
1787 /* Received server's public key */
1788 server_id = silc_id_payload_get_id(idp);
1789 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1790 if (!server_entry) {
1791 COMMAND_REPLY_ERROR;
1795 /* Notify application */
1796 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1800 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1802 silc_id_payload_free(idp);
1804 silc_pkcs_public_key_free(public_key);
1805 silc_free(client_id);
1806 silc_free(server_id);
1807 silc_client_command_reply_free(cmd);
1810 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1812 silc_client_command_reply_free(context);
1816 /******************************************************************************
1818 Internal command reply functions
1820 ******************************************************************************/
1822 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1824 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1825 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1827 SILC_LOG_DEBUG(("Start"));
1829 if (cmd->error != SILC_STATUS_OK)
1832 /* Save WHOIS info */
1833 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1835 /* Pending callbacks are not executed if this was an list entry */
1836 if (cmd->status != SILC_STATUS_OK &&
1837 cmd->status != SILC_STATUS_LIST_END) {
1838 silc_client_command_reply_free(cmd);
1843 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1845 /* If we received notify for invalid ID we'll remove the ID if we
1847 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1848 SilcClientEntry client_entry;
1850 unsigned char *tmp =
1851 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1854 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1856 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1859 silc_client_del_client(cmd->client, conn, client_entry);
1860 silc_free(client_id);
1865 /* Unregister this command reply */
1866 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1867 NULL, silc_client_command_reply_whois_i,
1870 silc_client_command_reply_free(cmd);
1873 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1875 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1876 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1878 SILC_LOG_DEBUG(("Start"));
1880 if (cmd->error != SILC_STATUS_OK)
1883 /* Save IDENTIFY info */
1884 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1886 /* Pending callbacks are not executed if this was an list entry */
1887 if (cmd->status != SILC_STATUS_OK &&
1888 cmd->status != SILC_STATUS_LIST_END) {
1889 silc_client_command_reply_free(cmd);
1894 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1896 /* If we received notify for invalid ID we'll remove the ID if we
1898 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1899 SilcClientEntry client_entry;
1901 unsigned char *tmp =
1902 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1905 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1907 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1910 silc_client_del_client(cmd->client, conn, client_entry);
1911 silc_free(client_id);
1916 /* Unregister this command reply */
1917 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1918 NULL, silc_client_command_reply_identify_i,
1921 silc_client_command_reply_free(cmd);
1924 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1926 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1927 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1929 SilcServerEntry server;
1930 SilcServerID *server_id = NULL;
1931 char *server_name, *server_info;
1934 SILC_LOG_DEBUG(("Start"));
1936 if (cmd->error != SILC_STATUS_OK)
1940 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1944 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1948 /* Get server name */
1949 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1953 /* Get server info */
1954 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1958 /* See whether we have this server cached. If not create it. */
1959 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1961 SILC_LOG_DEBUG(("New server entry"));
1962 silc_client_add_server(cmd->client, conn, server_name, server_info,
1963 silc_id_dup(server_id, SILC_ID_SERVER));
1967 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1968 silc_free(server_id);
1969 silc_client_command_reply_free(cmd);
1972 static void silc_client_command_reply_users_i_cb(SilcClient client,
1973 SilcClientConnection conn,
1974 SilcChannelEntry *channels,
1975 SilcUInt32 channels_count,
1978 if (!channels_count) {
1979 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1980 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1982 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1983 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1984 "%s", silc_client_status_message(cmd->error));
1985 COMMAND_REPLY_ERROR;
1986 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1987 silc_client_command_reply_free(cmd);
1991 silc_client_command_reply_users_i(context, NULL);
1994 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
1996 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1998 SILC_LOG_DEBUG(("Start"));
2000 if (cmd->error != SILC_STATUS_OK)
2003 /* Save USERS info */
2004 if (silc_client_command_reply_users_save(
2005 cmd, cmd->status, FALSE,
2006 silc_client_command_reply_users_i_cb,
2007 silc_client_command_reply_users_i))
2011 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2013 /* Unregister this command reply */
2014 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2015 NULL, silc_client_command_reply_users_i,
2018 silc_client_command_reply_free(cmd);
2021 /* Private range commands, specific to this implementation (and compatible
2022 with SILC Server >= 0.9). */
2024 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2026 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2027 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2029 if (cmd->error != SILC_STATUS_OK) {
2030 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2031 "%s", silc_client_status_message(cmd->error));
2032 COMMAND_REPLY_ERROR;
2036 /* Notify application */
2037 COMMAND_REPLY((ARGS));
2040 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2041 silc_client_command_reply_free(cmd);
2044 SILC_CLIENT_CMD_REPLY_FUNC(close)
2046 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2047 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2049 if (cmd->error != SILC_STATUS_OK) {
2050 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2051 "%s", silc_client_status_message(cmd->error));
2052 COMMAND_REPLY_ERROR;
2056 /* Notify application */
2057 COMMAND_REPLY((ARGS));
2060 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2061 silc_client_command_reply_free(cmd);
2064 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2066 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2067 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2069 if (cmd->error != SILC_STATUS_OK) {
2070 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2071 "%s", silc_client_status_message(cmd->error));
2072 COMMAND_REPLY_ERROR;
2076 /* Notify application */
2077 COMMAND_REPLY((ARGS));
2080 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2081 silc_client_command_reply_free(cmd);