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" },
82 /* Command reply operation that is called at the end of all command replys.
83 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
84 #define COMMAND_REPLY(args) cmd->client->internal->ops->command_reply args
85 #define ARGS cmd->client, cmd->sock->user_data, \
86 cmd->payload, TRUE, silc_command_get(cmd->payload), cmd->status
88 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
89 #define COMMAND_REPLY_ERROR cmd->client->internal->ops-> \
90 command_reply(cmd->client, cmd->sock->user_data, cmd->payload, \
91 FALSE, silc_command_get(cmd->payload), cmd->status)
93 #define SAY cmd->client->internal->ops->say
95 /* All functions that call the COMMAND_CHECK_STATUS or the
96 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
98 #define COMMAND_CHECK_STATUS \
100 SILC_LOG_DEBUG(("Start")); \
101 if (cmd->status != SILC_STATUS_OK) { \
102 COMMAND_REPLY_ERROR; \
107 #define COMMAND_CHECK_STATUS_LIST \
109 SILC_LOG_DEBUG(("Start")); \
110 if (cmd->status != SILC_STATUS_OK && \
111 cmd->status != SILC_STATUS_LIST_START && \
112 cmd->status != SILC_STATUS_LIST_ITEM && \
113 cmd->status != SILC_STATUS_LIST_END) { \
114 COMMAND_REPLY_ERROR; \
119 /* Process received command reply. */
121 void silc_client_command_reply_process(SilcClient client,
122 SilcSocketConnection sock,
123 SilcPacketContext *packet)
125 SilcBuffer buffer = packet->buffer;
126 SilcClientCommand cmd;
127 SilcClientCommandReplyContext ctx;
128 SilcCommandPayload payload;
130 SilcCommandCb reply = NULL;
132 /* Get command reply payload from packet */
133 payload = silc_command_payload_parse(buffer->data, buffer->len);
135 /* Silently ignore bad reply packet */
136 SILC_LOG_DEBUG(("Bad command reply packet"));
140 /* Allocate command reply context. This must be free'd by the
141 command reply routine receiving it. */
142 ctx = silc_calloc(1, sizeof(*ctx));
143 ctx->client = client;
145 ctx->payload = payload;
146 ctx->status = silc_command_get_status(ctx->payload);
147 ctx->args = silc_command_get_args(ctx->payload);
148 ctx->packet = packet;
149 ctx->ident = silc_command_get_ident(ctx->payload);
151 /* Check for pending commands and mark to be exeucted */
152 silc_client_command_pending_check(sock->user_data, ctx,
153 silc_command_get(ctx->payload),
156 /* Execute command reply */
158 command = silc_command_get(ctx->payload);
160 /* Try to find matching the command identifier */
161 silc_list_start(client->internal->commands);
162 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
163 if (cmd->cmd == command && !cmd->ident)
165 if (cmd->cmd == command && cmd->ident == ctx->ident) {
166 (*cmd->reply)((void *)ctx, NULL);
171 if (cmd == SILC_LIST_END) {
173 /* No specific identifier for command reply, call first one found */
180 /* Returns status message string */
182 char *silc_client_command_status_message(SilcCommandStatus status)
186 for (i = 0; silc_command_status_messages[i].message; i++) {
187 if (silc_command_status_messages[i].status == status)
191 if (silc_command_status_messages[i].message == NULL)
194 return silc_command_status_messages[i].message;
197 /* Free command reply context and its internals. */
199 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
202 silc_command_payload_free(cmd->payload);
208 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
209 SilcCommandStatus status,
212 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
213 SilcClientID *client_id;
214 SilcClientEntry client_entry = NULL;
217 unsigned char *id_data, *tmp;
218 char *nickname = NULL, *username = NULL;
219 char *realname = NULL;
220 SilcUInt32 idle = 0, mode = 0;
221 SilcBuffer channels = NULL;
222 unsigned char *fingerprint;
223 SilcUInt32 fingerprint_len;
225 argc = silc_argument_get_arg_num(cmd->args);
227 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
234 client_id = silc_id_payload_parse_id(id_data, len, NULL);
241 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
242 username = silc_argument_get_arg_type(cmd->args, 4, &len);
243 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
244 if (!nickname || !username || !realname) {
250 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
252 channels = silc_buffer_alloc(len);
253 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
254 silc_buffer_put(channels, tmp, len);
257 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
259 SILC_GET32_MSB(mode, tmp);
261 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
263 SILC_GET32_MSB(idle, tmp);
265 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
267 /* Check if we have this client cached already. */
268 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
270 SILC_LOG_DEBUG(("Adding new client entry"));
272 silc_client_add_client(cmd->client, conn, nickname, username, realname,
275 silc_client_update_client(cmd->client, conn, client_entry,
276 nickname, username, realname, mode);
277 silc_free(client_id);
280 if (fingerprint && !client_entry->fingerprint) {
281 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
282 client_entry->fingerprint_len = fingerprint_len;
285 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
286 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
288 /* Notify application */
289 if (!cmd->callback && notify)
290 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
291 channels, mode, idle, fingerprint));
294 silc_buffer_free(channels);
297 /* Received reply for WHOIS command. This maybe called several times
298 for one WHOIS command as server may reply with list of results. */
300 SILC_CLIENT_CMD_REPLY_FUNC(whois)
302 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
303 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
305 COMMAND_CHECK_STATUS_LIST;
307 /* Save WHOIS info */
308 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
310 /* Pending callbacks are not executed if this was an list entry */
311 if (cmd->status != SILC_STATUS_OK &&
312 cmd->status != SILC_STATUS_LIST_END) {
313 silc_client_command_reply_free(cmd);
318 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
320 /* If we received notify for invalid ID we'll remove the ID if we
322 if (cmd->status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
323 SilcClientEntry client_entry;
326 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
329 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
331 client_entry = silc_client_get_client_by_id(cmd->client, conn,
334 silc_client_del_client(cmd->client, conn, client_entry);
335 silc_free(client_id);
340 silc_client_command_reply_free(cmd);
343 /* Received reply for WHOWAS command. */
345 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
347 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
348 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
349 SilcClientID *client_id;
350 SilcClientEntry client_entry = NULL;
352 unsigned char *id_data;
353 char *nickname, *username;
354 char *realname = NULL;
356 COMMAND_CHECK_STATUS_LIST;
358 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
364 client_id = silc_id_payload_parse_id(id_data, len, NULL);
370 /* Get the client entry, if exists */
371 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
372 silc_free(client_id);
374 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
375 username = silc_argument_get_arg_type(cmd->args, 4, &len);
376 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
377 if (!nickname || !username) {
382 /* Notify application. We don't save any history information to any
383 cache. Just pass the data to the application for displaying on
385 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
387 /* Pending callbacks are not executed if this was an list entry */
388 if (cmd->status != SILC_STATUS_OK &&
389 cmd->status != SILC_STATUS_LIST_END) {
390 silc_client_command_reply_free(cmd);
395 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
396 silc_client_command_reply_free(cmd);
400 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
401 SilcCommandStatus status,
404 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
405 SilcClient client = cmd->client;
406 SilcClientID *client_id = NULL;
407 SilcServerID *server_id = NULL;
408 SilcChannelID *channel_id = NULL;
409 SilcClientEntry client_entry;
410 SilcServerEntry server_entry;
411 SilcChannelEntry channel_entry;
414 unsigned char *id_data;
415 char *name = NULL, *info = NULL;
416 SilcIDPayload idp = NULL;
419 argc = silc_argument_get_arg_num(cmd->args);
421 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
427 idp = silc_id_payload_parse(id_data, len);
434 name = silc_argument_get_arg_type(cmd->args, 3, &len);
435 info = silc_argument_get_arg_type(cmd->args, 4, &len);
437 id_type = silc_id_payload_get_type(idp);
441 client_id = silc_id_payload_get_id(idp);
443 SILC_LOG_DEBUG(("Received client information"));
445 /* Check if we have this client cached already. */
446 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
448 SILC_LOG_DEBUG(("Adding new client entry"));
450 silc_client_add_client(cmd->client, conn, name, info, NULL,
451 silc_id_dup(client_id, id_type), 0);
453 silc_client_update_client(cmd->client, conn, client_entry,
454 name, info, NULL, 0);
457 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
458 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
460 /* Notify application */
462 COMMAND_REPLY((ARGS, client_entry, name, info));
466 server_id = silc_id_payload_get_id(idp);
468 SILC_LOG_DEBUG(("Received server information"));
470 /* Check if we have this server cached already. */
471 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
473 SILC_LOG_DEBUG(("Adding new server entry"));
474 server_entry = silc_client_add_server(cmd->client, conn, name, info,
475 silc_id_dup(server_id, id_type));
483 /* Notify application */
485 COMMAND_REPLY((ARGS, server_entry, name, info));
488 case SILC_ID_CHANNEL:
489 channel_id = silc_id_payload_get_id(idp);
491 SILC_LOG_DEBUG(("Received channel information"));
493 /* Check if we have this channel cached already. */
494 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
495 if (!channel_entry) {
499 /* Add new channel entry */
500 channel_entry = silc_client_add_channel(client, conn, name, 0,
505 /* Notify application */
507 COMMAND_REPLY((ARGS, channel_entry, name, info));
511 silc_id_payload_free(idp);
512 silc_free(client_id);
513 silc_free(server_id);
514 silc_free(channel_id);
517 /* Received reply for IDENTIFY command. This maybe called several times
518 for one IDENTIFY command as server may reply with list of results.
519 This is totally silent and does not print anything on screen. */
521 SILC_CLIENT_CMD_REPLY_FUNC(identify)
523 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
524 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
526 COMMAND_CHECK_STATUS_LIST;
528 /* Save IDENTIFY info */
529 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
531 /* Pending callbacks are not executed if this was an list entry */
532 if (cmd->status != SILC_STATUS_OK &&
533 cmd->status != SILC_STATUS_LIST_END) {
534 silc_client_command_reply_free(cmd);
539 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
541 /* If we received notify for invalid ID we'll remove the ID if we
543 if (cmd->status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
544 SilcClientEntry client_entry;
547 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
550 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
552 client_entry = silc_client_get_client_by_id(cmd->client, conn,
555 silc_client_del_client(cmd->client, conn, client_entry);
556 silc_free(client_id);
561 silc_client_command_reply_free(cmd);
564 /* Received reply for command NICK. If everything went without errors
565 we just received our new Client ID. */
567 SILC_CLIENT_CMD_REPLY_FUNC(nick)
569 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
570 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
573 SilcUInt32 argc, len;
575 SILC_LOG_DEBUG(("Start"));
577 if (cmd->status != SILC_STATUS_OK) {
578 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
579 "Cannot set nickname: %s",
580 silc_client_command_status_message(cmd->status));
585 argc = silc_argument_get_arg_num(cmd->args);
586 if (argc < 2 || argc > 2) {
587 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
588 "Cannot set nickname: bad reply to command");
593 /* Take received Client ID */
594 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
595 idp = silc_id_payload_parse(tmp, len);
600 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
602 /* Notify application */
603 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
604 COMMAND_REPLY((ARGS, conn->local_entry));
605 silc_client_command_reply_free(cmd);
609 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
610 silc_client_command_reply_free(cmd);
613 /* Received reply to the LIST command. */
615 SILC_CLIENT_CMD_REPLY_FUNC(list)
617 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
618 unsigned char *tmp, *name, *topic;
619 SilcUInt32 usercount = 0;
621 COMMAND_CHECK_STATUS_LIST;
623 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
624 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
625 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
627 SILC_GET32_MSB(usercount, tmp);
629 /* Notify application */
630 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
632 /* Pending callbacks are not executed if this was an list entry */
633 if (cmd->status != SILC_STATUS_OK &&
634 cmd->status != SILC_STATUS_LIST_END) {
635 silc_client_command_reply_free(cmd);
640 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
641 silc_client_command_reply_free(cmd);
644 /* Received reply to topic command. */
646 SILC_CLIENT_CMD_REPLY_FUNC(topic)
648 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
649 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
650 SilcChannelEntry channel;
651 SilcChannelID *channel_id = NULL;
654 SilcUInt32 argc, len;
656 if (cmd->status != SILC_STATUS_OK) {
657 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
658 "%s", silc_client_command_status_message(cmd->status));
663 argc = silc_argument_get_arg_num(cmd->args);
664 if (argc < 1 || argc > 3) {
669 /* Take Channel ID */
670 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
675 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
679 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
683 /* Get the channel entry */
684 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
686 silc_free(channel_id);
691 /* Notify application */
692 COMMAND_REPLY((ARGS, channel, topic));
695 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
696 silc_client_command_reply_free(cmd);
699 /* Received reply to invite command. */
701 SILC_CLIENT_CMD_REPLY_FUNC(invite)
703 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
704 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
705 SilcChannelEntry channel;
706 SilcChannelID *channel_id;
710 if (cmd->status != SILC_STATUS_OK) {
711 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
712 "%s", silc_client_command_status_message(cmd->status));
717 /* Take Channel ID */
718 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
722 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
726 /* Get the channel entry */
727 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
729 silc_free(channel_id);
734 /* Get the invite list */
735 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
737 /* Notify application */
738 COMMAND_REPLY((ARGS, channel, tmp));
741 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
742 silc_client_command_reply_free(cmd);
745 /* Received reply to the KILL command. */
747 SILC_CLIENT_CMD_REPLY_FUNC(kill)
749 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
750 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
752 if (cmd->status != SILC_STATUS_OK) {
753 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
754 "%s", silc_client_command_status_message(cmd->status));
759 /* Notify application */
760 COMMAND_REPLY((ARGS));
763 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
764 silc_client_command_reply_free(cmd);
767 /* Received reply to INFO command. We receive the server ID and some
768 information about the server user requested. */
770 SILC_CLIENT_CMD_REPLY_FUNC(info)
772 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
773 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
775 SilcServerEntry server;
776 SilcServerID *server_id = NULL;
777 char *server_name, *server_info;
780 SILC_LOG_DEBUG(("Start"));
782 if (cmd->status != SILC_STATUS_OK) {
783 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
784 silc_client_command_status_message(cmd->status));
790 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
794 server_id = silc_id_payload_parse_id(tmp, len, NULL);
798 /* Get server name */
799 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
803 /* Get server info */
804 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
808 /* See whether we have this server cached. If not create it. */
809 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
811 SILC_LOG_DEBUG(("New server entry"));
812 server = silc_client_add_server(cmd->client, conn, server_name,
814 silc_id_dup(server_id, SILC_ID_SERVER));
819 /* Notify application */
820 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
823 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
824 silc_free(server_id);
825 silc_client_command_reply_free(cmd);
828 /* Received reply to PING command. The reply time is shown to user. */
830 SILC_CLIENT_CMD_REPLY_FUNC(ping)
832 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
833 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
836 time_t diff, curtime;
838 if (cmd->status != SILC_STATUS_OK) {
839 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
840 "%s", silc_client_command_status_message(cmd->status));
845 curtime = time(NULL);
846 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
847 cmd->packet->src_id_type);
848 if (!id || !conn->ping) {
853 for (i = 0; i < conn->ping_count; i++) {
854 if (!conn->ping[i].dest_id)
856 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
857 diff = curtime - conn->ping[i].start_time;
858 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
859 "Ping reply from %s: %d second%s",
860 conn->ping[i].dest_name, diff,
861 diff == 1 ? "" : "s");
863 conn->ping[i].start_time = 0;
864 silc_free(conn->ping[i].dest_id);
865 conn->ping[i].dest_id = NULL;
866 silc_free(conn->ping[i].dest_name);
867 conn->ping[i].dest_name = NULL;
874 /* Notify application */
875 COMMAND_REPLY((ARGS));
878 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
879 silc_client_command_reply_free(cmd);
882 /* Received reply for JOIN command. */
884 SILC_CLIENT_CMD_REPLY_FUNC(join)
886 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
887 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
888 SilcChannelEntry channel;
890 SilcChannelID *channel_id;
891 SilcUInt32 argc, mode = 0, len, list_count;
892 char *topic, *tmp, *channel_name = NULL, *hmac;
893 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
896 SILC_LOG_DEBUG(("Start"));
898 if (cmd->status != SILC_STATUS_OK) {
899 if (cmd->status != SILC_STATUS_ERR_USER_ON_CHANNEL)
900 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
901 "%s", silc_client_command_status_message(cmd->status));
906 argc = silc_argument_get_arg_num(cmd->args);
907 if (argc < 7 || argc > 14) {
908 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
909 "Cannot join channel: Bad reply packet");
914 /* Get channel name */
915 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
917 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
918 "Cannot join channel: Bad reply packet");
925 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
927 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
928 "Cannot join channel: Bad reply packet");
932 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
938 /* Get channel mode */
939 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
941 SILC_GET32_MSB(mode, tmp);
943 /* Get channel key */
944 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
946 keyp = silc_buffer_alloc(len);
947 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
948 silc_buffer_put(keyp, tmp, len);
952 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
954 /* Check whether we have this channel entry already. */
955 channel = silc_client_get_channel(cmd->client, conn, channel_name);
957 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
958 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
960 /* Create new channel entry */
961 channel = silc_client_add_channel(cmd->client, conn, channel_name,
965 conn->current_channel = channel;
968 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
970 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
971 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
972 "Cannot join channel: Unsupported HMAC `%s'", hmac);
978 /* Get the list count */
979 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
982 SILC_GET32_MSB(list_count, tmp);
984 /* Get Client ID list */
985 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
989 client_id_list = silc_buffer_alloc(len);
990 silc_buffer_pull_tail(client_id_list, len);
991 silc_buffer_put(client_id_list, tmp, len);
993 /* Get client mode list */
994 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
998 client_mode_list = silc_buffer_alloc(len);
999 silc_buffer_pull_tail(client_mode_list, len);
1000 silc_buffer_put(client_mode_list, tmp, len);
1002 /* Add clients we received in the reply to the channel */
1003 for (i = 0; i < list_count; i++) {
1006 SilcClientID *client_id;
1007 SilcClientEntry client_entry;
1010 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1012 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1017 SILC_GET32_MSB(mode, client_mode_list->data);
1019 /* Check if we have this client cached already. */
1020 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1021 if (!client_entry) {
1022 /* No, we don't have it, add entry for it. */
1024 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1025 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1028 /* Join client to the channel */
1029 if (!silc_client_on_channel(channel, client_entry)) {
1030 chu = silc_calloc(1, sizeof(*chu));
1031 chu->client = client_entry;
1032 chu->channel = channel;
1034 silc_hash_table_add(channel->user_list, client_entry, chu);
1035 silc_hash_table_add(client_entry->channels, channel, chu);
1038 silc_free(client_id);
1039 silc_buffer_pull(client_id_list, idp_len);
1040 silc_buffer_pull(client_mode_list, 4);
1042 silc_buffer_push(client_id_list, client_id_list->data -
1043 client_id_list->head);
1044 silc_buffer_push(client_mode_list, client_mode_list->data -
1045 client_mode_list->head);
1047 /* Save channel key */
1048 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1049 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1051 /* Notify application */
1052 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1053 keyp ? keyp->head : NULL, NULL,
1054 NULL, topic, hmac, list_count, client_id_list,
1058 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1059 silc_client_command_reply_free(cmd);
1062 silc_buffer_free(keyp);
1064 silc_buffer_free(client_id_list);
1065 if (client_mode_list)
1066 silc_buffer_free(client_mode_list);
1069 /* Received reply for MOTD command */
1071 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1073 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1074 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1076 char *motd = NULL, *cp, line[256];
1078 if (cmd->status != SILC_STATUS_OK) {
1079 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1080 "%s", silc_client_command_status_message(cmd->status));
1081 COMMAND_REPLY_ERROR;
1085 argc = silc_argument_get_arg_num(cmd->args);
1087 COMMAND_REPLY_ERROR;
1092 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1094 COMMAND_REPLY_ERROR;
1101 if (cp[i++] == '\n') {
1102 memset(line, 0, sizeof(line));
1103 strncat(line, cp, i - 1);
1109 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1118 /* Notify application */
1119 COMMAND_REPLY((ARGS, motd));
1122 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1123 silc_client_command_reply_free(cmd);
1126 /* Received reply tot he UMODE command. Save the current user mode */
1128 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1130 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1131 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1135 if (cmd->status != SILC_STATUS_OK) {
1136 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1137 "%s", silc_client_command_status_message(cmd->status));
1138 COMMAND_REPLY_ERROR;
1142 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1144 COMMAND_REPLY_ERROR;
1148 SILC_GET32_MSB(mode, tmp);
1149 conn->local_entry->mode = mode;
1151 /* Notify application */
1152 COMMAND_REPLY((ARGS, mode));
1155 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1156 silc_client_command_reply_free(cmd);
1159 /* Received reply for CMODE command. */
1161 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1163 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1164 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1167 SilcChannelID *channel_id;
1168 SilcChannelEntry channel;
1171 if (cmd->status != SILC_STATUS_OK) {
1172 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1173 "%s", silc_client_command_status_message(cmd->status));
1174 COMMAND_REPLY_ERROR;
1178 /* Take Channel ID */
1179 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1182 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1186 /* Get the channel entry */
1187 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1189 silc_free(channel_id);
1190 COMMAND_REPLY_ERROR;
1194 /* Get channel mode */
1195 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1197 silc_free(channel_id);
1198 COMMAND_REPLY_ERROR;
1203 SILC_GET32_MSB(mode, tmp);
1204 channel->mode = mode;
1206 /* Notify application */
1207 COMMAND_REPLY((ARGS, channel, mode));
1209 silc_free(channel_id);
1212 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1213 silc_client_command_reply_free(cmd);
1216 /* Received reply for CUMODE command */
1218 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1220 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1221 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1222 SilcClientID *client_id;
1223 SilcChannelID *channel_id;
1224 SilcClientEntry client_entry;
1225 SilcChannelEntry channel;
1226 SilcChannelUser chu;
1227 unsigned char *modev, *tmp, *id;
1228 SilcUInt32 len, mode;
1230 if (cmd->status != SILC_STATUS_OK) {
1231 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1232 "%s", silc_client_command_status_message(cmd->status));
1233 COMMAND_REPLY_ERROR;
1237 /* Get channel mode */
1238 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1240 COMMAND_REPLY_ERROR;
1244 /* Take Channel ID */
1245 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1248 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1252 /* Get the channel entry */
1253 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1255 silc_free(channel_id);
1256 COMMAND_REPLY_ERROR;
1261 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1263 silc_free(channel_id);
1264 COMMAND_REPLY_ERROR;
1267 client_id = silc_id_payload_parse_id(id, len, NULL);
1269 silc_free(channel_id);
1270 COMMAND_REPLY_ERROR;
1274 /* Get client entry */
1275 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1276 if (!client_entry) {
1277 silc_free(channel_id);
1278 silc_free(client_id);
1279 COMMAND_REPLY_ERROR;
1284 SILC_GET32_MSB(mode, modev);
1285 chu = silc_client_on_channel(channel, client_entry);
1289 /* Notify application */
1290 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1291 silc_free(client_id);
1292 silc_free(channel_id);
1295 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1296 silc_client_command_reply_free(cmd);
1299 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1301 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1302 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1304 if (cmd->status != SILC_STATUS_OK) {
1305 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1306 "%s", silc_client_command_status_message(cmd->status));
1307 COMMAND_REPLY_ERROR;
1311 /* Notify application */
1312 COMMAND_REPLY((ARGS));
1315 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1316 silc_client_command_reply_free(cmd);
1319 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1321 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1322 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1324 if (cmd->status != SILC_STATUS_OK) {
1325 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1326 "%s", silc_client_command_status_message(cmd->status));
1327 COMMAND_REPLY_ERROR;
1331 /* Notify application */
1332 COMMAND_REPLY((ARGS));
1335 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1336 silc_client_command_reply_free(cmd);
1339 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1341 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1342 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1344 if (cmd->status != SILC_STATUS_OK) {
1345 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1346 "%s", silc_client_command_status_message(cmd->status));
1347 COMMAND_REPLY_ERROR;
1351 /* Notify application */
1352 COMMAND_REPLY((ARGS));
1355 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1356 silc_client_command_reply_free(cmd);
1359 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1361 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1362 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1364 if (cmd->status != SILC_STATUS_OK) {
1365 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1366 "%s", silc_client_command_status_message(cmd->status));
1367 COMMAND_REPLY_ERROR;
1371 /* Notify application */
1372 COMMAND_REPLY((ARGS));
1375 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1376 silc_client_command_reply_free(cmd);
1379 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1381 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1382 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1383 SilcChannelEntry channel;
1384 SilcChannelID *channel_id;
1388 if (cmd->status != SILC_STATUS_OK) {
1389 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1390 "%s", silc_client_command_status_message(cmd->status));
1391 COMMAND_REPLY_ERROR;
1395 /* Take Channel ID */
1396 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1400 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1404 /* Get the channel entry */
1405 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1407 silc_free(channel_id);
1408 COMMAND_REPLY_ERROR;
1412 /* Get the ban list */
1413 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1415 /* Notify application */
1416 COMMAND_REPLY((ARGS, channel, tmp));
1419 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1420 silc_client_command_reply_free(cmd);
1423 SILC_CLIENT_CMD_REPLY_FUNC(close)
1425 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1426 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1428 if (cmd->status != SILC_STATUS_OK) {
1429 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1430 "%s", silc_client_command_status_message(cmd->status));
1431 COMMAND_REPLY_ERROR;
1435 /* Notify application */
1436 COMMAND_REPLY((ARGS));
1439 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1440 silc_client_command_reply_free(cmd);
1443 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1445 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1446 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1448 if (cmd->status != SILC_STATUS_OK) {
1449 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1450 "%s", silc_client_command_status_message(cmd->status));
1451 COMMAND_REPLY_ERROR;
1455 /* Notify application */
1456 COMMAND_REPLY((ARGS));
1459 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1460 silc_client_command_reply_free(cmd);
1463 /* Reply to LEAVE command. */
1465 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1467 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1468 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1470 if (cmd->status != SILC_STATUS_OK) {
1471 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1472 "%s", silc_client_command_status_message(cmd->status));
1473 COMMAND_REPLY_ERROR;
1477 /* Notify application */
1478 COMMAND_REPLY((ARGS));
1481 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1482 silc_client_command_reply_free(cmd);
1485 /* Channel resolving callback for USERS command reply. */
1487 static void silc_client_command_reply_users_cb(SilcClient client,
1488 SilcClientConnection conn,
1489 SilcChannelEntry *channels,
1490 SilcUInt32 channels_count,
1493 if (!channels_count) {
1494 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1495 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1496 SilcCommandStatus status = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1498 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1499 "%s", silc_client_command_status_message(status));
1500 COMMAND_REPLY_ERROR;
1501 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1502 silc_client_command_reply_free(cmd);
1506 silc_client_command_reply_users(context, NULL);
1509 /* Reply to USERS command. Received list of client ID's and theirs modes
1510 on the channel we requested. */
1512 SILC_CLIENT_CMD_REPLY_FUNC(users)
1514 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1515 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1516 SilcChannelEntry channel;
1517 SilcClientEntry client_entry;
1518 SilcChannelUser chu;
1519 SilcChannelID *channel_id = NULL;
1520 SilcBuffer client_id_list = NULL;
1521 SilcBuffer client_mode_list = NULL;
1523 SilcUInt32 tmp_len, list_count;
1525 unsigned char **res_argv = NULL;
1526 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1528 SILC_LOG_DEBUG(("Start"));
1530 if (cmd->status != SILC_STATUS_OK) {
1531 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1532 "%s", silc_client_command_status_message(cmd->status));
1533 COMMAND_REPLY_ERROR;
1537 /* Get channel ID */
1538 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1540 COMMAND_REPLY_ERROR;
1543 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1545 COMMAND_REPLY_ERROR;
1549 /* Get the list count */
1550 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1552 COMMAND_REPLY_ERROR;
1555 SILC_GET32_MSB(list_count, tmp);
1557 /* Get Client ID list */
1558 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1560 COMMAND_REPLY_ERROR;
1564 client_id_list = silc_buffer_alloc(tmp_len);
1565 silc_buffer_pull_tail(client_id_list, tmp_len);
1566 silc_buffer_put(client_id_list, tmp, tmp_len);
1568 /* Get client mode list */
1569 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1571 COMMAND_REPLY_ERROR;
1575 client_mode_list = silc_buffer_alloc(tmp_len);
1576 silc_buffer_pull_tail(client_mode_list, tmp_len);
1577 silc_buffer_put(client_mode_list, tmp, tmp_len);
1579 /* Get channel entry */
1580 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1582 /* Resolve the channel from server */
1583 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1584 silc_client_command_reply_users_cb,
1586 silc_free(channel_id);
1588 silc_buffer_free(client_id_list);
1589 if (client_mode_list)
1590 silc_buffer_free(client_mode_list);
1594 /* Cache the received Client ID's and modes. */
1595 for (i = 0; i < list_count; i++) {
1598 SilcClientID *client_id;
1601 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1603 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1608 SILC_GET32_MSB(mode, client_mode_list->data);
1610 /* Check if we have this client cached already. */
1611 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1612 if (!client_entry || !client_entry->username || !client_entry->realname) {
1614 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1615 silc_buffer_pull(client_id_list, idp_len);
1616 silc_buffer_pull(client_mode_list, 4);
1619 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1622 /* No we don't have it (or it is incomplete in information), query
1623 it from the server. Assemble argument table that will be sent
1624 for the WHOIS command later. */
1625 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1627 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1629 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1631 res_argv[res_argc] = client_id_list->data;
1632 res_argv_lens[res_argc] = idp_len;
1633 res_argv_types[res_argc] = res_argc + 3;
1636 if (!silc_client_on_channel(channel, client_entry)) {
1637 chu = silc_calloc(1, sizeof(*chu));
1638 chu->client = client_entry;
1640 chu->channel = channel;
1641 silc_hash_table_add(channel->user_list, client_entry, chu);
1642 silc_hash_table_add(client_entry->channels, channel, chu);
1646 silc_free(client_id);
1647 silc_buffer_pull(client_id_list, idp_len);
1648 silc_buffer_pull(client_mode_list, 4);
1651 /* Query the client information from server if the list included clients
1652 that we don't know about. */
1656 /* Send the WHOIS command to server */
1657 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1658 silc_client_command_reply_whois_i, 0,
1660 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1661 res_argc, res_argv, res_argv_lens,
1662 res_argv_types, conn->cmd_ident);
1663 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1664 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1667 /* Register pending command callback. After we've received the WHOIS
1668 command reply we will reprocess this command reply by re-calling this
1669 USERS command reply callback. */
1670 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1671 silc_client_command_reply_users, cmd);
1673 silc_buffer_free(res_cmd);
1674 silc_free(channel_id);
1675 silc_free(res_argv);
1676 silc_free(res_argv_lens);
1677 silc_free(res_argv_types);
1679 silc_buffer_free(client_id_list);
1680 if (client_mode_list)
1681 silc_buffer_free(client_mode_list);
1685 silc_buffer_push(client_id_list, (client_id_list->data -
1686 client_id_list->head));
1687 silc_buffer_push(client_mode_list, (client_mode_list->data -
1688 client_mode_list->head));
1690 /* Notify application */
1691 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1694 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1695 silc_client_command_reply_free(cmd);
1696 silc_free(channel_id);
1698 silc_buffer_free(client_id_list);
1699 if (client_mode_list)
1700 silc_buffer_free(client_mode_list);
1703 /* Received command reply to GETKEY command. WE've received the remote
1704 client's public key. */
1706 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1708 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1709 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1710 SilcIDPayload idp = NULL;
1711 SilcClientID *client_id = NULL;
1712 SilcClientEntry client_entry;
1713 SilcServerID *server_id = NULL;
1714 SilcServerEntry server_entry;
1716 unsigned char *tmp, *pk;
1720 SilcPublicKey public_key = NULL;
1722 SILC_LOG_DEBUG(("Start"));
1724 if (cmd->status != SILC_STATUS_OK) {
1725 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1726 "%s", silc_client_command_status_message(cmd->status));
1727 COMMAND_REPLY_ERROR;
1731 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1733 COMMAND_REPLY_ERROR;
1736 idp = silc_id_payload_parse(tmp, len);
1738 COMMAND_REPLY_ERROR;
1742 /* Get the public key payload */
1743 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1745 /* Decode the public key */
1746 SILC_GET16_MSB(pk_len, tmp);
1747 SILC_GET16_MSB(type, tmp + 2);
1750 if (type == SILC_SKE_PK_TYPE_SILC)
1751 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1755 id_type = silc_id_payload_get_type(idp);
1756 if (id_type == SILC_ID_CLIENT) {
1757 /* Received client's public key */
1758 client_id = silc_id_payload_get_id(idp);
1759 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1760 if (!client_entry) {
1761 COMMAND_REPLY_ERROR;
1765 /* Notify application */
1766 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1767 } else if (id_type == SILC_ID_SERVER) {
1768 /* Received server's public key */
1769 server_id = silc_id_payload_get_id(idp);
1770 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1771 if (!server_entry) {
1772 COMMAND_REPLY_ERROR;
1776 /* Notify application */
1777 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1781 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1783 silc_id_payload_free(idp);
1785 silc_pkcs_public_key_free(public_key);
1786 silc_free(client_id);
1787 silc_free(server_id);
1788 silc_client_command_reply_free(cmd);
1791 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1793 silc_client_command_reply_free(context);
1797 /******************************************************************************
1799 Internal command reply functions
1801 ******************************************************************************/
1803 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1805 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1806 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1808 SILC_LOG_DEBUG(("Start"));
1810 if (cmd->status != SILC_STATUS_OK &&
1811 cmd->status != SILC_STATUS_LIST_START &&
1812 cmd->status != SILC_STATUS_LIST_ITEM &&
1813 cmd->status != SILC_STATUS_LIST_END)
1816 /* Save WHOIS info */
1817 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1819 /* Pending callbacks are not executed if this was an list entry */
1820 if (cmd->status != SILC_STATUS_OK &&
1821 cmd->status != SILC_STATUS_LIST_END) {
1822 silc_client_command_reply_free(cmd);
1827 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1829 /* If we received notify for invalid ID we'll remove the ID if we
1831 if (cmd->status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1832 SilcClientEntry client_entry;
1834 unsigned char *tmp =
1835 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1838 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1840 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1843 silc_client_del_client(cmd->client, conn, client_entry);
1844 silc_free(client_id);
1849 /* Unregister this command reply */
1850 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1851 NULL, silc_client_command_reply_whois_i,
1854 silc_client_command_reply_free(cmd);
1857 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1859 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1860 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1862 SILC_LOG_DEBUG(("Start"));
1864 if (cmd->status != SILC_STATUS_OK &&
1865 cmd->status != SILC_STATUS_LIST_START &&
1866 cmd->status != SILC_STATUS_LIST_ITEM &&
1867 cmd->status != SILC_STATUS_LIST_END)
1870 /* Save IDENTIFY info */
1871 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1873 /* Pending callbacks are not executed if this was an list entry */
1874 if (cmd->status != SILC_STATUS_OK &&
1875 cmd->status != SILC_STATUS_LIST_END) {
1876 silc_client_command_reply_free(cmd);
1881 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1883 /* If we received notify for invalid ID we'll remove the ID if we
1885 if (cmd->status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1886 SilcClientEntry client_entry;
1888 unsigned char *tmp =
1889 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1892 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1894 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1897 silc_client_del_client(cmd->client, conn, client_entry);
1898 silc_free(client_id);
1903 /* Unregister this command reply */
1904 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1905 NULL, silc_client_command_reply_identify_i,
1908 silc_client_command_reply_free(cmd);
1911 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1913 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1914 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1916 SilcServerEntry server;
1917 SilcServerID *server_id = NULL;
1918 char *server_name, *server_info;
1921 SILC_LOG_DEBUG(("Start"));
1923 if (cmd->status != SILC_STATUS_OK)
1927 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1931 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1935 /* Get server name */
1936 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1940 /* Get server info */
1941 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1945 /* See whether we have this server cached. If not create it. */
1946 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1948 SILC_LOG_DEBUG(("New server entry"));
1949 silc_client_add_server(cmd->client, conn, server_name, server_info,
1950 silc_id_dup(server_id, SILC_ID_SERVER));
1954 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1955 silc_free(server_id);
1956 silc_client_command_reply_free(cmd);