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(watch)
1403 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1404 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1406 if (cmd->error != SILC_STATUS_OK) {
1407 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1408 "%s", silc_client_status_message(cmd->error));
1409 COMMAND_REPLY_ERROR;
1413 /* Notify application */
1414 COMMAND_REPLY((ARGS));
1417 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1418 silc_client_command_reply_free(cmd);
1421 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1423 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1424 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1425 SilcChannelEntry channel;
1426 SilcChannelID *channel_id;
1430 if (cmd->error != SILC_STATUS_OK) {
1431 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1432 "%s", silc_client_status_message(cmd->error));
1433 COMMAND_REPLY_ERROR;
1437 /* Take Channel ID */
1438 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1442 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1446 /* Get the channel entry */
1447 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1449 silc_free(channel_id);
1450 COMMAND_REPLY_ERROR;
1454 /* Get the ban list */
1455 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1457 /* Notify application */
1458 COMMAND_REPLY((ARGS, channel, tmp));
1461 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1462 silc_client_command_reply_free(cmd);
1465 /* Reply to LEAVE command. */
1467 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1469 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1470 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1471 SilcChannelID *channel_id;
1472 SilcChannelEntry channel = NULL;
1476 if (cmd->error != SILC_STATUS_OK) {
1477 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1478 "%s", silc_client_status_message(cmd->error));
1479 COMMAND_REPLY_ERROR;
1483 /* From protocol version 1.1 we get the channel ID of the left channel */
1484 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1486 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1490 /* Get the channel entry */
1491 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1493 silc_free(channel_id);
1494 COMMAND_REPLY_ERROR;
1498 silc_free(channel_id);
1501 /* Notify application */
1502 COMMAND_REPLY((ARGS, channel));
1505 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1506 silc_client_command_reply_free(cmd);
1509 /* Channel resolving callback for USERS command reply. */
1511 static void silc_client_command_reply_users_cb(SilcClient client,
1512 SilcClientConnection conn,
1513 SilcChannelEntry *channels,
1514 SilcUInt32 channels_count,
1517 if (!channels_count) {
1518 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1519 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1521 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1522 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1523 "%s", silc_client_status_message(cmd->error));
1524 COMMAND_REPLY_ERROR;
1525 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1526 silc_client_command_reply_free(cmd);
1530 silc_client_command_reply_users(context, NULL);
1534 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1537 SilcGetChannelCallback get_channel,
1538 SilcCommandCb get_clients)
1540 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1541 SilcChannelEntry channel;
1542 SilcClientEntry client_entry;
1543 SilcChannelUser chu;
1544 SilcChannelID *channel_id = NULL;
1545 SilcBufferStruct client_id_list, client_mode_list;
1547 SilcUInt32 tmp_len, list_count;
1549 unsigned char **res_argv = NULL;
1550 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1551 bool wait_res = FALSE;
1553 SILC_LOG_DEBUG(("Start"));
1555 /* Get channel ID */
1556 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1558 COMMAND_REPLY_ERROR;
1561 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1563 COMMAND_REPLY_ERROR;
1567 /* Get the list count */
1568 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1570 COMMAND_REPLY_ERROR;
1573 SILC_GET32_MSB(list_count, tmp);
1575 /* Get Client ID list */
1576 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1578 COMMAND_REPLY_ERROR;
1581 silc_buffer_set(&client_id_list, tmp, tmp_len);
1583 /* Get client mode list */
1584 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1586 COMMAND_REPLY_ERROR;
1589 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1591 /* Get channel entry */
1592 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1594 /* Resolve the channel from server */
1595 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1597 silc_free(channel_id);
1601 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1603 /* Cache the received Client ID's and modes. */
1604 for (i = 0; i < list_count; i++) {
1607 SilcClientID *client_id;
1610 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1612 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1617 SILC_GET32_MSB(mode, client_mode_list.data);
1619 /* Check if we have this client cached already. */
1620 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1621 if (!client_entry || !client_entry->username || !client_entry->realname) {
1623 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1624 /* Attach to this resolving and wait until it finishes */
1625 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1626 client_entry->resolve_cmd_ident,
1630 silc_buffer_pull(&client_id_list, idp_len);
1631 silc_buffer_pull(&client_mode_list, 4);
1634 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1635 client_entry->resolve_cmd_ident = conn->cmd_ident + 1;
1638 /* No we don't have it (or it is incomplete in information), query
1639 it from the server. Assemble argument table that will be sent
1640 for the WHOIS command later. */
1641 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1643 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1645 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1647 res_argv[res_argc] = client_id_list.data;
1648 res_argv_lens[res_argc] = idp_len;
1649 res_argv_types[res_argc] = res_argc + 3;
1652 if (!silc_client_on_channel(channel, client_entry)) {
1653 chu = silc_calloc(1, sizeof(*chu));
1654 chu->client = client_entry;
1656 chu->channel = channel;
1657 silc_hash_table_add(channel->user_list, client_entry, chu);
1658 silc_hash_table_add(client_entry->channels, channel, chu);
1662 silc_free(client_id);
1663 silc_buffer_pull(&client_id_list, idp_len);
1664 silc_buffer_pull(&client_mode_list, 4);
1667 /* Query the client information from server if the list included clients
1668 that we don't know about. */
1672 /* Send the WHOIS command to server */
1673 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1674 silc_client_command_reply_whois_i, 0,
1676 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1677 res_argc, res_argv, res_argv_lens,
1678 res_argv_types, conn->cmd_ident);
1679 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1680 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1683 /* Register pending command callback. After we've received the WHOIS
1684 command reply we will reprocess this command reply by re-calling this
1685 USERS command reply callback. */
1686 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1689 silc_buffer_free(res_cmd);
1690 silc_free(channel_id);
1691 silc_free(res_argv);
1692 silc_free(res_argv_lens);
1693 silc_free(res_argv_types);
1700 silc_buffer_push(&client_id_list, (client_id_list.data -
1701 client_id_list.head));
1702 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1703 client_mode_list.head));
1705 /* Notify application */
1707 COMMAND_REPLY((ARGS, channel, list_count, &client_id_list,
1708 &client_mode_list));
1711 silc_free(channel_id);
1715 /* Reply to USERS command. Received list of client ID's and theirs modes
1716 on the channel we requested. */
1718 SILC_CLIENT_CMD_REPLY_FUNC(users)
1720 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1721 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1723 SILC_LOG_DEBUG(("Start"));
1725 if (cmd->error != SILC_STATUS_OK) {
1726 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1727 "%s", silc_client_status_message(cmd->error));
1728 COMMAND_REPLY_ERROR;
1732 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
1733 silc_client_command_reply_users_cb,
1734 silc_client_command_reply_users))
1738 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1739 silc_client_command_reply_free(cmd);
1742 /* Received command reply to GETKEY command. WE've received the remote
1743 client's public key. */
1745 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1747 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1748 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1749 SilcIDPayload idp = NULL;
1750 SilcClientID *client_id = NULL;
1751 SilcClientEntry client_entry;
1752 SilcServerID *server_id = NULL;
1753 SilcServerEntry server_entry;
1755 unsigned char *tmp, *pk;
1759 SilcPublicKey public_key = NULL;
1761 SILC_LOG_DEBUG(("Start"));
1763 if (cmd->error != SILC_STATUS_OK) {
1764 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1765 "%s", silc_client_status_message(cmd->error));
1766 COMMAND_REPLY_ERROR;
1770 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1772 COMMAND_REPLY_ERROR;
1775 idp = silc_id_payload_parse(tmp, len);
1777 COMMAND_REPLY_ERROR;
1781 /* Get the public key payload */
1782 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1784 /* Decode the public key */
1785 SILC_GET16_MSB(pk_len, tmp);
1786 SILC_GET16_MSB(type, tmp + 2);
1789 if (type == SILC_SKE_PK_TYPE_SILC)
1790 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1794 id_type = silc_id_payload_get_type(idp);
1795 if (id_type == SILC_ID_CLIENT) {
1796 /* Received client's public key */
1797 client_id = silc_id_payload_get_id(idp);
1798 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1799 if (!client_entry) {
1800 COMMAND_REPLY_ERROR;
1804 /* Notify application */
1805 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1806 } else if (id_type == SILC_ID_SERVER) {
1807 /* Received server's public key */
1808 server_id = silc_id_payload_get_id(idp);
1809 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1810 if (!server_entry) {
1811 COMMAND_REPLY_ERROR;
1815 /* Notify application */
1816 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1820 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1822 silc_id_payload_free(idp);
1824 silc_pkcs_public_key_free(public_key);
1825 silc_free(client_id);
1826 silc_free(server_id);
1827 silc_client_command_reply_free(cmd);
1830 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1832 silc_client_command_reply_free(context);
1836 /******************************************************************************
1838 Internal command reply functions
1840 ******************************************************************************/
1842 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1844 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1845 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1847 SILC_LOG_DEBUG(("Start"));
1849 if (cmd->error != SILC_STATUS_OK)
1852 /* Save WHOIS info */
1853 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1855 /* Pending callbacks are not executed if this was an list entry */
1856 if (cmd->status != SILC_STATUS_OK &&
1857 cmd->status != SILC_STATUS_LIST_END) {
1858 silc_client_command_reply_free(cmd);
1863 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1865 /* If we received notify for invalid ID we'll remove the ID if we
1867 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1868 SilcClientEntry client_entry;
1870 unsigned char *tmp =
1871 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1874 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1876 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1879 silc_client_del_client(cmd->client, conn, client_entry);
1880 silc_free(client_id);
1885 /* Unregister this command reply */
1886 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1887 NULL, silc_client_command_reply_whois_i,
1890 silc_client_command_reply_free(cmd);
1893 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1895 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1896 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1898 SILC_LOG_DEBUG(("Start"));
1900 if (cmd->error != SILC_STATUS_OK)
1903 /* Save IDENTIFY info */
1904 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1906 /* Pending callbacks are not executed if this was an list entry */
1907 if (cmd->status != SILC_STATUS_OK &&
1908 cmd->status != SILC_STATUS_LIST_END) {
1909 silc_client_command_reply_free(cmd);
1914 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1916 /* If we received notify for invalid ID we'll remove the ID if we
1918 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1919 SilcClientEntry client_entry;
1921 unsigned char *tmp =
1922 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1925 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1927 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1930 silc_client_del_client(cmd->client, conn, client_entry);
1931 silc_free(client_id);
1936 /* Unregister this command reply */
1937 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1938 NULL, silc_client_command_reply_identify_i,
1941 silc_client_command_reply_free(cmd);
1944 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1946 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1947 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1949 SilcServerEntry server;
1950 SilcServerID *server_id = NULL;
1951 char *server_name, *server_info;
1954 SILC_LOG_DEBUG(("Start"));
1956 if (cmd->error != SILC_STATUS_OK)
1960 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1964 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1968 /* Get server name */
1969 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1973 /* Get server info */
1974 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1978 /* See whether we have this server cached. If not create it. */
1979 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1981 SILC_LOG_DEBUG(("New server entry"));
1982 silc_client_add_server(cmd->client, conn, server_name, server_info,
1983 silc_id_dup(server_id, SILC_ID_SERVER));
1987 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1988 silc_free(server_id);
1989 silc_client_command_reply_free(cmd);
1992 static void silc_client_command_reply_users_i_cb(SilcClient client,
1993 SilcClientConnection conn,
1994 SilcChannelEntry *channels,
1995 SilcUInt32 channels_count,
1998 if (!channels_count) {
1999 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2000 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2002 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2003 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2004 "%s", silc_client_status_message(cmd->error));
2005 COMMAND_REPLY_ERROR;
2006 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2007 silc_client_command_reply_free(cmd);
2011 silc_client_command_reply_users_i(context, NULL);
2014 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2016 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2018 SILC_LOG_DEBUG(("Start"));
2020 if (cmd->error != SILC_STATUS_OK)
2023 /* Save USERS info */
2024 if (silc_client_command_reply_users_save(
2025 cmd, cmd->status, FALSE,
2026 silc_client_command_reply_users_i_cb,
2027 silc_client_command_reply_users_i))
2031 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2033 /* Unregister this command reply */
2034 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2035 NULL, silc_client_command_reply_users_i,
2038 silc_client_command_reply_free(cmd);
2041 /* Private range commands, specific to this implementation (and compatible
2042 with SILC Server >= 0.9). */
2044 SILC_CLIENT_CMD_REPLY_FUNC(connect)
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_CONNECT);
2061 silc_client_command_reply_free(cmd);
2064 SILC_CLIENT_CMD_REPLY_FUNC(close)
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_CLOSE);
2081 silc_client_command_reply_free(cmd);
2084 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2086 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2087 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2089 if (cmd->error != SILC_STATUS_OK) {
2090 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2091 "%s", silc_client_status_message(cmd->error));
2092 COMMAND_REPLY_ERROR;
2096 /* Notify application */
2097 COMMAND_REPLY((ARGS));
2100 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2101 silc_client_command_reply_free(cmd);