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 #define SAY cmd->client->internal->ops->say
41 /* All functions that call the COMMAND_CHECK_STATUS macro must have
42 out: and err: goto labels. out label should call the pending
43 command replies, and the err label just handle error condition. */
45 #define COMMAND_CHECK_STATUS \
47 SILC_LOG_DEBUG(("Start")); \
48 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
49 if (SILC_STATUS_IS_ERROR(cmd->status)) { \
51 COMMAND_REPLY_ERROR; \
54 /* List of errors */ \
55 COMMAND_REPLY_ERROR; \
56 if (cmd->status == SILC_STATUS_LIST_END) \
62 /* Same as COMMAND_CHECK_STATUS but doesn't call client operation */
63 #define COMMAND_CHECK_STATUS_I \
65 SILC_LOG_DEBUG(("Start")); \
66 if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \
67 if (SILC_STATUS_IS_ERROR(cmd->status)) \
69 if (cmd->status == SILC_STATUS_LIST_END) \
75 /* Process received command reply. */
77 void silc_client_command_reply_process(SilcClient client,
78 SilcSocketConnection sock,
79 SilcPacketContext *packet)
81 SilcBuffer buffer = packet->buffer;
82 SilcClientCommand cmd;
83 SilcClientCommandReplyContext ctx;
84 SilcCommandPayload payload;
86 SilcCommandCb reply = NULL;
88 /* Get command reply payload from packet */
89 payload = silc_command_payload_parse(buffer->data, buffer->len);
91 /* Silently ignore bad reply packet */
92 SILC_LOG_DEBUG(("Bad command reply packet"));
96 /* Allocate command reply context. This must be free'd by the
97 command reply routine receiving it. */
98 ctx = silc_calloc(1, sizeof(*ctx));
100 ctx->client = client;
102 ctx->payload = payload;
103 ctx->args = silc_command_get_args(ctx->payload);
104 ctx->packet = packet;
105 ctx->ident = silc_command_get_ident(ctx->payload);
106 silc_command_get_status(ctx->payload, &ctx->status, &ctx->error);
108 /* Check for pending commands and mark to be exeucted */
110 silc_client_command_pending_check(sock->user_data, ctx,
111 silc_command_get(ctx->payload),
112 ctx->ident, &ctx->callbacks_count);
114 /* Execute command reply */
116 command = silc_command_get(ctx->payload);
118 /* Try to find matching the command identifier */
119 silc_list_start(client->internal->commands);
120 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
121 if (cmd->cmd == command && !cmd->ident)
123 if (cmd->cmd == command && cmd->ident == ctx->ident) {
124 (*cmd->reply)((void *)ctx, NULL);
129 if (cmd == SILC_LIST_END) {
131 /* No specific identifier for command reply, call first one found */
138 /* Duplicate Command Reply Context by adding reference counter. The context
139 won't be free'd untill it hits zero. */
141 SilcClientCommandReplyContext
142 silc_client_command_reply_dup(SilcClientCommandReplyContext cmd)
145 SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
146 cmd->users - 1, cmd->users));
150 /* Free command reply context and its internals. */
152 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
155 SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
156 cmd->users + 1, cmd->users));
157 if (cmd->users < 1) {
158 silc_command_payload_free(cmd->payload);
164 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
168 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
169 SilcClientID *client_id;
170 SilcClientEntry client_entry = NULL;
172 unsigned char *id_data, *tmp;
173 char *nickname = NULL, *username = NULL;
174 char *realname = NULL;
175 SilcUInt32 idle = 0, mode = 0;
176 SilcBufferStruct channels, ch_user_modes;
177 bool has_channels = FALSE, has_user_modes = FALSE;
178 unsigned char *fingerprint;
179 SilcUInt32 fingerprint_len;
181 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
188 client_id = silc_id_payload_parse_id(id_data, len, NULL);
195 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
196 username = silc_argument_get_arg_type(cmd->args, 4, &len);
197 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
198 if (!nickname || !username || !realname) {
204 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
206 silc_buffer_set(&channels, tmp, len);
210 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
212 SILC_GET32_MSB(mode, tmp);
214 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
216 SILC_GET32_MSB(idle, tmp);
218 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
220 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
222 silc_buffer_set(&ch_user_modes, tmp, len);
223 has_user_modes = TRUE;
226 /* Check if we have this client cached already. */
227 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
229 SILC_LOG_DEBUG(("Adding new client entry"));
231 silc_client_add_client(cmd->client, conn, nickname, username, realname,
234 silc_client_update_client(cmd->client, conn, client_entry,
235 nickname, username, realname, mode);
236 silc_free(client_id);
239 if (fingerprint && !client_entry->fingerprint) {
240 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
241 client_entry->fingerprint_len = fingerprint_len;
244 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
246 /* Notify application */
247 if (!cmd->callbacks_count && notify)
248 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
249 has_channels ? &channels : NULL, mode, idle,
250 fingerprint, has_user_modes ? &ch_user_modes : NULL));
253 /* Received reply for WHOIS command. This maybe called several times
254 for one WHOIS command as server may reply with list of results. */
256 SILC_CLIENT_CMD_REPLY_FUNC(whois)
258 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
259 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
261 COMMAND_CHECK_STATUS;
263 /* Save WHOIS info */
264 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
266 /* Pending callbacks are not executed if this was an list entry */
267 if (cmd->status != SILC_STATUS_OK &&
268 cmd->status != SILC_STATUS_LIST_END) {
269 silc_client_command_reply_free(cmd);
274 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
277 /* If we received notify for invalid ID we'll remove the ID if we
279 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
280 SilcClientEntry client_entry;
283 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
286 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
288 client_entry = silc_client_get_client_by_id(cmd->client, conn,
291 silc_client_del_client(cmd->client, conn, client_entry);
292 silc_free(client_id);
297 silc_client_command_reply_free(cmd);
300 /* Received reply for WHOWAS command. */
302 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
304 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
305 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
306 SilcClientID *client_id;
307 SilcClientEntry client_entry = NULL;
309 unsigned char *id_data;
310 char *nickname, *username;
311 char *realname = NULL;
313 COMMAND_CHECK_STATUS;
315 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
321 client_id = silc_id_payload_parse_id(id_data, len, NULL);
327 /* Get the client entry, if exists */
328 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
329 silc_free(client_id);
331 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
332 username = silc_argument_get_arg_type(cmd->args, 4, &len);
333 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
334 if (!nickname || !username) {
339 /* Notify application. We don't save any history information to any
340 cache. Just pass the data to the application for displaying on
342 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
344 /* Pending callbacks are not executed if this was an list entry */
345 if (cmd->status != SILC_STATUS_OK &&
346 cmd->status != SILC_STATUS_LIST_END) {
347 silc_client_command_reply_free(cmd);
352 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
354 silc_client_command_reply_free(cmd);
358 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
362 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
363 SilcClient client = cmd->client;
364 SilcClientID *client_id = NULL;
365 SilcServerID *server_id = NULL;
366 SilcChannelID *channel_id = NULL;
367 SilcClientEntry client_entry;
368 SilcServerEntry server_entry;
369 SilcChannelEntry channel_entry;
371 unsigned char *id_data;
372 char *name = NULL, *info = NULL;
373 SilcIDPayload idp = NULL;
376 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
382 idp = silc_id_payload_parse(id_data, len);
389 name = silc_argument_get_arg_type(cmd->args, 3, &len);
390 info = silc_argument_get_arg_type(cmd->args, 4, &len);
392 id_type = silc_id_payload_get_type(idp);
396 client_id = silc_id_payload_get_id(idp);
398 SILC_LOG_DEBUG(("Received client information"));
400 /* Check if we have this client cached already. */
401 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
403 SILC_LOG_DEBUG(("Adding new client entry"));
405 silc_client_add_client(cmd->client, conn, name, info, NULL,
406 silc_id_dup(client_id, id_type), 0);
408 silc_client_update_client(cmd->client, conn, client_entry,
409 name, info, NULL, 0);
412 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
414 /* Notify application */
416 COMMAND_REPLY((ARGS, client_entry, name, info));
420 server_id = silc_id_payload_get_id(idp);
422 SILC_LOG_DEBUG(("Received server information"));
424 /* Check if we have this server cached already. */
425 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
427 SILC_LOG_DEBUG(("Adding new server entry"));
428 server_entry = silc_client_add_server(cmd->client, conn, name, info,
429 silc_id_dup(server_id, id_type));
436 silc_client_update_server(client, conn, server_entry, name, info);
439 server_entry->resolve_cmd_ident = 0;
441 /* Notify application */
443 COMMAND_REPLY((ARGS, server_entry, name, info));
446 case SILC_ID_CHANNEL:
447 channel_id = silc_id_payload_get_id(idp);
449 SILC_LOG_DEBUG(("Received channel information"));
451 /* Check if we have this channel cached already. */
452 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
453 if (!channel_entry) {
457 /* Add new channel entry */
458 channel_entry = silc_client_add_channel(client, conn, name, 0,
463 /* Notify application */
465 COMMAND_REPLY((ARGS, channel_entry, name, info));
469 silc_id_payload_free(idp);
470 silc_free(client_id);
471 silc_free(server_id);
472 silc_free(channel_id);
475 /* Received reply for IDENTIFY command. This maybe called several times
476 for one IDENTIFY command as server may reply with list of results.
477 This is totally silent and does not print anything on screen. */
479 SILC_CLIENT_CMD_REPLY_FUNC(identify)
481 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
482 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
484 COMMAND_CHECK_STATUS;
486 /* Save IDENTIFY info */
487 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
489 /* Pending callbacks are not executed if this was an list entry */
490 if (cmd->status != SILC_STATUS_OK &&
491 cmd->status != SILC_STATUS_LIST_END) {
492 silc_client_command_reply_free(cmd);
497 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
500 /* If we received notify for invalid ID we'll remove the ID if we
502 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
503 SilcClientEntry client_entry;
506 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
509 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
511 client_entry = silc_client_get_client_by_id(cmd->client, conn,
514 silc_client_del_client(cmd->client, conn, client_entry);
515 silc_free(client_id);
520 silc_client_command_reply_free(cmd);
523 /* Received reply for command NICK. If everything went without errors
524 we just received our new Client ID. */
526 SILC_CLIENT_CMD_REPLY_FUNC(nick)
528 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
529 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
532 SilcUInt32 argc, len;
534 SILC_LOG_DEBUG(("Start"));
536 if (cmd->error != SILC_STATUS_OK) {
537 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
538 "Cannot set nickname: %s",
539 silc_get_status_message(cmd->error));
544 argc = silc_argument_get_arg_num(cmd->args);
545 if (argc < 2 || argc > 3) {
546 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
547 "Cannot set nickname: bad reply to command");
552 /* Take received Client ID */
553 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
554 idp = silc_id_payload_parse(tmp, len);
559 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
561 /* Take the new nickname too */
562 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
564 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
566 silc_free(conn->nickname);
567 conn->nickname = strdup(tmp);
568 conn->local_entry->nickname = conn->nickname;
569 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
570 silc_idcache_add(conn->client_cache, strdup(tmp),
571 conn->local_entry->id, conn->local_entry, 0, NULL);
574 /* Notify application */
575 COMMAND_REPLY((ARGS, conn->local_entry, conn->local_entry->nickname));
578 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
579 silc_client_command_reply_free(cmd);
582 /* Received reply to the LIST command. */
584 SILC_CLIENT_CMD_REPLY_FUNC(list)
586 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
587 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
588 unsigned char *tmp, *name, *topic;
589 SilcUInt32 usercount = 0, len;
590 SilcChannelID *channel_id = NULL;
591 SilcChannelEntry channel_entry;
593 COMMAND_CHECK_STATUS;
595 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
601 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
607 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
613 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
614 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
616 SILC_GET32_MSB(usercount, tmp);
618 /* Check whether the channel exists, and add it to cache if it doesn't. */
619 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
621 if (!channel_entry) {
622 /* Add new channel entry */
623 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
625 if (!channel_entry) {
632 /* Notify application */
633 COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount));
635 /* Pending callbacks are not executed if this was an list entry */
636 if (cmd->status != SILC_STATUS_OK &&
637 cmd->status != SILC_STATUS_LIST_END) {
638 silc_client_command_reply_free(cmd);
643 silc_free(channel_id);
644 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
646 silc_client_command_reply_free(cmd);
649 /* Received reply to topic command. */
651 SILC_CLIENT_CMD_REPLY_FUNC(topic)
653 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
654 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
655 SilcChannelEntry channel;
656 SilcChannelID *channel_id = NULL;
659 SilcUInt32 argc, len;
661 if (cmd->error != SILC_STATUS_OK) {
662 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
663 "%s", silc_get_status_message(cmd->error));
668 argc = silc_argument_get_arg_num(cmd->args);
669 if (argc < 1 || argc > 3) {
674 /* Take Channel ID */
675 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
680 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
684 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
688 /* Get the channel entry */
689 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
691 silc_free(channel_id);
696 /* Notify application */
697 COMMAND_REPLY((ARGS, channel, topic));
700 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
701 silc_client_command_reply_free(cmd);
704 /* Received reply to invite command. */
706 SILC_CLIENT_CMD_REPLY_FUNC(invite)
708 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
709 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
710 SilcChannelEntry channel;
711 SilcChannelID *channel_id;
715 if (cmd->error != SILC_STATUS_OK) {
716 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
717 "%s", silc_get_status_message(cmd->error));
722 /* Take Channel ID */
723 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
727 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
731 /* Get the channel entry */
732 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
734 silc_free(channel_id);
739 /* Get the invite list */
740 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
742 /* Notify application */
743 COMMAND_REPLY((ARGS, channel, tmp));
746 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
747 silc_client_command_reply_free(cmd);
750 /* Received reply to the KILL command. */
752 SILC_CLIENT_CMD_REPLY_FUNC(kill)
754 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
755 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
757 if (cmd->error != SILC_STATUS_OK) {
758 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
759 "%s", silc_get_status_message(cmd->error));
764 /* Notify application */
765 COMMAND_REPLY((ARGS));
768 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
769 silc_client_command_reply_free(cmd);
772 /* Received reply to INFO command. We receive the server ID and some
773 information about the server user requested. */
775 SILC_CLIENT_CMD_REPLY_FUNC(info)
777 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
778 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
780 SilcServerEntry server;
781 SilcServerID *server_id = NULL;
782 char *server_name, *server_info;
785 SILC_LOG_DEBUG(("Start"));
787 if (cmd->error != SILC_STATUS_OK) {
788 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
789 silc_get_status_message(cmd->error));
795 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
799 server_id = silc_id_payload_parse_id(tmp, len, NULL);
803 /* Get server name */
804 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
808 /* Get server info */
809 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
813 /* See whether we have this server cached. If not create it. */
814 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
816 SILC_LOG_DEBUG(("New server entry"));
817 server = silc_client_add_server(cmd->client, conn, server_name,
819 silc_id_dup(server_id, SILC_ID_SERVER));
824 /* Notify application */
825 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
828 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
829 silc_free(server_id);
830 silc_client_command_reply_free(cmd);
833 /* Received reply to STATS command. */
835 SILC_CLIENT_CMD_REPLY_FUNC(stats)
837 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
838 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
839 unsigned char *tmp, *buf = NULL;
840 SilcUInt32 len, buf_len = 0;
842 if (cmd->error != SILC_STATUS_OK) {
843 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
844 "%s", silc_get_status_message(cmd->error));
850 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
854 /* Get statistics structure */
855 buf = silc_argument_get_arg_type(cmd->args, 3, &buf_len);
857 /* Notify application */
858 COMMAND_REPLY((ARGS, buf, buf_len));
861 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
862 silc_client_command_reply_free(cmd);
865 /* Received reply to PING command. The reply time is shown to user. */
867 SILC_CLIENT_CMD_REPLY_FUNC(ping)
869 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
870 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
873 time_t diff, curtime;
875 if (cmd->error != SILC_STATUS_OK) {
876 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
877 "%s", silc_get_status_message(cmd->error));
882 curtime = time(NULL);
883 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
884 cmd->packet->src_id_type);
885 if (!id || !conn->ping) {
890 for (i = 0; i < conn->ping_count; i++) {
891 if (!conn->ping[i].dest_id)
893 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
894 diff = curtime - conn->ping[i].start_time;
895 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
896 "Ping reply from %s: %d second%s",
897 conn->ping[i].dest_name, diff,
898 diff == 1 ? "" : "s");
900 conn->ping[i].start_time = 0;
901 silc_free(conn->ping[i].dest_id);
902 conn->ping[i].dest_id = NULL;
903 silc_free(conn->ping[i].dest_name);
904 conn->ping[i].dest_name = NULL;
911 /* Notify application */
912 COMMAND_REPLY((ARGS));
915 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
916 silc_client_command_reply_free(cmd);
919 /* Received reply for JOIN command. */
921 SILC_CLIENT_CMD_REPLY_FUNC(join)
923 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
924 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
925 SilcChannelEntry channel;
927 SilcChannelID *channel_id;
928 SilcUInt32 argc, mode = 0, len, list_count;
929 char *topic, *tmp, *channel_name = NULL, *hmac;
930 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
933 SILC_LOG_DEBUG(("Start"));
935 if (cmd->error != SILC_STATUS_OK) {
936 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
937 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
938 "%s", silc_get_status_message(cmd->error));
943 argc = silc_argument_get_arg_num(cmd->args);
945 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
946 "Cannot join channel: Bad reply packet");
951 /* Get channel name */
952 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
954 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
955 "Cannot join channel: Bad reply packet");
962 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
964 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
965 "Cannot join channel: Bad reply packet");
969 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
975 /* Get channel mode */
976 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
978 SILC_GET32_MSB(mode, tmp);
980 /* Get channel key */
981 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
983 keyp = silc_buffer_alloc(len);
984 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
985 silc_buffer_put(keyp, tmp, len);
989 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
991 /* Check whether we have this channel entry already. */
992 channel = silc_client_get_channel(cmd->client, conn, channel_name);
994 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
995 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
997 /* Create new channel entry */
998 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1002 conn->current_channel = channel;
1005 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1007 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1008 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1009 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1010 COMMAND_REPLY_ERROR;
1015 /* Get the list count */
1016 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1019 SILC_GET32_MSB(list_count, tmp);
1021 /* Get Client ID list */
1022 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1026 client_id_list = silc_buffer_alloc(len);
1027 silc_buffer_pull_tail(client_id_list, len);
1028 silc_buffer_put(client_id_list, tmp, len);
1030 /* Get client mode list */
1031 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1035 client_mode_list = silc_buffer_alloc(len);
1036 silc_buffer_pull_tail(client_mode_list, len);
1037 silc_buffer_put(client_mode_list, tmp, len);
1039 /* Add clients we received in the reply to the channel */
1040 for (i = 0; i < list_count; i++) {
1043 SilcClientID *client_id;
1044 SilcClientEntry client_entry;
1047 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1049 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1054 SILC_GET32_MSB(mode, client_mode_list->data);
1056 /* Check if we have this client cached already. */
1057 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1058 if (!client_entry) {
1059 /* No, we don't have it, add entry for it. */
1061 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1062 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1065 /* Join client to the channel */
1066 if (!silc_client_on_channel(channel, client_entry)) {
1067 chu = silc_calloc(1, sizeof(*chu));
1068 chu->client = client_entry;
1069 chu->channel = channel;
1071 silc_hash_table_add(channel->user_list, client_entry, chu);
1072 silc_hash_table_add(client_entry->channels, channel, chu);
1075 silc_free(client_id);
1076 silc_buffer_pull(client_id_list, idp_len);
1077 silc_buffer_pull(client_mode_list, 4);
1079 silc_buffer_push(client_id_list, client_id_list->data -
1080 client_id_list->head);
1081 silc_buffer_push(client_mode_list, client_mode_list->data -
1082 client_mode_list->head);
1084 /* Save channel key */
1085 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1086 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1088 /* Notify application */
1089 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1090 keyp ? keyp->head : NULL, NULL,
1091 NULL, topic, hmac, list_count, client_id_list,
1095 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1096 silc_client_command_reply_free(cmd);
1099 silc_buffer_free(keyp);
1101 silc_buffer_free(client_id_list);
1102 if (client_mode_list)
1103 silc_buffer_free(client_mode_list);
1106 /* Received reply for MOTD command */
1108 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1110 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1111 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1113 char *motd = NULL, *cp, line[256];
1115 if (cmd->error != SILC_STATUS_OK) {
1116 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1117 "%s", silc_get_status_message(cmd->error));
1118 COMMAND_REPLY_ERROR;
1122 argc = silc_argument_get_arg_num(cmd->args);
1124 COMMAND_REPLY_ERROR;
1129 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1131 COMMAND_REPLY_ERROR;
1138 if (cp[i++] == '\n') {
1139 memset(line, 0, sizeof(line));
1140 strncat(line, cp, i - 1);
1146 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1155 /* Notify application */
1156 COMMAND_REPLY((ARGS, motd));
1159 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1160 silc_client_command_reply_free(cmd);
1163 /* Received reply tot he UMODE command. Save the current user mode */
1165 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1167 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1168 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1172 if (cmd->error != SILC_STATUS_OK) {
1173 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1174 "%s", silc_get_status_message(cmd->error));
1175 COMMAND_REPLY_ERROR;
1179 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1181 COMMAND_REPLY_ERROR;
1185 SILC_GET32_MSB(mode, tmp);
1186 conn->local_entry->mode = mode;
1188 /* Notify application */
1189 COMMAND_REPLY((ARGS, mode));
1192 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1193 silc_client_command_reply_free(cmd);
1196 /* Received reply for CMODE command. */
1198 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1200 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1201 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1204 SilcChannelID *channel_id;
1205 SilcChannelEntry channel;
1208 if (cmd->error != SILC_STATUS_OK) {
1209 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1210 "%s", silc_get_status_message(cmd->error));
1211 COMMAND_REPLY_ERROR;
1215 /* Take Channel ID */
1216 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1219 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1223 /* Get the channel entry */
1224 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1226 silc_free(channel_id);
1227 COMMAND_REPLY_ERROR;
1231 /* Get channel mode */
1232 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1234 silc_free(channel_id);
1235 COMMAND_REPLY_ERROR;
1240 SILC_GET32_MSB(mode, tmp);
1241 channel->mode = mode;
1243 /* Notify application */
1244 COMMAND_REPLY((ARGS, channel, mode));
1246 silc_free(channel_id);
1249 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1250 silc_client_command_reply_free(cmd);
1253 /* Received reply for CUMODE command */
1255 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1257 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1258 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1259 SilcClientID *client_id;
1260 SilcChannelID *channel_id;
1261 SilcClientEntry client_entry;
1262 SilcChannelEntry channel;
1263 SilcChannelUser chu;
1264 unsigned char *modev, *tmp, *id;
1265 SilcUInt32 len, mode;
1267 if (cmd->error != SILC_STATUS_OK) {
1268 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1269 "%s", silc_get_status_message(cmd->error));
1270 COMMAND_REPLY_ERROR;
1274 /* Get channel mode */
1275 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1277 COMMAND_REPLY_ERROR;
1281 /* Take Channel ID */
1282 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1285 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1289 /* Get the channel entry */
1290 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1292 silc_free(channel_id);
1293 COMMAND_REPLY_ERROR;
1298 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1300 silc_free(channel_id);
1301 COMMAND_REPLY_ERROR;
1304 client_id = silc_id_payload_parse_id(id, len, NULL);
1306 silc_free(channel_id);
1307 COMMAND_REPLY_ERROR;
1311 /* Get client entry */
1312 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1313 if (!client_entry) {
1314 silc_free(channel_id);
1315 silc_free(client_id);
1316 COMMAND_REPLY_ERROR;
1321 SILC_GET32_MSB(mode, modev);
1322 chu = silc_client_on_channel(channel, client_entry);
1326 /* Notify application */
1327 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1328 silc_free(client_id);
1329 silc_free(channel_id);
1332 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1333 silc_client_command_reply_free(cmd);
1336 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1338 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1339 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1341 if (cmd->error != SILC_STATUS_OK) {
1342 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1343 "%s", silc_get_status_message(cmd->error));
1344 COMMAND_REPLY_ERROR;
1348 /* Notify application */
1349 COMMAND_REPLY((ARGS));
1352 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1353 silc_client_command_reply_free(cmd);
1356 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1358 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1359 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1361 if (cmd->error != SILC_STATUS_OK) {
1362 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1363 "%s", silc_get_status_message(cmd->error));
1364 COMMAND_REPLY_ERROR;
1368 /* Notify application */
1369 COMMAND_REPLY((ARGS));
1372 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1373 silc_client_command_reply_free(cmd);
1376 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1378 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1379 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1381 if (cmd->error != SILC_STATUS_OK) {
1382 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1383 "%s", silc_get_status_message(cmd->error));
1384 COMMAND_REPLY_ERROR;
1388 /* Notify application */
1389 COMMAND_REPLY((ARGS));
1392 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1393 silc_client_command_reply_free(cmd);
1396 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1398 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1399 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1402 if (cmd->error != SILC_STATUS_OK) {
1403 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1404 "%s", silc_get_status_message(cmd->error));
1405 COMMAND_REPLY_ERROR;
1409 /* Notify application */
1410 COMMAND_REPLY((ARGS));
1412 /* Generate the detachment data and deliver it to the client in the
1413 detach client operation */
1414 detach = silc_client_get_detach_data(cmd->client, conn);
1416 cmd->client->internal->ops->detach(cmd->client, conn,
1417 detach->data, detach->len);
1418 silc_buffer_free(detach);
1422 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1423 silc_client_command_reply_free(cmd);
1426 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1428 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1429 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1431 if (cmd->error != SILC_STATUS_OK) {
1432 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1433 "%s", silc_get_status_message(cmd->error));
1434 COMMAND_REPLY_ERROR;
1438 /* Notify application */
1439 COMMAND_REPLY((ARGS));
1442 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1443 silc_client_command_reply_free(cmd);
1446 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1448 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1449 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1450 SilcChannelEntry channel;
1451 SilcChannelID *channel_id;
1455 if (cmd->error != SILC_STATUS_OK) {
1456 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1457 "%s", silc_get_status_message(cmd->error));
1458 COMMAND_REPLY_ERROR;
1462 /* Take Channel ID */
1463 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1467 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1471 /* Get the channel entry */
1472 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1474 silc_free(channel_id);
1475 COMMAND_REPLY_ERROR;
1479 /* Get the ban list */
1480 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1482 /* Notify application */
1483 COMMAND_REPLY((ARGS, channel, tmp));
1486 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1487 silc_client_command_reply_free(cmd);
1490 /* Reply to LEAVE command. */
1492 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1494 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1495 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1496 SilcChannelID *channel_id;
1497 SilcChannelEntry channel = NULL;
1501 if (cmd->error != SILC_STATUS_OK) {
1502 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1503 "%s", silc_get_status_message(cmd->error));
1504 COMMAND_REPLY_ERROR;
1508 /* From protocol version 1.1 we get the channel ID of the left channel */
1509 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1511 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1515 /* Get the channel entry */
1516 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1518 silc_free(channel_id);
1519 COMMAND_REPLY_ERROR;
1523 silc_free(channel_id);
1526 /* Notify application */
1527 COMMAND_REPLY((ARGS, channel));
1530 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1531 silc_client_command_reply_free(cmd);
1534 /* Channel resolving callback for USERS command reply. */
1536 static void silc_client_command_reply_users_cb(SilcClient client,
1537 SilcClientConnection conn,
1538 SilcChannelEntry *channels,
1539 SilcUInt32 channels_count,
1542 if (!channels_count) {
1543 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1544 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1546 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1547 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1548 "%s", silc_get_status_message(cmd->error));
1549 COMMAND_REPLY_ERROR;
1550 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1551 silc_client_command_reply_free(cmd);
1555 silc_client_command_reply_users(context, NULL);
1559 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1562 SilcGetChannelCallback get_channel,
1563 SilcCommandCb get_clients)
1565 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1566 SilcChannelEntry channel;
1567 SilcClientEntry client_entry;
1568 SilcChannelUser chu;
1569 SilcChannelID *channel_id = NULL;
1570 SilcBufferStruct client_id_list, client_mode_list;
1572 SilcUInt32 tmp_len, list_count;
1574 unsigned char **res_argv = NULL;
1575 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1576 bool wait_res = FALSE;
1578 SILC_LOG_DEBUG(("Start"));
1580 /* Get channel ID */
1581 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1583 COMMAND_REPLY_ERROR;
1586 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1588 COMMAND_REPLY_ERROR;
1592 /* Get the list count */
1593 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1595 COMMAND_REPLY_ERROR;
1598 SILC_GET32_MSB(list_count, tmp);
1600 /* Get Client ID list */
1601 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1603 COMMAND_REPLY_ERROR;
1606 silc_buffer_set(&client_id_list, tmp, tmp_len);
1608 /* Get client mode list */
1609 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1611 COMMAND_REPLY_ERROR;
1614 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1616 /* Get channel entry */
1617 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1619 /* Resolve the channel from server */
1620 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1622 silc_free(channel_id);
1626 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1628 /* Cache the received Client ID's and modes. */
1629 for (i = 0; i < list_count; i++) {
1632 SilcClientID *client_id;
1635 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1637 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1642 SILC_GET32_MSB(mode, client_mode_list.data);
1644 /* Check if we have this client cached already. */
1645 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1646 if (!client_entry || !client_entry->username || !client_entry->realname) {
1647 /* No we don't have it (or it is incomplete in information), query
1648 it from the server. Assemble argument table that will be sent
1649 for the WHOIS command later. */
1650 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1652 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1654 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1656 res_argv[res_argc] = client_id_list.data;
1657 res_argv_lens[res_argc] = idp_len;
1658 res_argv_types[res_argc] = res_argc + 4;
1661 if (!silc_client_on_channel(channel, client_entry)) {
1662 chu = silc_calloc(1, sizeof(*chu));
1663 chu->client = client_entry;
1665 chu->channel = channel;
1666 silc_hash_table_add(channel->user_list, client_entry, chu);
1667 silc_hash_table_add(client_entry->channels, channel, chu);
1671 silc_free(client_id);
1672 silc_buffer_pull(&client_id_list, idp_len);
1673 silc_buffer_pull(&client_mode_list, 4);
1676 /* Query the client information from server if the list included clients
1677 that we don't know about. */
1681 /* Send the WHOIS command to server */
1682 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1683 silc_client_command_reply_whois_i, 0,
1685 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1686 res_argc, res_argv, res_argv_lens,
1687 res_argv_types, conn->cmd_ident);
1688 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1689 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1692 /* Register pending command callback. After we've received the WHOIS
1693 command reply we will reprocess this command reply by re-calling this
1694 USERS command reply callback. */
1695 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1698 silc_buffer_free(res_cmd);
1699 silc_free(channel_id);
1700 silc_free(res_argv);
1701 silc_free(res_argv_lens);
1702 silc_free(res_argv_types);
1709 silc_buffer_push(&client_id_list, (client_id_list.data -
1710 client_id_list.head));
1711 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1712 client_mode_list.head));
1714 /* Notify application */
1716 COMMAND_REPLY((ARGS, channel, list_count, &client_id_list,
1717 &client_mode_list));
1720 silc_free(channel_id);
1724 /* Reply to USERS command. Received list of client ID's and theirs modes
1725 on the channel we requested. */
1727 SILC_CLIENT_CMD_REPLY_FUNC(users)
1729 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1730 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1732 SILC_LOG_DEBUG(("Start"));
1734 if (cmd->error != SILC_STATUS_OK) {
1735 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1736 "%s", silc_get_status_message(cmd->error));
1737 COMMAND_REPLY_ERROR;
1741 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
1742 silc_client_command_reply_users_cb,
1743 silc_client_command_reply_users))
1747 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1748 silc_client_command_reply_free(cmd);
1751 /* Received command reply to GETKEY command. WE've received the remote
1752 client's public key. */
1754 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1756 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1757 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1758 SilcIDPayload idp = NULL;
1759 SilcClientID *client_id = NULL;
1760 SilcClientEntry client_entry;
1761 SilcServerID *server_id = NULL;
1762 SilcServerEntry server_entry;
1764 unsigned char *tmp, *pk;
1768 SilcPublicKey public_key = NULL;
1770 SILC_LOG_DEBUG(("Start"));
1772 if (cmd->error != SILC_STATUS_OK) {
1773 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1774 "%s", silc_get_status_message(cmd->error));
1775 COMMAND_REPLY_ERROR;
1779 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1781 COMMAND_REPLY_ERROR;
1784 idp = silc_id_payload_parse(tmp, len);
1786 COMMAND_REPLY_ERROR;
1790 /* Get the public key payload */
1791 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1793 /* Decode the public key */
1794 SILC_GET16_MSB(pk_len, tmp);
1795 SILC_GET16_MSB(type, tmp + 2);
1798 if (type == SILC_SKE_PK_TYPE_SILC)
1799 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1803 id_type = silc_id_payload_get_type(idp);
1804 if (id_type == SILC_ID_CLIENT) {
1805 /* Received client's public key */
1806 client_id = silc_id_payload_get_id(idp);
1807 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1808 if (!client_entry) {
1809 COMMAND_REPLY_ERROR;
1813 /* Notify application */
1814 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1815 } else if (id_type == SILC_ID_SERVER) {
1816 /* Received server's public key */
1817 server_id = silc_id_payload_get_id(idp);
1818 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1819 if (!server_entry) {
1820 COMMAND_REPLY_ERROR;
1824 /* Notify application */
1825 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1829 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1831 silc_id_payload_free(idp);
1833 silc_pkcs_public_key_free(public_key);
1834 silc_free(client_id);
1835 silc_free(server_id);
1836 silc_client_command_reply_free(cmd);
1839 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1841 silc_client_command_reply_free(context);
1845 /******************************************************************************
1847 Internal command reply functions
1849 ******************************************************************************/
1851 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1853 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1854 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1856 COMMAND_CHECK_STATUS_I;
1858 /* Save WHOIS info */
1859 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1861 /* Pending callbacks are not executed if this was an list entry */
1862 if (cmd->status != SILC_STATUS_OK &&
1863 cmd->status != SILC_STATUS_LIST_END) {
1864 silc_client_command_reply_free(cmd);
1869 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
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_WHOIS,
1894 NULL, silc_client_command_reply_whois_i,
1897 silc_client_command_reply_free(cmd);
1900 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1902 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1903 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1905 COMMAND_CHECK_STATUS_I;
1907 /* Save IDENTIFY info */
1908 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1910 /* Pending callbacks are not executed if this was an list entry */
1911 if (cmd->status != SILC_STATUS_OK &&
1912 cmd->status != SILC_STATUS_LIST_END) {
1913 silc_client_command_reply_free(cmd);
1918 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1921 /* If we received notify for invalid ID we'll remove the ID if we
1923 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1924 SilcClientEntry client_entry;
1926 unsigned char *tmp =
1927 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1930 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1932 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1935 silc_client_del_client(cmd->client, conn, client_entry);
1936 silc_free(client_id);
1941 /* Unregister this command reply */
1942 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1943 NULL, silc_client_command_reply_identify_i,
1946 silc_client_command_reply_free(cmd);
1949 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1951 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1952 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1954 SilcServerEntry server;
1955 SilcServerID *server_id = NULL;
1956 char *server_name, *server_info;
1959 COMMAND_CHECK_STATUS_I;
1962 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1966 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1970 /* Get server name */
1971 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1975 /* Get server info */
1976 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1980 /* See whether we have this server cached. If not create it. */
1981 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1983 SILC_LOG_DEBUG(("New server entry"));
1984 silc_client_add_server(cmd->client, conn, server_name, server_info,
1985 silc_id_dup(server_id, SILC_ID_SERVER));
1989 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1990 silc_free(server_id);
1992 silc_client_command_reply_free(cmd);
1995 static void silc_client_command_reply_users_i_cb(SilcClient client,
1996 SilcClientConnection conn,
1997 SilcChannelEntry *channels,
1998 SilcUInt32 channels_count,
2001 if (!channels_count) {
2002 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2003 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2005 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2006 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2007 "%s", silc_get_status_message(cmd->error));
2008 COMMAND_REPLY_ERROR;
2009 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2010 silc_client_command_reply_free(cmd);
2014 silc_client_command_reply_users_i(context, NULL);
2017 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2019 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2021 COMMAND_CHECK_STATUS_I;
2023 /* Save USERS info */
2024 if (silc_client_command_reply_users_save(
2025 cmd, cmd->status, FALSE,
2026 silc_client_command_reply_users_i_cb,
2027 silc_client_command_reply_users_i))
2031 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2034 /* Unregister this command reply */
2035 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2036 NULL, silc_client_command_reply_users_i,
2039 silc_client_command_reply_free(cmd);
2042 /* Private range commands, specific to this implementation (and compatible
2043 with SILC Server >= 0.9). */
2045 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2047 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2048 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2050 if (cmd->error != SILC_STATUS_OK) {
2051 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2052 "%s", silc_get_status_message(cmd->error));
2053 COMMAND_REPLY_ERROR;
2057 /* Notify application */
2058 COMMAND_REPLY((ARGS));
2061 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2062 silc_client_command_reply_free(cmd);
2065 SILC_CLIENT_CMD_REPLY_FUNC(close)
2067 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2068 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2070 if (cmd->error != SILC_STATUS_OK) {
2071 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2072 "%s", silc_get_status_message(cmd->error));
2073 COMMAND_REPLY_ERROR;
2077 /* Notify application */
2078 COMMAND_REPLY((ARGS));
2081 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2082 silc_client_command_reply_free(cmd);
2085 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2087 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2088 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2090 if (cmd->error != SILC_STATUS_OK) {
2091 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2092 "%s", silc_get_status_message(cmd->error));
2093 COMMAND_REPLY_ERROR;
2097 /* Notify application */
2098 COMMAND_REPLY((ARGS));
2101 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2102 silc_client_command_reply_free(cmd);