5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 * Command reply functions are "the otherside" of the command functions.
22 * Reply to a command sent by server is handled by these functions.
24 * The arguments received from server are also passed to the calling
25 * application through command_reply client operation. The arguments are
26 * exactly same and in same order as the server sent it. However, ID's are
27 * not sent to the application. Instead, corresponding ID entry is sent
28 * to the application. For example, instead of sending Client ID the
29 * corresponding SilcClientEntry is sent to the application. The case is
30 * same with for example Channel ID's. This way application has all the
31 * necessary data already in hand without redundant searching. If ID is
32 * received but ID entry does not exist, NULL is sent.
35 #include "silcincludes.h"
36 #include "silcclient.h"
37 #include "client_internal.h"
39 const SilcCommandStatusMessage silc_command_status_messages[] = {
41 { STAT(NO_SUCH_NICK), "There was no such nickname" },
42 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
43 { STAT(NO_SUCH_SERVER), "There was no such server" },
44 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
45 { STAT(NO_RECIPIENT), "No recipient given" },
46 { STAT(UNKNOWN_COMMAND), "Unknown command" },
47 { STAT(WILDCARDS), "Unknown command" },
48 { STAT(NO_CLIENT_ID), "No Client ID given" },
49 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
50 { STAT(NO_SERVER_ID), "No Server ID given" },
51 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
52 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
53 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
54 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
55 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
56 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
57 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
58 { STAT(USER_ON_CHANNEL), "User already on the channel" },
59 { STAT(NOT_REGISTERED), "You have not registered" },
60 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
61 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
62 { STAT(PERM_DENIED), "Permission denied" },
63 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
64 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
65 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
66 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
67 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
68 { STAT(UNKNOWN_MODE), "Unknown mode" },
69 { STAT(NOT_YOU), "Cannot change mode for other users" },
70 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
71 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
72 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
73 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
74 { STAT(BAD_NICKNAME), "Bad nickname" },
75 { STAT(BAD_CHANNEL), "Bad channel name" },
76 { STAT(AUTH_FAILED), "Authentication failed" },
77 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
78 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
83 #define SAY cmd->client->internal->ops->say
85 /* All functions that call the COMMAND_CHECK_STATUS macro must have
88 #define COMMAND_CHECK_STATUS \
90 SILC_LOG_DEBUG(("Start")); \
91 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
92 COMMAND_REPLY_ERROR; \
97 /* Process received command reply. */
99 void silc_client_command_reply_process(SilcClient client,
100 SilcSocketConnection sock,
101 SilcPacketContext *packet)
103 SilcBuffer buffer = packet->buffer;
104 SilcClientCommand cmd;
105 SilcClientCommandReplyContext ctx;
106 SilcCommandPayload payload;
108 SilcCommandCb reply = NULL;
110 /* Get command reply payload from packet */
111 payload = silc_command_payload_parse(buffer->data, buffer->len);
113 /* Silently ignore bad reply packet */
114 SILC_LOG_DEBUG(("Bad command reply packet"));
118 /* Allocate command reply context. This must be free'd by the
119 command reply routine receiving it. */
120 ctx = silc_calloc(1, sizeof(*ctx));
121 ctx->client = client;
123 ctx->payload = payload;
124 ctx->args = silc_command_get_args(ctx->payload);
125 ctx->packet = packet;
126 ctx->ident = silc_command_get_ident(ctx->payload);
127 silc_command_get_status(ctx->payload, &ctx->status, &ctx->error);
129 /* Check for pending commands and mark to be exeucted */
130 silc_client_command_pending_check(sock->user_data, ctx,
131 silc_command_get(ctx->payload),
134 /* Execute command reply */
136 command = silc_command_get(ctx->payload);
138 /* Try to find matching the command identifier */
139 silc_list_start(client->internal->commands);
140 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
141 if (cmd->cmd == command && !cmd->ident)
143 if (cmd->cmd == command && cmd->ident == ctx->ident) {
144 (*cmd->reply)((void *)ctx, NULL);
149 if (cmd == SILC_LIST_END) {
151 /* No specific identifier for command reply, call first one found */
158 /* Returns status message string */
160 char *silc_client_command_status_message(SilcCommandStatus status)
164 for (i = 0; silc_command_status_messages[i].message; i++) {
165 if (silc_command_status_messages[i].status == status)
169 if (silc_command_status_messages[i].message == NULL)
172 return silc_command_status_messages[i].message;
175 /* Free command reply context and its internals. */
177 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
180 silc_command_payload_free(cmd->payload);
186 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
187 SilcCommandStatus status,
190 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
191 SilcClientID *client_id;
192 SilcClientEntry client_entry = NULL;
194 unsigned char *id_data, *tmp;
195 char *nickname = NULL, *username = NULL;
196 char *realname = NULL;
197 SilcUInt32 idle = 0, mode = 0;
198 SilcBufferStruct channels;
199 unsigned char *fingerprint;
200 SilcUInt32 fingerprint_len;
202 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
209 client_id = silc_id_payload_parse_id(id_data, len, NULL);
216 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
217 username = silc_argument_get_arg_type(cmd->args, 4, &len);
218 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
219 if (!nickname || !username || !realname) {
225 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
227 silc_buffer_set(&channels, tmp, len);
229 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
231 SILC_GET32_MSB(mode, tmp);
233 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
235 SILC_GET32_MSB(idle, tmp);
237 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
239 /* Check if we have this client cached already. */
240 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
242 SILC_LOG_DEBUG(("Adding new client entry"));
244 silc_client_add_client(cmd->client, conn, nickname, username, realname,
247 silc_client_update_client(cmd->client, conn, client_entry,
248 nickname, username, realname, mode);
249 silc_free(client_id);
252 if (fingerprint && !client_entry->fingerprint) {
253 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
254 client_entry->fingerprint_len = fingerprint_len;
257 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
258 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
260 /* Notify application */
261 if (!cmd->callback && notify)
262 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
263 &channels, mode, idle, fingerprint));
266 /* Received reply for WHOIS command. This maybe called several times
267 for one WHOIS command as server may reply with list of results. */
269 SILC_CLIENT_CMD_REPLY_FUNC(whois)
271 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
272 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
274 COMMAND_CHECK_STATUS;
276 /* Save WHOIS info */
277 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
279 /* Pending callbacks are not executed if this was an list entry */
280 if (cmd->status != SILC_STATUS_OK &&
281 cmd->status != SILC_STATUS_LIST_END) {
282 silc_client_command_reply_free(cmd);
287 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
289 /* If we received notify for invalid ID we'll remove the ID if we
291 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
292 SilcClientEntry client_entry;
295 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
298 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
300 client_entry = silc_client_get_client_by_id(cmd->client, conn,
303 silc_client_del_client(cmd->client, conn, client_entry);
304 silc_free(client_id);
309 silc_client_command_reply_free(cmd);
312 /* Received reply for WHOWAS command. */
314 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
316 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
317 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
318 SilcClientID *client_id;
319 SilcClientEntry client_entry = NULL;
321 unsigned char *id_data;
322 char *nickname, *username;
323 char *realname = NULL;
325 COMMAND_CHECK_STATUS;
327 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
333 client_id = silc_id_payload_parse_id(id_data, len, NULL);
339 /* Get the client entry, if exists */
340 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
341 silc_free(client_id);
343 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
344 username = silc_argument_get_arg_type(cmd->args, 4, &len);
345 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
346 if (!nickname || !username) {
351 /* Notify application. We don't save any history information to any
352 cache. Just pass the data to the application for displaying on
354 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
356 /* Pending callbacks are not executed if this was an list entry */
357 if (cmd->status != SILC_STATUS_OK &&
358 cmd->status != SILC_STATUS_LIST_END) {
359 silc_client_command_reply_free(cmd);
364 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
365 silc_client_command_reply_free(cmd);
369 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
370 SilcCommandStatus status,
373 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
374 SilcClient client = cmd->client;
375 SilcClientID *client_id = NULL;
376 SilcServerID *server_id = NULL;
377 SilcChannelID *channel_id = NULL;
378 SilcClientEntry client_entry;
379 SilcServerEntry server_entry;
380 SilcChannelEntry channel_entry;
382 unsigned char *id_data;
383 char *name = NULL, *info = NULL;
384 SilcIDPayload idp = NULL;
387 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
393 idp = silc_id_payload_parse(id_data, len);
400 name = silc_argument_get_arg_type(cmd->args, 3, &len);
401 info = silc_argument_get_arg_type(cmd->args, 4, &len);
403 id_type = silc_id_payload_get_type(idp);
407 client_id = silc_id_payload_get_id(idp);
409 SILC_LOG_DEBUG(("Received client information"));
411 /* Check if we have this client cached already. */
412 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
414 SILC_LOG_DEBUG(("Adding new client entry"));
416 silc_client_add_client(cmd->client, conn, name, info, NULL,
417 silc_id_dup(client_id, id_type), 0);
419 silc_client_update_client(cmd->client, conn, client_entry,
420 name, info, NULL, 0);
423 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
424 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
426 /* Notify application */
428 COMMAND_REPLY((ARGS, client_entry, name, info));
432 server_id = silc_id_payload_get_id(idp);
434 SILC_LOG_DEBUG(("Received server information"));
436 /* Check if we have this server cached already. */
437 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
439 SILC_LOG_DEBUG(("Adding new server entry"));
440 server_entry = silc_client_add_server(cmd->client, conn, name, info,
441 silc_id_dup(server_id, id_type));
449 /* Notify application */
451 COMMAND_REPLY((ARGS, server_entry, name, info));
454 case SILC_ID_CHANNEL:
455 channel_id = silc_id_payload_get_id(idp);
457 SILC_LOG_DEBUG(("Received channel information"));
459 /* Check if we have this channel cached already. */
460 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
461 if (!channel_entry) {
465 /* Add new channel entry */
466 channel_entry = silc_client_add_channel(client, conn, name, 0,
471 /* Notify application */
473 COMMAND_REPLY((ARGS, channel_entry, name, info));
477 silc_id_payload_free(idp);
478 silc_free(client_id);
479 silc_free(server_id);
480 silc_free(channel_id);
483 /* Received reply for IDENTIFY command. This maybe called several times
484 for one IDENTIFY command as server may reply with list of results.
485 This is totally silent and does not print anything on screen. */
487 SILC_CLIENT_CMD_REPLY_FUNC(identify)
489 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
490 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
492 COMMAND_CHECK_STATUS;
494 /* Save IDENTIFY info */
495 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
497 /* Pending callbacks are not executed if this was an list entry */
498 if (cmd->status != SILC_STATUS_OK &&
499 cmd->status != SILC_STATUS_LIST_END) {
500 silc_client_command_reply_free(cmd);
505 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
507 /* If we received notify for invalid ID we'll remove the ID if we
509 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
510 SilcClientEntry client_entry;
513 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
516 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
518 client_entry = silc_client_get_client_by_id(cmd->client, conn,
521 silc_client_del_client(cmd->client, conn, client_entry);
522 silc_free(client_id);
527 silc_client_command_reply_free(cmd);
530 /* Received reply for command NICK. If everything went without errors
531 we just received our new Client ID. */
533 SILC_CLIENT_CMD_REPLY_FUNC(nick)
535 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
536 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
539 SilcUInt32 argc, len;
541 SILC_LOG_DEBUG(("Start"));
543 if (cmd->error != SILC_STATUS_OK) {
544 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
545 "Cannot set nickname: %s",
546 silc_client_command_status_message(cmd->error));
551 argc = silc_argument_get_arg_num(cmd->args);
552 if (argc < 2 || argc > 2) {
553 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
554 "Cannot set nickname: bad reply to command");
559 /* Take received Client ID */
560 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
561 idp = silc_id_payload_parse(tmp, len);
566 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
568 /* Notify application */
569 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
570 COMMAND_REPLY((ARGS, conn->local_entry));
571 silc_client_command_reply_free(cmd);
575 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
576 silc_client_command_reply_free(cmd);
579 /* Received reply to the LIST command. */
581 SILC_CLIENT_CMD_REPLY_FUNC(list)
583 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
584 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
585 unsigned char *tmp, *name, *topic;
586 SilcUInt32 usercount = 0, len;
587 SilcChannelID *channel_id = NULL;
588 SilcChannelEntry channel_entry;
590 COMMAND_CHECK_STATUS;
592 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
598 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
604 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
610 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
611 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
613 SILC_GET32_MSB(usercount, tmp);
615 /* Check whether the channel exists, and add it to cache if it doesn't. */
616 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
618 if (!channel_entry) {
619 /* Add new channel entry */
620 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
622 if (!channel_entry) {
629 /* Notify application */
630 COMMAND_REPLY((ARGS, channel_entry, 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_free(channel_id);
641 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
642 silc_client_command_reply_free(cmd);
645 /* Received reply to topic command. */
647 SILC_CLIENT_CMD_REPLY_FUNC(topic)
649 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
650 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
651 SilcChannelEntry channel;
652 SilcChannelID *channel_id = NULL;
655 SilcUInt32 argc, len;
657 if (cmd->error != SILC_STATUS_OK) {
658 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
659 "%s", silc_client_command_status_message(cmd->error));
664 argc = silc_argument_get_arg_num(cmd->args);
665 if (argc < 1 || argc > 3) {
670 /* Take Channel ID */
671 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
676 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
680 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
684 /* Get the channel entry */
685 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
687 silc_free(channel_id);
692 /* Notify application */
693 COMMAND_REPLY((ARGS, channel, topic));
696 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
697 silc_client_command_reply_free(cmd);
700 /* Received reply to invite command. */
702 SILC_CLIENT_CMD_REPLY_FUNC(invite)
704 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
705 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
706 SilcChannelEntry channel;
707 SilcChannelID *channel_id;
711 if (cmd->error != SILC_STATUS_OK) {
712 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
713 "%s", silc_client_command_status_message(cmd->error));
718 /* Take Channel ID */
719 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
723 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
727 /* Get the channel entry */
728 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
730 silc_free(channel_id);
735 /* Get the invite list */
736 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
738 /* Notify application */
739 COMMAND_REPLY((ARGS, channel, tmp));
742 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
743 silc_client_command_reply_free(cmd);
746 /* Received reply to the KILL command. */
748 SILC_CLIENT_CMD_REPLY_FUNC(kill)
750 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
751 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
753 if (cmd->error != SILC_STATUS_OK) {
754 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
755 "%s", silc_client_command_status_message(cmd->error));
760 /* Notify application */
761 COMMAND_REPLY((ARGS));
764 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
765 silc_client_command_reply_free(cmd);
768 /* Received reply to INFO command. We receive the server ID and some
769 information about the server user requested. */
771 SILC_CLIENT_CMD_REPLY_FUNC(info)
773 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
774 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
776 SilcServerEntry server;
777 SilcServerID *server_id = NULL;
778 char *server_name, *server_info;
781 SILC_LOG_DEBUG(("Start"));
783 if (cmd->error != SILC_STATUS_OK) {
784 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
785 silc_client_command_status_message(cmd->error));
791 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
795 server_id = silc_id_payload_parse_id(tmp, len, NULL);
799 /* Get server name */
800 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
804 /* Get server info */
805 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
809 /* See whether we have this server cached. If not create it. */
810 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
812 SILC_LOG_DEBUG(("New server entry"));
813 server = silc_client_add_server(cmd->client, conn, server_name,
815 silc_id_dup(server_id, SILC_ID_SERVER));
820 /* Notify application */
821 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
824 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
825 silc_free(server_id);
826 silc_client_command_reply_free(cmd);
829 /* Received reply to PING command. The reply time is shown to user. */
831 SILC_CLIENT_CMD_REPLY_FUNC(ping)
833 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
834 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
837 time_t diff, curtime;
839 if (cmd->error != SILC_STATUS_OK) {
840 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
841 "%s", silc_client_command_status_message(cmd->error));
846 curtime = time(NULL);
847 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
848 cmd->packet->src_id_type);
849 if (!id || !conn->ping) {
854 for (i = 0; i < conn->ping_count; i++) {
855 if (!conn->ping[i].dest_id)
857 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
858 diff = curtime - conn->ping[i].start_time;
859 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
860 "Ping reply from %s: %d second%s",
861 conn->ping[i].dest_name, diff,
862 diff == 1 ? "" : "s");
864 conn->ping[i].start_time = 0;
865 silc_free(conn->ping[i].dest_id);
866 conn->ping[i].dest_id = NULL;
867 silc_free(conn->ping[i].dest_name);
868 conn->ping[i].dest_name = NULL;
875 /* Notify application */
876 COMMAND_REPLY((ARGS));
879 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
880 silc_client_command_reply_free(cmd);
883 /* Received reply for JOIN command. */
885 SILC_CLIENT_CMD_REPLY_FUNC(join)
887 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
888 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
889 SilcChannelEntry channel;
891 SilcChannelID *channel_id;
892 SilcUInt32 argc, mode = 0, len, list_count;
893 char *topic, *tmp, *channel_name = NULL, *hmac;
894 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
897 SILC_LOG_DEBUG(("Start"));
899 if (cmd->error != SILC_STATUS_OK) {
900 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
901 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
902 "%s", silc_client_command_status_message(cmd->error));
907 argc = silc_argument_get_arg_num(cmd->args);
908 if (argc < 7 || argc > 14) {
909 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
910 "Cannot join channel: Bad reply packet");
915 /* Get channel name */
916 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
918 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
919 "Cannot join channel: Bad reply packet");
926 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
928 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
929 "Cannot join channel: Bad reply packet");
933 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
939 /* Get channel mode */
940 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
942 SILC_GET32_MSB(mode, tmp);
944 /* Get channel key */
945 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
947 keyp = silc_buffer_alloc(len);
948 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
949 silc_buffer_put(keyp, tmp, len);
953 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
955 /* Check whether we have this channel entry already. */
956 channel = silc_client_get_channel(cmd->client, conn, channel_name);
958 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
959 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
961 /* Create new channel entry */
962 channel = silc_client_add_channel(cmd->client, conn, channel_name,
966 conn->current_channel = channel;
969 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
971 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
972 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
973 "Cannot join channel: Unsupported HMAC `%s'", hmac);
979 /* Get the list count */
980 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
983 SILC_GET32_MSB(list_count, tmp);
985 /* Get Client ID list */
986 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
990 client_id_list = silc_buffer_alloc(len);
991 silc_buffer_pull_tail(client_id_list, len);
992 silc_buffer_put(client_id_list, tmp, len);
994 /* Get client mode list */
995 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
999 client_mode_list = silc_buffer_alloc(len);
1000 silc_buffer_pull_tail(client_mode_list, len);
1001 silc_buffer_put(client_mode_list, tmp, len);
1003 /* Add clients we received in the reply to the channel */
1004 for (i = 0; i < list_count; i++) {
1007 SilcClientID *client_id;
1008 SilcClientEntry client_entry;
1011 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1013 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1018 SILC_GET32_MSB(mode, client_mode_list->data);
1020 /* Check if we have this client cached already. */
1021 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1022 if (!client_entry) {
1023 /* No, we don't have it, add entry for it. */
1025 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1026 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1029 /* Join client to the channel */
1030 if (!silc_client_on_channel(channel, client_entry)) {
1031 chu = silc_calloc(1, sizeof(*chu));
1032 chu->client = client_entry;
1033 chu->channel = channel;
1035 silc_hash_table_add(channel->user_list, client_entry, chu);
1036 silc_hash_table_add(client_entry->channels, channel, chu);
1039 silc_free(client_id);
1040 silc_buffer_pull(client_id_list, idp_len);
1041 silc_buffer_pull(client_mode_list, 4);
1043 silc_buffer_push(client_id_list, client_id_list->data -
1044 client_id_list->head);
1045 silc_buffer_push(client_mode_list, client_mode_list->data -
1046 client_mode_list->head);
1048 /* Save channel key */
1049 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1050 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1052 /* Notify application */
1053 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1054 keyp ? keyp->head : NULL, NULL,
1055 NULL, topic, hmac, list_count, client_id_list,
1059 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1060 silc_client_command_reply_free(cmd);
1063 silc_buffer_free(keyp);
1065 silc_buffer_free(client_id_list);
1066 if (client_mode_list)
1067 silc_buffer_free(client_mode_list);
1070 /* Received reply for MOTD command */
1072 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1074 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1075 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1077 char *motd = NULL, *cp, line[256];
1079 if (cmd->error != SILC_STATUS_OK) {
1080 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1081 "%s", silc_client_command_status_message(cmd->error));
1082 COMMAND_REPLY_ERROR;
1086 argc = silc_argument_get_arg_num(cmd->args);
1088 COMMAND_REPLY_ERROR;
1093 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1095 COMMAND_REPLY_ERROR;
1102 if (cp[i++] == '\n') {
1103 memset(line, 0, sizeof(line));
1104 strncat(line, cp, i - 1);
1110 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1119 /* Notify application */
1120 COMMAND_REPLY((ARGS, motd));
1123 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1124 silc_client_command_reply_free(cmd);
1127 /* Received reply tot he UMODE command. Save the current user mode */
1129 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1131 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1132 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1136 if (cmd->error != SILC_STATUS_OK) {
1137 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1138 "%s", silc_client_command_status_message(cmd->error));
1139 COMMAND_REPLY_ERROR;
1143 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1145 COMMAND_REPLY_ERROR;
1149 SILC_GET32_MSB(mode, tmp);
1150 conn->local_entry->mode = mode;
1152 /* Notify application */
1153 COMMAND_REPLY((ARGS, mode));
1156 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1157 silc_client_command_reply_free(cmd);
1160 /* Received reply for CMODE command. */
1162 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1164 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1165 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1168 SilcChannelID *channel_id;
1169 SilcChannelEntry channel;
1172 if (cmd->error != SILC_STATUS_OK) {
1173 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1174 "%s", silc_client_command_status_message(cmd->error));
1175 COMMAND_REPLY_ERROR;
1179 /* Take Channel ID */
1180 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1183 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1187 /* Get the channel entry */
1188 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1190 silc_free(channel_id);
1191 COMMAND_REPLY_ERROR;
1195 /* Get channel mode */
1196 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1198 silc_free(channel_id);
1199 COMMAND_REPLY_ERROR;
1204 SILC_GET32_MSB(mode, tmp);
1205 channel->mode = mode;
1207 /* Notify application */
1208 COMMAND_REPLY((ARGS, channel, mode));
1210 silc_free(channel_id);
1213 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1214 silc_client_command_reply_free(cmd);
1217 /* Received reply for CUMODE command */
1219 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1221 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1222 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1223 SilcClientID *client_id;
1224 SilcChannelID *channel_id;
1225 SilcClientEntry client_entry;
1226 SilcChannelEntry channel;
1227 SilcChannelUser chu;
1228 unsigned char *modev, *tmp, *id;
1229 SilcUInt32 len, mode;
1231 if (cmd->error != SILC_STATUS_OK) {
1232 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1233 "%s", silc_client_command_status_message(cmd->error));
1234 COMMAND_REPLY_ERROR;
1238 /* Get channel mode */
1239 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1241 COMMAND_REPLY_ERROR;
1245 /* Take Channel ID */
1246 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1249 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1253 /* Get the channel entry */
1254 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1256 silc_free(channel_id);
1257 COMMAND_REPLY_ERROR;
1262 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1264 silc_free(channel_id);
1265 COMMAND_REPLY_ERROR;
1268 client_id = silc_id_payload_parse_id(id, len, NULL);
1270 silc_free(channel_id);
1271 COMMAND_REPLY_ERROR;
1275 /* Get client entry */
1276 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1277 if (!client_entry) {
1278 silc_free(channel_id);
1279 silc_free(client_id);
1280 COMMAND_REPLY_ERROR;
1285 SILC_GET32_MSB(mode, modev);
1286 chu = silc_client_on_channel(channel, client_entry);
1290 /* Notify application */
1291 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1292 silc_free(client_id);
1293 silc_free(channel_id);
1296 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1297 silc_client_command_reply_free(cmd);
1300 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1302 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1303 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1305 if (cmd->error != SILC_STATUS_OK) {
1306 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1307 "%s", silc_client_command_status_message(cmd->error));
1308 COMMAND_REPLY_ERROR;
1312 /* Notify application */
1313 COMMAND_REPLY((ARGS));
1316 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1317 silc_client_command_reply_free(cmd);
1320 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1322 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1323 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1325 if (cmd->error != SILC_STATUS_OK) {
1326 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1327 "%s", silc_client_command_status_message(cmd->error));
1328 COMMAND_REPLY_ERROR;
1332 /* Notify application */
1333 COMMAND_REPLY((ARGS));
1336 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1337 silc_client_command_reply_free(cmd);
1340 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1342 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1343 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1345 if (cmd->error != SILC_STATUS_OK) {
1346 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1347 "%s", silc_client_command_status_message(cmd->error));
1348 COMMAND_REPLY_ERROR;
1352 /* Notify application */
1353 COMMAND_REPLY((ARGS));
1356 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1357 silc_client_command_reply_free(cmd);
1360 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1362 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1363 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1366 if (cmd->error != SILC_STATUS_OK) {
1367 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1368 "%s", silc_client_command_status_message(cmd->error));
1369 COMMAND_REPLY_ERROR;
1373 /* Notify application */
1374 COMMAND_REPLY((ARGS));
1376 /* Generate the detachment data and deliver it to the client in the
1377 detach client operation */
1378 detach = silc_client_get_detach_data(cmd->client, conn);
1380 cmd->client->internal->ops->detach(cmd->client, conn,
1381 detach->data, detach->len);
1382 silc_buffer_free(detach);
1386 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1387 silc_client_command_reply_free(cmd);
1390 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1392 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1393 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1394 SilcChannelEntry channel;
1395 SilcChannelID *channel_id;
1399 if (cmd->error != SILC_STATUS_OK) {
1400 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1401 "%s", silc_client_command_status_message(cmd->error));
1402 COMMAND_REPLY_ERROR;
1406 /* Take Channel ID */
1407 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1411 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1415 /* Get the channel entry */
1416 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1418 silc_free(channel_id);
1419 COMMAND_REPLY_ERROR;
1423 /* Get the ban list */
1424 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1426 /* Notify application */
1427 COMMAND_REPLY((ARGS, channel, tmp));
1430 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1431 silc_client_command_reply_free(cmd);
1434 /* Reply to LEAVE command. */
1436 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1438 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1439 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1440 SilcChannelID *channel_id;
1441 SilcChannelEntry channel = NULL;
1445 if (cmd->error != SILC_STATUS_OK) {
1446 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1447 "%s", silc_client_command_status_message(cmd->error));
1448 COMMAND_REPLY_ERROR;
1452 /* From protocol version 1.1 we get the channel ID of the left channel */
1453 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1455 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1459 /* Get the channel entry */
1460 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1462 silc_free(channel_id);
1463 COMMAND_REPLY_ERROR;
1467 silc_free(channel_id);
1470 /* Notify application */
1471 COMMAND_REPLY((ARGS, channel));
1474 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1475 silc_client_command_reply_free(cmd);
1478 /* Channel resolving callback for USERS command reply. */
1480 static void silc_client_command_reply_users_cb(SilcClient client,
1481 SilcClientConnection conn,
1482 SilcChannelEntry *channels,
1483 SilcUInt32 channels_count,
1486 if (!channels_count) {
1487 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1488 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1490 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1491 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1492 "%s", silc_client_command_status_message(cmd->error));
1493 COMMAND_REPLY_ERROR;
1494 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1495 silc_client_command_reply_free(cmd);
1499 silc_client_command_reply_users(context, NULL);
1503 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1504 SilcCommandStatus status,
1506 SilcGetChannelCallback get_channel,
1507 SilcCommandCb get_clients)
1509 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1510 SilcChannelEntry channel;
1511 SilcClientEntry client_entry;
1512 SilcChannelUser chu;
1513 SilcChannelID *channel_id = NULL;
1514 SilcBufferStruct client_id_list, client_mode_list;
1516 SilcUInt32 tmp_len, list_count;
1518 unsigned char **res_argv = NULL;
1519 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1521 SILC_LOG_DEBUG(("Start"));
1523 /* Get channel ID */
1524 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1526 COMMAND_REPLY_ERROR;
1529 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1531 COMMAND_REPLY_ERROR;
1535 /* Get the list count */
1536 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1538 COMMAND_REPLY_ERROR;
1541 SILC_GET32_MSB(list_count, tmp);
1543 /* Get Client ID list */
1544 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1546 COMMAND_REPLY_ERROR;
1549 silc_buffer_set(&client_id_list, tmp, tmp_len);
1551 /* Get client mode list */
1552 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1554 COMMAND_REPLY_ERROR;
1557 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1559 /* Get channel entry */
1560 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1562 /* Resolve the channel from server */
1563 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1565 silc_free(channel_id);
1569 /* Cache the received Client ID's and modes. */
1570 for (i = 0; i < list_count; i++) {
1573 SilcClientID *client_id;
1576 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1578 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1583 SILC_GET32_MSB(mode, client_mode_list.data);
1585 /* Check if we have this client cached already. */
1586 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1587 if (!client_entry || !client_entry->username || !client_entry->realname) {
1589 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1590 silc_buffer_pull(&client_id_list, idp_len);
1591 silc_buffer_pull(&client_mode_list, 4);
1594 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1597 /* No we don't have it (or it is incomplete in information), query
1598 it from the server. Assemble argument table that will be sent
1599 for the WHOIS command later. */
1600 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1602 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1604 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1606 res_argv[res_argc] = client_id_list.data;
1607 res_argv_lens[res_argc] = idp_len;
1608 res_argv_types[res_argc] = res_argc + 3;
1611 if (!silc_client_on_channel(channel, client_entry)) {
1612 chu = silc_calloc(1, sizeof(*chu));
1613 chu->client = client_entry;
1615 chu->channel = channel;
1616 silc_hash_table_add(channel->user_list, client_entry, chu);
1617 silc_hash_table_add(client_entry->channels, channel, chu);
1621 silc_free(client_id);
1622 silc_buffer_pull(&client_id_list, idp_len);
1623 silc_buffer_pull(&client_mode_list, 4);
1626 /* Query the client information from server if the list included clients
1627 that we don't know about. */
1631 /* Send the WHOIS command to server */
1632 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1633 silc_client_command_reply_whois_i, 0,
1635 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1636 res_argc, res_argv, res_argv_lens,
1637 res_argv_types, conn->cmd_ident);
1638 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1639 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1642 /* Register pending command callback. After we've received the WHOIS
1643 command reply we will reprocess this command reply by re-calling this
1644 USERS command reply callback. */
1645 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1648 silc_buffer_free(res_cmd);
1649 silc_free(channel_id);
1650 silc_free(res_argv);
1651 silc_free(res_argv_lens);
1652 silc_free(res_argv_types);
1656 silc_buffer_push(&client_id_list, (client_id_list.data -
1657 client_id_list.head));
1658 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1659 client_mode_list.head));
1661 /* Notify application */
1663 COMMAND_REPLY((ARGS, channel, list_count, &client_id_list,
1664 &client_mode_list));
1667 silc_free(channel_id);
1671 /* Reply to USERS command. Received list of client ID's and theirs modes
1672 on the channel we requested. */
1674 SILC_CLIENT_CMD_REPLY_FUNC(users)
1676 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1677 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1679 SILC_LOG_DEBUG(("Start"));
1681 if (cmd->error != SILC_STATUS_OK) {
1682 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1683 "%s", silc_client_command_status_message(cmd->error));
1684 COMMAND_REPLY_ERROR;
1688 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
1689 silc_client_command_reply_users_cb,
1690 silc_client_command_reply_users))
1694 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1695 silc_client_command_reply_free(cmd);
1698 /* Received command reply to GETKEY command. WE've received the remote
1699 client's public key. */
1701 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1703 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1704 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1705 SilcIDPayload idp = NULL;
1706 SilcClientID *client_id = NULL;
1707 SilcClientEntry client_entry;
1708 SilcServerID *server_id = NULL;
1709 SilcServerEntry server_entry;
1711 unsigned char *tmp, *pk;
1715 SilcPublicKey public_key = NULL;
1717 SILC_LOG_DEBUG(("Start"));
1719 if (cmd->error != SILC_STATUS_OK) {
1720 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1721 "%s", silc_client_command_status_message(cmd->error));
1722 COMMAND_REPLY_ERROR;
1726 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1728 COMMAND_REPLY_ERROR;
1731 idp = silc_id_payload_parse(tmp, len);
1733 COMMAND_REPLY_ERROR;
1737 /* Get the public key payload */
1738 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1740 /* Decode the public key */
1741 SILC_GET16_MSB(pk_len, tmp);
1742 SILC_GET16_MSB(type, tmp + 2);
1745 if (type == SILC_SKE_PK_TYPE_SILC)
1746 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1750 id_type = silc_id_payload_get_type(idp);
1751 if (id_type == SILC_ID_CLIENT) {
1752 /* Received client's public key */
1753 client_id = silc_id_payload_get_id(idp);
1754 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1755 if (!client_entry) {
1756 COMMAND_REPLY_ERROR;
1760 /* Notify application */
1761 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1762 } else if (id_type == SILC_ID_SERVER) {
1763 /* Received server's public key */
1764 server_id = silc_id_payload_get_id(idp);
1765 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1766 if (!server_entry) {
1767 COMMAND_REPLY_ERROR;
1771 /* Notify application */
1772 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1776 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1778 silc_id_payload_free(idp);
1780 silc_pkcs_public_key_free(public_key);
1781 silc_free(client_id);
1782 silc_free(server_id);
1783 silc_client_command_reply_free(cmd);
1786 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1788 silc_client_command_reply_free(context);
1792 /******************************************************************************
1794 Internal command reply functions
1796 ******************************************************************************/
1798 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1800 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1801 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1803 SILC_LOG_DEBUG(("Start"));
1805 if (cmd->error != SILC_STATUS_OK)
1808 /* Save WHOIS info */
1809 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1811 /* Pending callbacks are not executed if this was an list entry */
1812 if (cmd->status != SILC_STATUS_OK &&
1813 cmd->status != SILC_STATUS_LIST_END) {
1814 silc_client_command_reply_free(cmd);
1819 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1821 /* If we received notify for invalid ID we'll remove the ID if we
1823 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1824 SilcClientEntry client_entry;
1826 unsigned char *tmp =
1827 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1830 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1832 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1835 silc_client_del_client(cmd->client, conn, client_entry);
1836 silc_free(client_id);
1841 /* Unregister this command reply */
1842 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1843 NULL, silc_client_command_reply_whois_i,
1846 silc_client_command_reply_free(cmd);
1849 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1851 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1852 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1854 SILC_LOG_DEBUG(("Start"));
1856 if (cmd->error != SILC_STATUS_OK)
1859 /* Save IDENTIFY info */
1860 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1862 /* Pending callbacks are not executed if this was an list entry */
1863 if (cmd->status != SILC_STATUS_OK &&
1864 cmd->status != SILC_STATUS_LIST_END) {
1865 silc_client_command_reply_free(cmd);
1870 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1872 /* If we received notify for invalid ID we'll remove the ID if we
1874 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1875 SilcClientEntry client_entry;
1877 unsigned char *tmp =
1878 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1881 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1883 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1886 silc_client_del_client(cmd->client, conn, client_entry);
1887 silc_free(client_id);
1892 /* Unregister this command reply */
1893 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1894 NULL, silc_client_command_reply_identify_i,
1897 silc_client_command_reply_free(cmd);
1900 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1902 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1903 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1905 SilcServerEntry server;
1906 SilcServerID *server_id = NULL;
1907 char *server_name, *server_info;
1910 SILC_LOG_DEBUG(("Start"));
1912 if (cmd->error != SILC_STATUS_OK)
1916 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1920 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1924 /* Get server name */
1925 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1929 /* Get server info */
1930 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1934 /* See whether we have this server cached. If not create it. */
1935 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1937 SILC_LOG_DEBUG(("New server entry"));
1938 silc_client_add_server(cmd->client, conn, server_name, server_info,
1939 silc_id_dup(server_id, SILC_ID_SERVER));
1943 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1944 silc_free(server_id);
1945 silc_client_command_reply_free(cmd);
1948 static void silc_client_command_reply_users_i_cb(SilcClient client,
1949 SilcClientConnection conn,
1950 SilcChannelEntry *channels,
1951 SilcUInt32 channels_count,
1954 if (!channels_count) {
1955 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1956 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1958 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1959 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1960 "%s", silc_client_command_status_message(cmd->error));
1961 COMMAND_REPLY_ERROR;
1962 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1963 silc_client_command_reply_free(cmd);
1967 silc_client_command_reply_users_i(context, NULL);
1970 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
1972 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1974 SILC_LOG_DEBUG(("Start"));
1976 if (cmd->error != SILC_STATUS_OK)
1979 /* Save USERS info */
1980 if (silc_client_command_reply_users_save(
1981 cmd, cmd->status, FALSE,
1982 silc_client_command_reply_users_i_cb,
1983 silc_client_command_reply_users_i))
1987 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1989 /* Unregister this command reply */
1990 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
1991 NULL, silc_client_command_reply_users_i,
1994 silc_client_command_reply_free(cmd);
1997 /* Private range commands, specific to this implementation (and compatible
1998 with SILC Server >= 0.9). */
2000 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2002 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2003 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2005 if (cmd->error != SILC_STATUS_OK) {
2006 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2007 "%s", silc_client_command_status_message(cmd->error));
2008 COMMAND_REPLY_ERROR;
2012 /* Notify application */
2013 COMMAND_REPLY((ARGS));
2016 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2017 silc_client_command_reply_free(cmd);
2020 SILC_CLIENT_CMD_REPLY_FUNC(close)
2022 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2023 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2025 if (cmd->error != SILC_STATUS_OK) {
2026 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2027 "%s", silc_client_command_status_message(cmd->error));
2028 COMMAND_REPLY_ERROR;
2032 /* Notify application */
2033 COMMAND_REPLY((ARGS));
2036 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2037 silc_client_command_reply_free(cmd);
2040 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2042 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2043 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2045 if (cmd->error != SILC_STATUS_OK) {
2046 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2047 "%s", silc_client_command_status_message(cmd->error));
2048 COMMAND_REPLY_ERROR;
2052 /* Notify application */
2053 COMMAND_REPLY((ARGS));
2056 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2057 silc_client_command_reply_free(cmd);