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 SilcCommandStatusMessage 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 */
130 silc_client_command_pending_check(sock->user_data, ctx,
131 silc_command_get(ctx->payload),
134 /* Execute command reply */
136 command = silc_command_get(ctx->payload);
138 /* Try to find matching the command identifier */
139 silc_list_start(client->internal->commands);
140 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
141 if (cmd->cmd == command && !cmd->ident)
143 if (cmd->cmd == command && cmd->ident == ctx->ident) {
144 (*cmd->reply)((void *)ctx, NULL);
149 if (cmd == SILC_LIST_END) {
151 /* No specific identifier for command reply, call first one found */
158 /* Returns status message string */
160 char *silc_client_command_status_message(SilcCommandStatus status)
164 for (i = 0; silc_command_status_messages[i].message; i++) {
165 if (silc_command_status_messages[i].status == status)
169 if (silc_command_status_messages[i].message == NULL)
172 return silc_command_status_messages[i].message;
175 /* Free command reply context and its internals. */
177 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
180 silc_command_payload_free(cmd->payload);
186 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
187 SilcCommandStatus status,
190 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
191 SilcClientID *client_id;
192 SilcClientEntry client_entry = NULL;
194 unsigned char *id_data, *tmp;
195 char *nickname = NULL, *username = NULL;
196 char *realname = NULL;
197 SilcUInt32 idle = 0, mode = 0;
198 SilcBufferStruct channels, ch_user_modes;
199 bool has_channels = FALSE, has_user_modes = FALSE;
200 unsigned char *fingerprint;
201 SilcUInt32 fingerprint_len;
203 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
210 client_id = silc_id_payload_parse_id(id_data, len, NULL);
217 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
218 username = silc_argument_get_arg_type(cmd->args, 4, &len);
219 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
220 if (!nickname || !username || !realname) {
226 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
228 silc_buffer_set(&channels, tmp, len);
232 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
234 SILC_GET32_MSB(mode, tmp);
236 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
238 SILC_GET32_MSB(idle, tmp);
240 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
242 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
244 silc_buffer_set(&ch_user_modes, tmp, len);
245 has_user_modes = TRUE;
248 /* Check if we have this client cached already. */
249 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
251 SILC_LOG_DEBUG(("Adding new client entry"));
253 silc_client_add_client(cmd->client, conn, nickname, username, realname,
256 silc_client_update_client(cmd->client, conn, client_entry,
257 nickname, username, realname, mode);
258 silc_free(client_id);
261 if (fingerprint && !client_entry->fingerprint) {
262 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
263 client_entry->fingerprint_len = fingerprint_len;
266 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
267 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
269 /* Notify application */
270 if (!cmd->callback && notify)
271 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
272 has_channels ? &channels : NULL, mode, idle,
273 fingerprint, has_user_modes ? &ch_user_modes : NULL));
276 /* Received reply for WHOIS command. This maybe called several times
277 for one WHOIS command as server may reply with list of results. */
279 SILC_CLIENT_CMD_REPLY_FUNC(whois)
281 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
282 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
284 COMMAND_CHECK_STATUS;
286 /* Save WHOIS info */
287 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
289 /* Pending callbacks are not executed if this was an list entry */
290 if (cmd->status != SILC_STATUS_OK &&
291 cmd->status != SILC_STATUS_LIST_END) {
292 silc_client_command_reply_free(cmd);
297 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
299 /* If we received notify for invalid ID we'll remove the ID if we
301 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
302 SilcClientEntry client_entry;
305 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
308 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
310 client_entry = silc_client_get_client_by_id(cmd->client, conn,
313 silc_client_del_client(cmd->client, conn, client_entry);
314 silc_free(client_id);
319 silc_client_command_reply_free(cmd);
322 /* Received reply for WHOWAS command. */
324 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
326 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
327 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
328 SilcClientID *client_id;
329 SilcClientEntry client_entry = NULL;
331 unsigned char *id_data;
332 char *nickname, *username;
333 char *realname = NULL;
335 COMMAND_CHECK_STATUS;
337 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
343 client_id = silc_id_payload_parse_id(id_data, len, NULL);
349 /* Get the client entry, if exists */
350 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
351 silc_free(client_id);
353 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
354 username = silc_argument_get_arg_type(cmd->args, 4, &len);
355 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
356 if (!nickname || !username) {
361 /* Notify application. We don't save any history information to any
362 cache. Just pass the data to the application for displaying on
364 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
366 /* Pending callbacks are not executed if this was an list entry */
367 if (cmd->status != SILC_STATUS_OK &&
368 cmd->status != SILC_STATUS_LIST_END) {
369 silc_client_command_reply_free(cmd);
374 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
375 silc_client_command_reply_free(cmd);
379 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
380 SilcCommandStatus status,
383 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
384 SilcClient client = cmd->client;
385 SilcClientID *client_id = NULL;
386 SilcServerID *server_id = NULL;
387 SilcChannelID *channel_id = NULL;
388 SilcClientEntry client_entry;
389 SilcServerEntry server_entry;
390 SilcChannelEntry channel_entry;
392 unsigned char *id_data;
393 char *name = NULL, *info = NULL;
394 SilcIDPayload idp = NULL;
397 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
403 idp = silc_id_payload_parse(id_data, len);
410 name = silc_argument_get_arg_type(cmd->args, 3, &len);
411 info = silc_argument_get_arg_type(cmd->args, 4, &len);
413 id_type = silc_id_payload_get_type(idp);
417 client_id = silc_id_payload_get_id(idp);
419 SILC_LOG_DEBUG(("Received client information"));
421 /* Check if we have this client cached already. */
422 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
424 SILC_LOG_DEBUG(("Adding new client entry"));
426 silc_client_add_client(cmd->client, conn, name, info, NULL,
427 silc_id_dup(client_id, id_type), 0);
429 silc_client_update_client(cmd->client, conn, client_entry,
430 name, info, NULL, 0);
433 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
434 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
436 /* Notify application */
438 COMMAND_REPLY((ARGS, client_entry, name, info));
442 server_id = silc_id_payload_get_id(idp);
444 SILC_LOG_DEBUG(("Received server information"));
446 /* Check if we have this server cached already. */
447 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
449 SILC_LOG_DEBUG(("Adding new server entry"));
450 server_entry = silc_client_add_server(cmd->client, conn, name, info,
451 silc_id_dup(server_id, id_type));
459 /* Notify application */
461 COMMAND_REPLY((ARGS, server_entry, name, info));
464 case SILC_ID_CHANNEL:
465 channel_id = silc_id_payload_get_id(idp);
467 SILC_LOG_DEBUG(("Received channel information"));
469 /* Check if we have this channel cached already. */
470 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
471 if (!channel_entry) {
475 /* Add new channel entry */
476 channel_entry = silc_client_add_channel(client, conn, name, 0,
481 /* Notify application */
483 COMMAND_REPLY((ARGS, channel_entry, name, info));
487 silc_id_payload_free(idp);
488 silc_free(client_id);
489 silc_free(server_id);
490 silc_free(channel_id);
493 /* Received reply for IDENTIFY command. This maybe called several times
494 for one IDENTIFY command as server may reply with list of results.
495 This is totally silent and does not print anything on screen. */
497 SILC_CLIENT_CMD_REPLY_FUNC(identify)
499 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
500 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
502 COMMAND_CHECK_STATUS;
504 /* Save IDENTIFY info */
505 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
507 /* Pending callbacks are not executed if this was an list entry */
508 if (cmd->status != SILC_STATUS_OK &&
509 cmd->status != SILC_STATUS_LIST_END) {
510 silc_client_command_reply_free(cmd);
515 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
517 /* If we received notify for invalid ID we'll remove the ID if we
519 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
520 SilcClientEntry client_entry;
523 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
526 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
528 client_entry = silc_client_get_client_by_id(cmd->client, conn,
531 silc_client_del_client(cmd->client, conn, client_entry);
532 silc_free(client_id);
537 silc_client_command_reply_free(cmd);
540 /* Received reply for command NICK. If everything went without errors
541 we just received our new Client ID. */
543 SILC_CLIENT_CMD_REPLY_FUNC(nick)
545 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
546 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
549 SilcUInt32 argc, len;
551 SILC_LOG_DEBUG(("Start"));
553 if (cmd->error != SILC_STATUS_OK) {
554 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
555 "Cannot set nickname: %s",
556 silc_client_command_status_message(cmd->error));
561 argc = silc_argument_get_arg_num(cmd->args);
562 if (argc < 2 || argc > 2) {
563 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
564 "Cannot set nickname: bad reply to command");
569 /* Take received Client ID */
570 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
571 idp = silc_id_payload_parse(tmp, len);
576 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
578 /* Notify application */
579 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
580 COMMAND_REPLY((ARGS, conn->local_entry));
581 silc_client_command_reply_free(cmd);
585 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
586 silc_client_command_reply_free(cmd);
589 /* Received reply to the LIST command. */
591 SILC_CLIENT_CMD_REPLY_FUNC(list)
593 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
594 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
595 unsigned char *tmp, *name, *topic;
596 SilcUInt32 usercount = 0, len;
597 SilcChannelID *channel_id = NULL;
598 SilcChannelEntry channel_entry;
600 COMMAND_CHECK_STATUS;
602 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
608 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
614 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
620 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
621 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
623 SILC_GET32_MSB(usercount, tmp);
625 /* Check whether the channel exists, and add it to cache if it doesn't. */
626 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
628 if (!channel_entry) {
629 /* Add new channel entry */
630 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
632 if (!channel_entry) {
639 /* Notify application */
640 COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount));
642 /* Pending callbacks are not executed if this was an list entry */
643 if (cmd->status != SILC_STATUS_OK &&
644 cmd->status != SILC_STATUS_LIST_END) {
645 silc_client_command_reply_free(cmd);
650 silc_free(channel_id);
651 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
652 silc_client_command_reply_free(cmd);
655 /* Received reply to topic command. */
657 SILC_CLIENT_CMD_REPLY_FUNC(topic)
659 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
660 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
661 SilcChannelEntry channel;
662 SilcChannelID *channel_id = NULL;
665 SilcUInt32 argc, len;
667 if (cmd->error != SILC_STATUS_OK) {
668 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
669 "%s", silc_client_command_status_message(cmd->error));
674 argc = silc_argument_get_arg_num(cmd->args);
675 if (argc < 1 || argc > 3) {
680 /* Take Channel ID */
681 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
686 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
690 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
694 /* Get the channel entry */
695 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
697 silc_free(channel_id);
702 /* Notify application */
703 COMMAND_REPLY((ARGS, channel, topic));
706 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
707 silc_client_command_reply_free(cmd);
710 /* Received reply to invite command. */
712 SILC_CLIENT_CMD_REPLY_FUNC(invite)
714 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
715 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
716 SilcChannelEntry channel;
717 SilcChannelID *channel_id;
721 if (cmd->error != SILC_STATUS_OK) {
722 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
723 "%s", silc_client_command_status_message(cmd->error));
728 /* Take Channel ID */
729 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
733 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
737 /* Get the channel entry */
738 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
740 silc_free(channel_id);
745 /* Get the invite list */
746 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
748 /* Notify application */
749 COMMAND_REPLY((ARGS, channel, tmp));
752 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
753 silc_client_command_reply_free(cmd);
756 /* Received reply to the KILL command. */
758 SILC_CLIENT_CMD_REPLY_FUNC(kill)
760 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
761 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
763 if (cmd->error != SILC_STATUS_OK) {
764 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
765 "%s", silc_client_command_status_message(cmd->error));
770 /* Notify application */
771 COMMAND_REPLY((ARGS));
774 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
775 silc_client_command_reply_free(cmd);
778 /* Received reply to INFO command. We receive the server ID and some
779 information about the server user requested. */
781 SILC_CLIENT_CMD_REPLY_FUNC(info)
783 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
784 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
786 SilcServerEntry server;
787 SilcServerID *server_id = NULL;
788 char *server_name, *server_info;
791 SILC_LOG_DEBUG(("Start"));
793 if (cmd->error != SILC_STATUS_OK) {
794 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
795 silc_client_command_status_message(cmd->error));
801 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
805 server_id = silc_id_payload_parse_id(tmp, len, NULL);
809 /* Get server name */
810 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
814 /* Get server info */
815 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
819 /* See whether we have this server cached. If not create it. */
820 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
822 SILC_LOG_DEBUG(("New server entry"));
823 server = silc_client_add_server(cmd->client, conn, server_name,
825 silc_id_dup(server_id, SILC_ID_SERVER));
830 /* Notify application */
831 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
834 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
835 silc_free(server_id);
836 silc_client_command_reply_free(cmd);
839 /* Received reply to PING command. The reply time is shown to user. */
841 SILC_CLIENT_CMD_REPLY_FUNC(ping)
843 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
844 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
847 time_t diff, curtime;
849 if (cmd->error != SILC_STATUS_OK) {
850 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
851 "%s", silc_client_command_status_message(cmd->error));
856 curtime = time(NULL);
857 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
858 cmd->packet->src_id_type);
859 if (!id || !conn->ping) {
864 for (i = 0; i < conn->ping_count; i++) {
865 if (!conn->ping[i].dest_id)
867 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
868 diff = curtime - conn->ping[i].start_time;
869 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
870 "Ping reply from %s: %d second%s",
871 conn->ping[i].dest_name, diff,
872 diff == 1 ? "" : "s");
874 conn->ping[i].start_time = 0;
875 silc_free(conn->ping[i].dest_id);
876 conn->ping[i].dest_id = NULL;
877 silc_free(conn->ping[i].dest_name);
878 conn->ping[i].dest_name = NULL;
885 /* Notify application */
886 COMMAND_REPLY((ARGS));
889 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
890 silc_client_command_reply_free(cmd);
893 /* Received reply for JOIN command. */
895 SILC_CLIENT_CMD_REPLY_FUNC(join)
897 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
898 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
899 SilcChannelEntry channel;
901 SilcChannelID *channel_id;
902 SilcUInt32 argc, mode = 0, len, list_count;
903 char *topic, *tmp, *channel_name = NULL, *hmac;
904 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
907 SILC_LOG_DEBUG(("Start"));
909 if (cmd->error != SILC_STATUS_OK) {
910 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
911 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
912 "%s", silc_client_command_status_message(cmd->error));
917 argc = silc_argument_get_arg_num(cmd->args);
918 if (argc < 7 || argc > 14) {
919 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
920 "Cannot join channel: Bad reply packet");
925 /* Get channel name */
926 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
928 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
929 "Cannot join channel: Bad reply packet");
936 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
938 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
939 "Cannot join channel: Bad reply packet");
943 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
949 /* Get channel mode */
950 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
952 SILC_GET32_MSB(mode, tmp);
954 /* Get channel key */
955 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
957 keyp = silc_buffer_alloc(len);
958 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
959 silc_buffer_put(keyp, tmp, len);
963 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
965 /* Check whether we have this channel entry already. */
966 channel = silc_client_get_channel(cmd->client, conn, channel_name);
968 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
969 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
971 /* Create new channel entry */
972 channel = silc_client_add_channel(cmd->client, conn, channel_name,
976 conn->current_channel = channel;
979 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
981 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
982 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
983 "Cannot join channel: Unsupported HMAC `%s'", hmac);
989 /* Get the list count */
990 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
993 SILC_GET32_MSB(list_count, tmp);
995 /* Get Client ID list */
996 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1000 client_id_list = silc_buffer_alloc(len);
1001 silc_buffer_pull_tail(client_id_list, len);
1002 silc_buffer_put(client_id_list, tmp, len);
1004 /* Get client mode list */
1005 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1009 client_mode_list = silc_buffer_alloc(len);
1010 silc_buffer_pull_tail(client_mode_list, len);
1011 silc_buffer_put(client_mode_list, tmp, len);
1013 /* Add clients we received in the reply to the channel */
1014 for (i = 0; i < list_count; i++) {
1017 SilcClientID *client_id;
1018 SilcClientEntry client_entry;
1021 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1023 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1028 SILC_GET32_MSB(mode, client_mode_list->data);
1030 /* Check if we have this client cached already. */
1031 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1032 if (!client_entry) {
1033 /* No, we don't have it, add entry for it. */
1035 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1036 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1039 /* Join client to the channel */
1040 if (!silc_client_on_channel(channel, client_entry)) {
1041 chu = silc_calloc(1, sizeof(*chu));
1042 chu->client = client_entry;
1043 chu->channel = channel;
1045 silc_hash_table_add(channel->user_list, client_entry, chu);
1046 silc_hash_table_add(client_entry->channels, channel, chu);
1049 silc_free(client_id);
1050 silc_buffer_pull(client_id_list, idp_len);
1051 silc_buffer_pull(client_mode_list, 4);
1053 silc_buffer_push(client_id_list, client_id_list->data -
1054 client_id_list->head);
1055 silc_buffer_push(client_mode_list, client_mode_list->data -
1056 client_mode_list->head);
1058 /* Save channel key */
1059 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1060 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1062 /* Notify application */
1063 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1064 keyp ? keyp->head : NULL, NULL,
1065 NULL, topic, hmac, list_count, client_id_list,
1069 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1070 silc_client_command_reply_free(cmd);
1073 silc_buffer_free(keyp);
1075 silc_buffer_free(client_id_list);
1076 if (client_mode_list)
1077 silc_buffer_free(client_mode_list);
1080 /* Received reply for MOTD command */
1082 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1084 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1085 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1087 char *motd = NULL, *cp, line[256];
1089 if (cmd->error != SILC_STATUS_OK) {
1090 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1091 "%s", silc_client_command_status_message(cmd->error));
1092 COMMAND_REPLY_ERROR;
1096 argc = silc_argument_get_arg_num(cmd->args);
1098 COMMAND_REPLY_ERROR;
1103 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1105 COMMAND_REPLY_ERROR;
1112 if (cp[i++] == '\n') {
1113 memset(line, 0, sizeof(line));
1114 strncat(line, cp, i - 1);
1120 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1129 /* Notify application */
1130 COMMAND_REPLY((ARGS, motd));
1133 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1134 silc_client_command_reply_free(cmd);
1137 /* Received reply tot he UMODE command. Save the current user mode */
1139 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1141 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1142 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1146 if (cmd->error != SILC_STATUS_OK) {
1147 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1148 "%s", silc_client_command_status_message(cmd->error));
1149 COMMAND_REPLY_ERROR;
1153 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1155 COMMAND_REPLY_ERROR;
1159 SILC_GET32_MSB(mode, tmp);
1160 conn->local_entry->mode = mode;
1162 /* Notify application */
1163 COMMAND_REPLY((ARGS, mode));
1166 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1167 silc_client_command_reply_free(cmd);
1170 /* Received reply for CMODE command. */
1172 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1174 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1175 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1178 SilcChannelID *channel_id;
1179 SilcChannelEntry channel;
1182 if (cmd->error != SILC_STATUS_OK) {
1183 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1184 "%s", silc_client_command_status_message(cmd->error));
1185 COMMAND_REPLY_ERROR;
1189 /* Take Channel ID */
1190 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1193 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1197 /* Get the channel entry */
1198 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1200 silc_free(channel_id);
1201 COMMAND_REPLY_ERROR;
1205 /* Get channel mode */
1206 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1208 silc_free(channel_id);
1209 COMMAND_REPLY_ERROR;
1214 SILC_GET32_MSB(mode, tmp);
1215 channel->mode = mode;
1217 /* Notify application */
1218 COMMAND_REPLY((ARGS, channel, mode));
1220 silc_free(channel_id);
1223 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1224 silc_client_command_reply_free(cmd);
1227 /* Received reply for CUMODE command */
1229 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1231 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1232 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1233 SilcClientID *client_id;
1234 SilcChannelID *channel_id;
1235 SilcClientEntry client_entry;
1236 SilcChannelEntry channel;
1237 SilcChannelUser chu;
1238 unsigned char *modev, *tmp, *id;
1239 SilcUInt32 len, mode;
1241 if (cmd->error != SILC_STATUS_OK) {
1242 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1243 "%s", silc_client_command_status_message(cmd->error));
1244 COMMAND_REPLY_ERROR;
1248 /* Get channel mode */
1249 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1251 COMMAND_REPLY_ERROR;
1255 /* Take Channel ID */
1256 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1259 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1263 /* Get the channel entry */
1264 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1266 silc_free(channel_id);
1267 COMMAND_REPLY_ERROR;
1272 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1274 silc_free(channel_id);
1275 COMMAND_REPLY_ERROR;
1278 client_id = silc_id_payload_parse_id(id, len, NULL);
1280 silc_free(channel_id);
1281 COMMAND_REPLY_ERROR;
1285 /* Get client entry */
1286 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1287 if (!client_entry) {
1288 silc_free(channel_id);
1289 silc_free(client_id);
1290 COMMAND_REPLY_ERROR;
1295 SILC_GET32_MSB(mode, modev);
1296 chu = silc_client_on_channel(channel, client_entry);
1300 /* Notify application */
1301 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1302 silc_free(client_id);
1303 silc_free(channel_id);
1306 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1307 silc_client_command_reply_free(cmd);
1310 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1312 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1313 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1315 if (cmd->error != SILC_STATUS_OK) {
1316 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1317 "%s", silc_client_command_status_message(cmd->error));
1318 COMMAND_REPLY_ERROR;
1322 /* Notify application */
1323 COMMAND_REPLY((ARGS));
1326 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1327 silc_client_command_reply_free(cmd);
1330 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1332 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1333 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1335 if (cmd->error != SILC_STATUS_OK) {
1336 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1337 "%s", silc_client_command_status_message(cmd->error));
1338 COMMAND_REPLY_ERROR;
1342 /* Notify application */
1343 COMMAND_REPLY((ARGS));
1346 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1347 silc_client_command_reply_free(cmd);
1350 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1352 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1353 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1355 if (cmd->error != SILC_STATUS_OK) {
1356 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1357 "%s", silc_client_command_status_message(cmd->error));
1358 COMMAND_REPLY_ERROR;
1362 /* Notify application */
1363 COMMAND_REPLY((ARGS));
1366 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1367 silc_client_command_reply_free(cmd);
1370 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1372 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1373 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1376 if (cmd->error != SILC_STATUS_OK) {
1377 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1378 "%s", silc_client_command_status_message(cmd->error));
1379 COMMAND_REPLY_ERROR;
1383 /* Notify application */
1384 COMMAND_REPLY((ARGS));
1386 /* Generate the detachment data and deliver it to the client in the
1387 detach client operation */
1388 detach = silc_client_get_detach_data(cmd->client, conn);
1390 cmd->client->internal->ops->detach(cmd->client, conn,
1391 detach->data, detach->len);
1392 silc_buffer_free(detach);
1396 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1397 silc_client_command_reply_free(cmd);
1400 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1402 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1403 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1404 SilcChannelEntry channel;
1405 SilcChannelID *channel_id;
1409 if (cmd->error != SILC_STATUS_OK) {
1410 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1411 "%s", silc_client_command_status_message(cmd->error));
1412 COMMAND_REPLY_ERROR;
1416 /* Take Channel ID */
1417 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1421 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1425 /* Get the channel entry */
1426 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1428 silc_free(channel_id);
1429 COMMAND_REPLY_ERROR;
1433 /* Get the ban list */
1434 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1436 /* Notify application */
1437 COMMAND_REPLY((ARGS, channel, tmp));
1440 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1441 silc_client_command_reply_free(cmd);
1444 /* Reply to LEAVE command. */
1446 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1448 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1449 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1450 SilcChannelID *channel_id;
1451 SilcChannelEntry channel = NULL;
1455 if (cmd->error != SILC_STATUS_OK) {
1456 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1457 "%s", silc_client_command_status_message(cmd->error));
1458 COMMAND_REPLY_ERROR;
1462 /* From protocol version 1.1 we get the channel ID of the left channel */
1463 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1465 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1469 /* Get the channel entry */
1470 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1472 silc_free(channel_id);
1473 COMMAND_REPLY_ERROR;
1477 silc_free(channel_id);
1480 /* Notify application */
1481 COMMAND_REPLY((ARGS, channel));
1484 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1485 silc_client_command_reply_free(cmd);
1488 /* Channel resolving callback for USERS command reply. */
1490 static void silc_client_command_reply_users_cb(SilcClient client,
1491 SilcClientConnection conn,
1492 SilcChannelEntry *channels,
1493 SilcUInt32 channels_count,
1496 if (!channels_count) {
1497 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1498 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1500 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1501 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1502 "%s", silc_client_command_status_message(cmd->error));
1503 COMMAND_REPLY_ERROR;
1504 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1505 silc_client_command_reply_free(cmd);
1509 silc_client_command_reply_users(context, NULL);
1513 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1514 SilcCommandStatus status,
1516 SilcGetChannelCallback get_channel,
1517 SilcCommandCb get_clients)
1519 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1520 SilcChannelEntry channel;
1521 SilcClientEntry client_entry;
1522 SilcChannelUser chu;
1523 SilcChannelID *channel_id = NULL;
1524 SilcBufferStruct client_id_list, client_mode_list;
1526 SilcUInt32 tmp_len, list_count;
1528 unsigned char **res_argv = NULL;
1529 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1531 SILC_LOG_DEBUG(("Start"));
1533 /* Get channel ID */
1534 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1536 COMMAND_REPLY_ERROR;
1539 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1541 COMMAND_REPLY_ERROR;
1545 /* Get the list count */
1546 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1548 COMMAND_REPLY_ERROR;
1551 SILC_GET32_MSB(list_count, tmp);
1553 /* Get Client ID list */
1554 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1556 COMMAND_REPLY_ERROR;
1559 silc_buffer_set(&client_id_list, tmp, tmp_len);
1561 /* Get client mode list */
1562 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1564 COMMAND_REPLY_ERROR;
1567 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1569 /* Get channel entry */
1570 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1572 /* Resolve the channel from server */
1573 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1575 silc_free(channel_id);
1579 /* Cache the received Client ID's and modes. */
1580 for (i = 0; i < list_count; i++) {
1583 SilcClientID *client_id;
1586 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1588 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1593 SILC_GET32_MSB(mode, client_mode_list.data);
1595 /* Check if we have this client cached already. */
1596 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1597 if (!client_entry || !client_entry->username || !client_entry->realname) {
1599 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1600 silc_buffer_pull(&client_id_list, idp_len);
1601 silc_buffer_pull(&client_mode_list, 4);
1604 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1607 /* No we don't have it (or it is incomplete in information), query
1608 it from the server. Assemble argument table that will be sent
1609 for the WHOIS command later. */
1610 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1612 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1614 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1616 res_argv[res_argc] = client_id_list.data;
1617 res_argv_lens[res_argc] = idp_len;
1618 res_argv_types[res_argc] = res_argc + 3;
1621 if (!silc_client_on_channel(channel, client_entry)) {
1622 chu = silc_calloc(1, sizeof(*chu));
1623 chu->client = client_entry;
1625 chu->channel = channel;
1626 silc_hash_table_add(channel->user_list, client_entry, chu);
1627 silc_hash_table_add(client_entry->channels, channel, chu);
1631 silc_free(client_id);
1632 silc_buffer_pull(&client_id_list, idp_len);
1633 silc_buffer_pull(&client_mode_list, 4);
1636 /* Query the client information from server if the list included clients
1637 that we don't know about. */
1641 /* Send the WHOIS command to server */
1642 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1643 silc_client_command_reply_whois_i, 0,
1645 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1646 res_argc, res_argv, res_argv_lens,
1647 res_argv_types, conn->cmd_ident);
1648 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1649 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1652 /* Register pending command callback. After we've received the WHOIS
1653 command reply we will reprocess this command reply by re-calling this
1654 USERS command reply callback. */
1655 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1658 silc_buffer_free(res_cmd);
1659 silc_free(channel_id);
1660 silc_free(res_argv);
1661 silc_free(res_argv_lens);
1662 silc_free(res_argv_types);
1666 silc_buffer_push(&client_id_list, (client_id_list.data -
1667 client_id_list.head));
1668 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1669 client_mode_list.head));
1671 /* Notify application */
1673 COMMAND_REPLY((ARGS, channel, list_count, &client_id_list,
1674 &client_mode_list));
1677 silc_free(channel_id);
1681 /* Reply to USERS command. Received list of client ID's and theirs modes
1682 on the channel we requested. */
1684 SILC_CLIENT_CMD_REPLY_FUNC(users)
1686 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1687 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1689 SILC_LOG_DEBUG(("Start"));
1691 if (cmd->error != SILC_STATUS_OK) {
1692 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1693 "%s", silc_client_command_status_message(cmd->error));
1694 COMMAND_REPLY_ERROR;
1698 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
1699 silc_client_command_reply_users_cb,
1700 silc_client_command_reply_users))
1704 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1705 silc_client_command_reply_free(cmd);
1708 /* Received command reply to GETKEY command. WE've received the remote
1709 client's public key. */
1711 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1713 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1714 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1715 SilcIDPayload idp = NULL;
1716 SilcClientID *client_id = NULL;
1717 SilcClientEntry client_entry;
1718 SilcServerID *server_id = NULL;
1719 SilcServerEntry server_entry;
1721 unsigned char *tmp, *pk;
1725 SilcPublicKey public_key = NULL;
1727 SILC_LOG_DEBUG(("Start"));
1729 if (cmd->error != SILC_STATUS_OK) {
1730 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1731 "%s", silc_client_command_status_message(cmd->error));
1732 COMMAND_REPLY_ERROR;
1736 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1738 COMMAND_REPLY_ERROR;
1741 idp = silc_id_payload_parse(tmp, len);
1743 COMMAND_REPLY_ERROR;
1747 /* Get the public key payload */
1748 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1750 /* Decode the public key */
1751 SILC_GET16_MSB(pk_len, tmp);
1752 SILC_GET16_MSB(type, tmp + 2);
1755 if (type == SILC_SKE_PK_TYPE_SILC)
1756 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1760 id_type = silc_id_payload_get_type(idp);
1761 if (id_type == SILC_ID_CLIENT) {
1762 /* Received client's public key */
1763 client_id = silc_id_payload_get_id(idp);
1764 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1765 if (!client_entry) {
1766 COMMAND_REPLY_ERROR;
1770 /* Notify application */
1771 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1772 } else if (id_type == SILC_ID_SERVER) {
1773 /* Received server's public key */
1774 server_id = silc_id_payload_get_id(idp);
1775 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1776 if (!server_entry) {
1777 COMMAND_REPLY_ERROR;
1781 /* Notify application */
1782 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1786 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1788 silc_id_payload_free(idp);
1790 silc_pkcs_public_key_free(public_key);
1791 silc_free(client_id);
1792 silc_free(server_id);
1793 silc_client_command_reply_free(cmd);
1796 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1798 silc_client_command_reply_free(context);
1802 /******************************************************************************
1804 Internal command reply functions
1806 ******************************************************************************/
1808 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1810 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1811 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1813 SILC_LOG_DEBUG(("Start"));
1815 if (cmd->error != SILC_STATUS_OK)
1818 /* Save WHOIS info */
1819 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1821 /* Pending callbacks are not executed if this was an list entry */
1822 if (cmd->status != SILC_STATUS_OK &&
1823 cmd->status != SILC_STATUS_LIST_END) {
1824 silc_client_command_reply_free(cmd);
1829 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1831 /* If we received notify for invalid ID we'll remove the ID if we
1833 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1834 SilcClientEntry client_entry;
1836 unsigned char *tmp =
1837 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1840 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1842 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1845 silc_client_del_client(cmd->client, conn, client_entry);
1846 silc_free(client_id);
1851 /* Unregister this command reply */
1852 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1853 NULL, silc_client_command_reply_whois_i,
1856 silc_client_command_reply_free(cmd);
1859 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1861 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1862 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1864 SILC_LOG_DEBUG(("Start"));
1866 if (cmd->error != SILC_STATUS_OK)
1869 /* Save IDENTIFY info */
1870 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1872 /* Pending callbacks are not executed if this was an list entry */
1873 if (cmd->status != SILC_STATUS_OK &&
1874 cmd->status != SILC_STATUS_LIST_END) {
1875 silc_client_command_reply_free(cmd);
1880 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1882 /* If we received notify for invalid ID we'll remove the ID if we
1884 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1885 SilcClientEntry client_entry;
1887 unsigned char *tmp =
1888 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1891 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1893 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1896 silc_client_del_client(cmd->client, conn, client_entry);
1897 silc_free(client_id);
1902 /* Unregister this command reply */
1903 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1904 NULL, silc_client_command_reply_identify_i,
1907 silc_client_command_reply_free(cmd);
1910 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1912 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1913 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1915 SilcServerEntry server;
1916 SilcServerID *server_id = NULL;
1917 char *server_name, *server_info;
1920 SILC_LOG_DEBUG(("Start"));
1922 if (cmd->error != SILC_STATUS_OK)
1926 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1930 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1934 /* Get server name */
1935 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1939 /* Get server info */
1940 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1944 /* See whether we have this server cached. If not create it. */
1945 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1947 SILC_LOG_DEBUG(("New server entry"));
1948 silc_client_add_server(cmd->client, conn, server_name, server_info,
1949 silc_id_dup(server_id, SILC_ID_SERVER));
1953 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1954 silc_free(server_id);
1955 silc_client_command_reply_free(cmd);
1958 static void silc_client_command_reply_users_i_cb(SilcClient client,
1959 SilcClientConnection conn,
1960 SilcChannelEntry *channels,
1961 SilcUInt32 channels_count,
1964 if (!channels_count) {
1965 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1966 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1968 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1969 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1970 "%s", silc_client_command_status_message(cmd->error));
1971 COMMAND_REPLY_ERROR;
1972 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1973 silc_client_command_reply_free(cmd);
1977 silc_client_command_reply_users_i(context, NULL);
1980 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
1982 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1984 SILC_LOG_DEBUG(("Start"));
1986 if (cmd->error != SILC_STATUS_OK)
1989 /* Save USERS info */
1990 if (silc_client_command_reply_users_save(
1991 cmd, cmd->status, FALSE,
1992 silc_client_command_reply_users_i_cb,
1993 silc_client_command_reply_users_i))
1997 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1999 /* Unregister this command reply */
2000 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2001 NULL, silc_client_command_reply_users_i,
2004 silc_client_command_reply_free(cmd);
2007 /* Private range commands, specific to this implementation (and compatible
2008 with SILC Server >= 0.9). */
2010 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2012 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2013 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2015 if (cmd->error != SILC_STATUS_OK) {
2016 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2017 "%s", silc_client_command_status_message(cmd->error));
2018 COMMAND_REPLY_ERROR;
2022 /* Notify application */
2023 COMMAND_REPLY((ARGS));
2026 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2027 silc_client_command_reply_free(cmd);
2030 SILC_CLIENT_CMD_REPLY_FUNC(close)
2032 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2033 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2035 if (cmd->error != SILC_STATUS_OK) {
2036 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2037 "%s", silc_client_command_status_message(cmd->error));
2038 COMMAND_REPLY_ERROR;
2042 /* Notify application */
2043 COMMAND_REPLY((ARGS));
2046 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2047 silc_client_command_reply_free(cmd);
2050 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2052 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2053 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2055 if (cmd->error != SILC_STATUS_OK) {
2056 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2057 "%s", silc_client_command_status_message(cmd->error));
2058 COMMAND_REPLY_ERROR;
2062 /* Notify application */
2063 COMMAND_REPLY((ARGS));
2066 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2067 silc_client_command_reply_free(cmd);