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(ban)
1361 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1362 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1363 SilcChannelEntry channel;
1364 SilcChannelID *channel_id;
1368 if (cmd->status != SILC_STATUS_OK) {
1369 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1370 "%s", silc_client_command_status_message(cmd->status));
1371 COMMAND_REPLY_ERROR;
1375 /* Take Channel ID */
1376 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1380 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1384 /* Get the channel entry */
1385 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1387 silc_free(channel_id);
1388 COMMAND_REPLY_ERROR;
1392 /* Get the ban list */
1393 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1395 /* Notify application */
1396 COMMAND_REPLY((ARGS, channel, tmp));
1399 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1400 silc_client_command_reply_free(cmd);
1403 /* Reply to LEAVE command. */
1405 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1407 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1408 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1409 SilcChannelID *channel_id;
1410 SilcChannelEntry channel = NULL;
1414 if (cmd->status != SILC_STATUS_OK) {
1415 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1416 "%s", silc_client_command_status_message(cmd->status));
1417 COMMAND_REPLY_ERROR;
1421 /* From protocol version 1.1 we get the channel ID of the left channel */
1422 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1424 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1428 /* Get the channel entry */
1429 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1431 silc_free(channel_id);
1432 COMMAND_REPLY_ERROR;
1436 silc_free(channel_id);
1439 /* Notify application */
1440 COMMAND_REPLY((ARGS, channel));
1443 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1444 silc_client_command_reply_free(cmd);
1447 /* Channel resolving callback for USERS command reply. */
1449 static void silc_client_command_reply_users_cb(SilcClient client,
1450 SilcClientConnection conn,
1451 SilcChannelEntry *channels,
1452 SilcUInt32 channels_count,
1455 if (!channels_count) {
1456 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1457 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1458 SilcCommandStatus status = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1460 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1461 "%s", silc_client_command_status_message(status));
1462 COMMAND_REPLY_ERROR;
1463 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1464 silc_client_command_reply_free(cmd);
1468 silc_client_command_reply_users(context, NULL);
1471 /* Reply to USERS command. Received list of client ID's and theirs modes
1472 on the channel we requested. */
1474 SILC_CLIENT_CMD_REPLY_FUNC(users)
1476 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1477 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1478 SilcChannelEntry channel;
1479 SilcClientEntry client_entry;
1480 SilcChannelUser chu;
1481 SilcChannelID *channel_id = NULL;
1482 SilcBuffer client_id_list = NULL;
1483 SilcBuffer client_mode_list = NULL;
1485 SilcUInt32 tmp_len, list_count;
1487 unsigned char **res_argv = NULL;
1488 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1490 SILC_LOG_DEBUG(("Start"));
1492 if (cmd->status != SILC_STATUS_OK) {
1493 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1494 "%s", silc_client_command_status_message(cmd->status));
1495 COMMAND_REPLY_ERROR;
1499 /* Get channel ID */
1500 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1502 COMMAND_REPLY_ERROR;
1505 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1507 COMMAND_REPLY_ERROR;
1511 /* Get the list count */
1512 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1514 COMMAND_REPLY_ERROR;
1517 SILC_GET32_MSB(list_count, tmp);
1519 /* Get Client ID list */
1520 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1522 COMMAND_REPLY_ERROR;
1526 client_id_list = silc_buffer_alloc(tmp_len);
1527 silc_buffer_pull_tail(client_id_list, tmp_len);
1528 silc_buffer_put(client_id_list, tmp, tmp_len);
1530 /* Get client mode list */
1531 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1533 COMMAND_REPLY_ERROR;
1537 client_mode_list = silc_buffer_alloc(tmp_len);
1538 silc_buffer_pull_tail(client_mode_list, tmp_len);
1539 silc_buffer_put(client_mode_list, tmp, tmp_len);
1541 /* Get channel entry */
1542 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1544 /* Resolve the channel from server */
1545 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1546 silc_client_command_reply_users_cb,
1548 silc_free(channel_id);
1550 silc_buffer_free(client_id_list);
1551 if (client_mode_list)
1552 silc_buffer_free(client_mode_list);
1556 /* Cache the received Client ID's and modes. */
1557 for (i = 0; i < list_count; i++) {
1560 SilcClientID *client_id;
1563 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1565 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1570 SILC_GET32_MSB(mode, client_mode_list->data);
1572 /* Check if we have this client cached already. */
1573 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1574 if (!client_entry || !client_entry->username || !client_entry->realname) {
1576 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1577 silc_buffer_pull(client_id_list, idp_len);
1578 silc_buffer_pull(client_mode_list, 4);
1581 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1584 /* No we don't have it (or it is incomplete in information), query
1585 it from the server. Assemble argument table that will be sent
1586 for the WHOIS command later. */
1587 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1589 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1591 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1593 res_argv[res_argc] = client_id_list->data;
1594 res_argv_lens[res_argc] = idp_len;
1595 res_argv_types[res_argc] = res_argc + 3;
1598 if (!silc_client_on_channel(channel, client_entry)) {
1599 chu = silc_calloc(1, sizeof(*chu));
1600 chu->client = client_entry;
1602 chu->channel = channel;
1603 silc_hash_table_add(channel->user_list, client_entry, chu);
1604 silc_hash_table_add(client_entry->channels, channel, chu);
1608 silc_free(client_id);
1609 silc_buffer_pull(client_id_list, idp_len);
1610 silc_buffer_pull(client_mode_list, 4);
1613 /* Query the client information from server if the list included clients
1614 that we don't know about. */
1618 /* Send the WHOIS command to server */
1619 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1620 silc_client_command_reply_whois_i, 0,
1622 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1623 res_argc, res_argv, res_argv_lens,
1624 res_argv_types, conn->cmd_ident);
1625 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1626 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1629 /* Register pending command callback. After we've received the WHOIS
1630 command reply we will reprocess this command reply by re-calling this
1631 USERS command reply callback. */
1632 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1633 silc_client_command_reply_users, cmd);
1635 silc_buffer_free(res_cmd);
1636 silc_free(channel_id);
1637 silc_free(res_argv);
1638 silc_free(res_argv_lens);
1639 silc_free(res_argv_types);
1641 silc_buffer_free(client_id_list);
1642 if (client_mode_list)
1643 silc_buffer_free(client_mode_list);
1647 silc_buffer_push(client_id_list, (client_id_list->data -
1648 client_id_list->head));
1649 silc_buffer_push(client_mode_list, (client_mode_list->data -
1650 client_mode_list->head));
1652 /* Notify application */
1653 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1656 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1657 silc_client_command_reply_free(cmd);
1658 silc_free(channel_id);
1660 silc_buffer_free(client_id_list);
1661 if (client_mode_list)
1662 silc_buffer_free(client_mode_list);
1665 /* Received command reply to GETKEY command. WE've received the remote
1666 client's public key. */
1668 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1670 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1671 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1672 SilcIDPayload idp = NULL;
1673 SilcClientID *client_id = NULL;
1674 SilcClientEntry client_entry;
1675 SilcServerID *server_id = NULL;
1676 SilcServerEntry server_entry;
1678 unsigned char *tmp, *pk;
1682 SilcPublicKey public_key = NULL;
1684 SILC_LOG_DEBUG(("Start"));
1686 if (cmd->status != SILC_STATUS_OK) {
1687 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1688 "%s", silc_client_command_status_message(cmd->status));
1689 COMMAND_REPLY_ERROR;
1693 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1695 COMMAND_REPLY_ERROR;
1698 idp = silc_id_payload_parse(tmp, len);
1700 COMMAND_REPLY_ERROR;
1704 /* Get the public key payload */
1705 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1707 /* Decode the public key */
1708 SILC_GET16_MSB(pk_len, tmp);
1709 SILC_GET16_MSB(type, tmp + 2);
1712 if (type == SILC_SKE_PK_TYPE_SILC)
1713 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1717 id_type = silc_id_payload_get_type(idp);
1718 if (id_type == SILC_ID_CLIENT) {
1719 /* Received client's public key */
1720 client_id = silc_id_payload_get_id(idp);
1721 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1722 if (!client_entry) {
1723 COMMAND_REPLY_ERROR;
1727 /* Notify application */
1728 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1729 } else if (id_type == SILC_ID_SERVER) {
1730 /* Received server's public key */
1731 server_id = silc_id_payload_get_id(idp);
1732 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1733 if (!server_entry) {
1734 COMMAND_REPLY_ERROR;
1738 /* Notify application */
1739 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1743 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1745 silc_id_payload_free(idp);
1747 silc_pkcs_public_key_free(public_key);
1748 silc_free(client_id);
1749 silc_free(server_id);
1750 silc_client_command_reply_free(cmd);
1753 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1755 silc_client_command_reply_free(context);
1759 /******************************************************************************
1761 Internal command reply functions
1763 ******************************************************************************/
1765 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1767 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1768 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1770 SILC_LOG_DEBUG(("Start"));
1772 if (cmd->status != SILC_STATUS_OK &&
1773 cmd->status != SILC_STATUS_LIST_START &&
1774 cmd->status != SILC_STATUS_LIST_ITEM &&
1775 cmd->status != SILC_STATUS_LIST_END)
1778 /* Save WHOIS info */
1779 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1781 /* Pending callbacks are not executed if this was an list entry */
1782 if (cmd->status != SILC_STATUS_OK &&
1783 cmd->status != SILC_STATUS_LIST_END) {
1784 silc_client_command_reply_free(cmd);
1789 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1791 /* If we received notify for invalid ID we'll remove the ID if we
1793 if (cmd->status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1794 SilcClientEntry client_entry;
1796 unsigned char *tmp =
1797 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1800 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1802 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1805 silc_client_del_client(cmd->client, conn, client_entry);
1806 silc_free(client_id);
1811 /* Unregister this command reply */
1812 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1813 NULL, silc_client_command_reply_whois_i,
1816 silc_client_command_reply_free(cmd);
1819 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1821 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1822 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1824 SILC_LOG_DEBUG(("Start"));
1826 if (cmd->status != SILC_STATUS_OK &&
1827 cmd->status != SILC_STATUS_LIST_START &&
1828 cmd->status != SILC_STATUS_LIST_ITEM &&
1829 cmd->status != SILC_STATUS_LIST_END)
1832 /* Save IDENTIFY info */
1833 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1835 /* Pending callbacks are not executed if this was an list entry */
1836 if (cmd->status != SILC_STATUS_OK &&
1837 cmd->status != SILC_STATUS_LIST_END) {
1838 silc_client_command_reply_free(cmd);
1843 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1845 /* If we received notify for invalid ID we'll remove the ID if we
1847 if (cmd->status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1848 SilcClientEntry client_entry;
1850 unsigned char *tmp =
1851 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1854 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1856 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1859 silc_client_del_client(cmd->client, conn, client_entry);
1860 silc_free(client_id);
1865 /* Unregister this command reply */
1866 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1867 NULL, silc_client_command_reply_identify_i,
1870 silc_client_command_reply_free(cmd);
1873 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1875 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1876 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1878 SilcServerEntry server;
1879 SilcServerID *server_id = NULL;
1880 char *server_name, *server_info;
1883 SILC_LOG_DEBUG(("Start"));
1885 if (cmd->status != SILC_STATUS_OK)
1889 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1893 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1897 /* Get server name */
1898 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1902 /* Get server info */
1903 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1907 /* See whether we have this server cached. If not create it. */
1908 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1910 SILC_LOG_DEBUG(("New server entry"));
1911 silc_client_add_server(cmd->client, conn, server_name, server_info,
1912 silc_id_dup(server_id, SILC_ID_SERVER));
1916 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1917 silc_free(server_id);
1918 silc_client_command_reply_free(cmd);
1922 /* Private range commands, specific to this implementation (and compatible
1923 with SILC Server). */
1925 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1927 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1928 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1930 if (cmd->status != SILC_STATUS_OK) {
1931 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1932 "%s", silc_client_command_status_message(cmd->status));
1933 COMMAND_REPLY_ERROR;
1937 /* Notify application */
1938 COMMAND_REPLY((ARGS));
1941 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
1942 silc_client_command_reply_free(cmd);
1945 SILC_CLIENT_CMD_REPLY_FUNC(close)
1947 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1948 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1950 if (cmd->status != SILC_STATUS_OK) {
1951 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1952 "%s", silc_client_command_status_message(cmd->status));
1953 COMMAND_REPLY_ERROR;
1957 /* Notify application */
1958 COMMAND_REPLY((ARGS));
1961 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
1962 silc_client_command_reply_free(cmd);
1965 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1967 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1968 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1970 if (cmd->status != SILC_STATUS_OK) {
1971 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1972 "%s", silc_client_command_status_message(cmd->status));
1973 COMMAND_REPLY_ERROR;
1977 /* Notify application */
1978 COMMAND_REPLY((ARGS));
1981 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
1982 silc_client_command_reply_free(cmd);