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 PING command. The reply time is shown to user. */
835 SILC_CLIENT_CMD_REPLY_FUNC(ping)
837 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
838 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
841 time_t diff, curtime;
843 if (cmd->error != SILC_STATUS_OK) {
844 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
845 "%s", silc_get_status_message(cmd->error));
850 curtime = time(NULL);
851 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
852 cmd->packet->src_id_type);
853 if (!id || !conn->ping) {
858 for (i = 0; i < conn->ping_count; i++) {
859 if (!conn->ping[i].dest_id)
861 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
862 diff = curtime - conn->ping[i].start_time;
863 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
864 "Ping reply from %s: %d second%s",
865 conn->ping[i].dest_name, diff,
866 diff == 1 ? "" : "s");
868 conn->ping[i].start_time = 0;
869 silc_free(conn->ping[i].dest_id);
870 conn->ping[i].dest_id = NULL;
871 silc_free(conn->ping[i].dest_name);
872 conn->ping[i].dest_name = NULL;
879 /* Notify application */
880 COMMAND_REPLY((ARGS));
883 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
884 silc_client_command_reply_free(cmd);
887 /* Received reply for JOIN command. */
889 SILC_CLIENT_CMD_REPLY_FUNC(join)
891 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
892 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
893 SilcChannelEntry channel;
895 SilcChannelID *channel_id;
896 SilcUInt32 argc, mode = 0, len, list_count;
897 char *topic, *tmp, *channel_name = NULL, *hmac;
898 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
901 SILC_LOG_DEBUG(("Start"));
903 if (cmd->error != SILC_STATUS_OK) {
904 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
905 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
906 "%s", silc_get_status_message(cmd->error));
911 argc = silc_argument_get_arg_num(cmd->args);
913 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
914 "Cannot join channel: Bad reply packet");
919 /* Get channel name */
920 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
922 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
923 "Cannot join channel: Bad reply packet");
930 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
932 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
933 "Cannot join channel: Bad reply packet");
937 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
943 /* Get channel mode */
944 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
946 SILC_GET32_MSB(mode, tmp);
948 /* Get channel key */
949 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
951 keyp = silc_buffer_alloc(len);
952 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
953 silc_buffer_put(keyp, tmp, len);
957 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
959 /* Check whether we have this channel entry already. */
960 channel = silc_client_get_channel(cmd->client, conn, channel_name);
962 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
963 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
965 /* Create new channel entry */
966 channel = silc_client_add_channel(cmd->client, conn, channel_name,
970 conn->current_channel = channel;
973 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
975 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
976 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
977 "Cannot join channel: Unsupported HMAC `%s'", hmac);
983 /* Get the list count */
984 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
987 SILC_GET32_MSB(list_count, tmp);
989 /* Get Client ID list */
990 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
994 client_id_list = silc_buffer_alloc(len);
995 silc_buffer_pull_tail(client_id_list, len);
996 silc_buffer_put(client_id_list, tmp, len);
998 /* Get client mode list */
999 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1003 client_mode_list = silc_buffer_alloc(len);
1004 silc_buffer_pull_tail(client_mode_list, len);
1005 silc_buffer_put(client_mode_list, tmp, len);
1007 /* Add clients we received in the reply to the channel */
1008 for (i = 0; i < list_count; i++) {
1011 SilcClientID *client_id;
1012 SilcClientEntry client_entry;
1015 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1017 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1022 SILC_GET32_MSB(mode, client_mode_list->data);
1024 /* Check if we have this client cached already. */
1025 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1026 if (!client_entry) {
1027 /* No, we don't have it, add entry for it. */
1029 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1030 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1033 /* Join client to the channel */
1034 if (!silc_client_on_channel(channel, client_entry)) {
1035 chu = silc_calloc(1, sizeof(*chu));
1036 chu->client = client_entry;
1037 chu->channel = channel;
1039 silc_hash_table_add(channel->user_list, client_entry, chu);
1040 silc_hash_table_add(client_entry->channels, channel, chu);
1043 silc_free(client_id);
1044 silc_buffer_pull(client_id_list, idp_len);
1045 silc_buffer_pull(client_mode_list, 4);
1047 silc_buffer_push(client_id_list, client_id_list->data -
1048 client_id_list->head);
1049 silc_buffer_push(client_mode_list, client_mode_list->data -
1050 client_mode_list->head);
1052 /* Save channel key */
1053 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1054 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1056 /* Notify application */
1057 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1058 keyp ? keyp->head : NULL, NULL,
1059 NULL, topic, hmac, list_count, client_id_list,
1063 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1064 silc_client_command_reply_free(cmd);
1067 silc_buffer_free(keyp);
1069 silc_buffer_free(client_id_list);
1070 if (client_mode_list)
1071 silc_buffer_free(client_mode_list);
1074 /* Received reply for MOTD command */
1076 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1078 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1079 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1081 char *motd = NULL, *cp, line[256];
1083 if (cmd->error != SILC_STATUS_OK) {
1084 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1085 "%s", silc_get_status_message(cmd->error));
1086 COMMAND_REPLY_ERROR;
1090 argc = silc_argument_get_arg_num(cmd->args);
1092 COMMAND_REPLY_ERROR;
1097 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1099 COMMAND_REPLY_ERROR;
1106 if (cp[i++] == '\n') {
1107 memset(line, 0, sizeof(line));
1108 strncat(line, cp, i - 1);
1114 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1123 /* Notify application */
1124 COMMAND_REPLY((ARGS, motd));
1127 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1128 silc_client_command_reply_free(cmd);
1131 /* Received reply tot he UMODE command. Save the current user mode */
1133 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1135 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1136 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1140 if (cmd->error != SILC_STATUS_OK) {
1141 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1142 "%s", silc_get_status_message(cmd->error));
1143 COMMAND_REPLY_ERROR;
1147 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1149 COMMAND_REPLY_ERROR;
1153 SILC_GET32_MSB(mode, tmp);
1154 conn->local_entry->mode = mode;
1156 /* Notify application */
1157 COMMAND_REPLY((ARGS, mode));
1160 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1161 silc_client_command_reply_free(cmd);
1164 /* Received reply for CMODE command. */
1166 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1168 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1169 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1172 SilcChannelID *channel_id;
1173 SilcChannelEntry channel;
1176 if (cmd->error != SILC_STATUS_OK) {
1177 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1178 "%s", silc_get_status_message(cmd->error));
1179 COMMAND_REPLY_ERROR;
1183 /* Take Channel ID */
1184 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1187 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1191 /* Get the channel entry */
1192 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1194 silc_free(channel_id);
1195 COMMAND_REPLY_ERROR;
1199 /* Get channel mode */
1200 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1202 silc_free(channel_id);
1203 COMMAND_REPLY_ERROR;
1208 SILC_GET32_MSB(mode, tmp);
1209 channel->mode = mode;
1211 /* Notify application */
1212 COMMAND_REPLY((ARGS, channel, mode));
1214 silc_free(channel_id);
1217 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1218 silc_client_command_reply_free(cmd);
1221 /* Received reply for CUMODE command */
1223 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1225 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1226 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1227 SilcClientID *client_id;
1228 SilcChannelID *channel_id;
1229 SilcClientEntry client_entry;
1230 SilcChannelEntry channel;
1231 SilcChannelUser chu;
1232 unsigned char *modev, *tmp, *id;
1233 SilcUInt32 len, mode;
1235 if (cmd->error != SILC_STATUS_OK) {
1236 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1237 "%s", silc_get_status_message(cmd->error));
1238 COMMAND_REPLY_ERROR;
1242 /* Get channel mode */
1243 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1245 COMMAND_REPLY_ERROR;
1249 /* Take Channel ID */
1250 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1253 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1257 /* Get the channel entry */
1258 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1260 silc_free(channel_id);
1261 COMMAND_REPLY_ERROR;
1266 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1268 silc_free(channel_id);
1269 COMMAND_REPLY_ERROR;
1272 client_id = silc_id_payload_parse_id(id, len, NULL);
1274 silc_free(channel_id);
1275 COMMAND_REPLY_ERROR;
1279 /* Get client entry */
1280 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1281 if (!client_entry) {
1282 silc_free(channel_id);
1283 silc_free(client_id);
1284 COMMAND_REPLY_ERROR;
1289 SILC_GET32_MSB(mode, modev);
1290 chu = silc_client_on_channel(channel, client_entry);
1294 /* Notify application */
1295 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1296 silc_free(client_id);
1297 silc_free(channel_id);
1300 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1301 silc_client_command_reply_free(cmd);
1304 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1306 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1307 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1309 if (cmd->error != SILC_STATUS_OK) {
1310 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1311 "%s", silc_get_status_message(cmd->error));
1312 COMMAND_REPLY_ERROR;
1316 /* Notify application */
1317 COMMAND_REPLY((ARGS));
1320 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1321 silc_client_command_reply_free(cmd);
1324 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1326 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1327 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1329 if (cmd->error != SILC_STATUS_OK) {
1330 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1331 "%s", silc_get_status_message(cmd->error));
1332 COMMAND_REPLY_ERROR;
1336 /* Notify application */
1337 COMMAND_REPLY((ARGS));
1340 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1341 silc_client_command_reply_free(cmd);
1344 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1346 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1347 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1349 if (cmd->error != SILC_STATUS_OK) {
1350 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1351 "%s", silc_get_status_message(cmd->error));
1352 COMMAND_REPLY_ERROR;
1356 /* Notify application */
1357 COMMAND_REPLY((ARGS));
1360 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1361 silc_client_command_reply_free(cmd);
1364 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1366 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1367 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1370 if (cmd->error != SILC_STATUS_OK) {
1371 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1372 "%s", silc_get_status_message(cmd->error));
1373 COMMAND_REPLY_ERROR;
1377 /* Notify application */
1378 COMMAND_REPLY((ARGS));
1380 /* Generate the detachment data and deliver it to the client in the
1381 detach client operation */
1382 detach = silc_client_get_detach_data(cmd->client, conn);
1384 cmd->client->internal->ops->detach(cmd->client, conn,
1385 detach->data, detach->len);
1386 silc_buffer_free(detach);
1390 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1391 silc_client_command_reply_free(cmd);
1394 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1396 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1397 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1399 if (cmd->error != SILC_STATUS_OK) {
1400 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1401 "%s", silc_get_status_message(cmd->error));
1402 COMMAND_REPLY_ERROR;
1406 /* Notify application */
1407 COMMAND_REPLY((ARGS));
1410 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1411 silc_client_command_reply_free(cmd);
1414 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1416 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1417 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1418 SilcChannelEntry channel;
1419 SilcChannelID *channel_id;
1423 if (cmd->error != SILC_STATUS_OK) {
1424 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1425 "%s", silc_get_status_message(cmd->error));
1426 COMMAND_REPLY_ERROR;
1430 /* Take Channel ID */
1431 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1435 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1439 /* Get the channel entry */
1440 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1442 silc_free(channel_id);
1443 COMMAND_REPLY_ERROR;
1447 /* Get the ban list */
1448 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1450 /* Notify application */
1451 COMMAND_REPLY((ARGS, channel, tmp));
1454 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1455 silc_client_command_reply_free(cmd);
1458 /* Reply to LEAVE command. */
1460 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1462 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1463 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1464 SilcChannelID *channel_id;
1465 SilcChannelEntry channel = NULL;
1469 if (cmd->error != SILC_STATUS_OK) {
1470 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1471 "%s", silc_get_status_message(cmd->error));
1472 COMMAND_REPLY_ERROR;
1476 /* From protocol version 1.1 we get the channel ID of the left channel */
1477 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1479 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1483 /* Get the channel entry */
1484 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1486 silc_free(channel_id);
1487 COMMAND_REPLY_ERROR;
1491 silc_free(channel_id);
1494 /* Notify application */
1495 COMMAND_REPLY((ARGS, channel));
1498 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1499 silc_client_command_reply_free(cmd);
1502 /* Channel resolving callback for USERS command reply. */
1504 static void silc_client_command_reply_users_cb(SilcClient client,
1505 SilcClientConnection conn,
1506 SilcChannelEntry *channels,
1507 SilcUInt32 channels_count,
1510 if (!channels_count) {
1511 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1512 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1514 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1515 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1516 "%s", silc_get_status_message(cmd->error));
1517 COMMAND_REPLY_ERROR;
1518 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1519 silc_client_command_reply_free(cmd);
1523 silc_client_command_reply_users(context, NULL);
1527 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1530 SilcGetChannelCallback get_channel,
1531 SilcCommandCb get_clients)
1533 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1534 SilcChannelEntry channel;
1535 SilcClientEntry client_entry;
1536 SilcChannelUser chu;
1537 SilcChannelID *channel_id = NULL;
1538 SilcBufferStruct client_id_list, client_mode_list;
1540 SilcUInt32 tmp_len, list_count;
1542 unsigned char **res_argv = NULL;
1543 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1544 bool wait_res = FALSE;
1546 SILC_LOG_DEBUG(("Start"));
1548 /* Get channel ID */
1549 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1551 COMMAND_REPLY_ERROR;
1554 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1556 COMMAND_REPLY_ERROR;
1560 /* Get the list count */
1561 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1563 COMMAND_REPLY_ERROR;
1566 SILC_GET32_MSB(list_count, tmp);
1568 /* Get Client ID list */
1569 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1571 COMMAND_REPLY_ERROR;
1574 silc_buffer_set(&client_id_list, tmp, tmp_len);
1576 /* Get client mode list */
1577 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1579 COMMAND_REPLY_ERROR;
1582 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1584 /* Get channel entry */
1585 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1587 /* Resolve the channel from server */
1588 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1590 silc_free(channel_id);
1594 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1596 /* Cache the received Client ID's and modes. */
1597 for (i = 0; i < list_count; i++) {
1600 SilcClientID *client_id;
1603 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1605 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1610 SILC_GET32_MSB(mode, client_mode_list.data);
1612 /* Check if we have this client cached already. */
1613 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1614 if (!client_entry || !client_entry->username || !client_entry->realname) {
1615 /* No we don't have it (or it is incomplete in information), query
1616 it from the server. Assemble argument table that will be sent
1617 for the WHOIS command later. */
1618 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1620 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1622 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1624 res_argv[res_argc] = client_id_list.data;
1625 res_argv_lens[res_argc] = idp_len;
1626 res_argv_types[res_argc] = res_argc + 4;
1629 if (!silc_client_on_channel(channel, client_entry)) {
1630 chu = silc_calloc(1, sizeof(*chu));
1631 chu->client = client_entry;
1633 chu->channel = channel;
1634 silc_hash_table_add(channel->user_list, client_entry, chu);
1635 silc_hash_table_add(client_entry->channels, channel, chu);
1639 silc_free(client_id);
1640 silc_buffer_pull(&client_id_list, idp_len);
1641 silc_buffer_pull(&client_mode_list, 4);
1644 /* Query the client information from server if the list included clients
1645 that we don't know about. */
1649 /* Send the WHOIS command to server */
1650 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1651 silc_client_command_reply_whois_i, 0,
1653 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1654 res_argc, res_argv, res_argv_lens,
1655 res_argv_types, conn->cmd_ident);
1656 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1657 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1660 /* Register pending command callback. After we've received the WHOIS
1661 command reply we will reprocess this command reply by re-calling this
1662 USERS command reply callback. */
1663 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1666 silc_buffer_free(res_cmd);
1667 silc_free(channel_id);
1668 silc_free(res_argv);
1669 silc_free(res_argv_lens);
1670 silc_free(res_argv_types);
1677 silc_buffer_push(&client_id_list, (client_id_list.data -
1678 client_id_list.head));
1679 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1680 client_mode_list.head));
1682 /* Notify application */
1684 COMMAND_REPLY((ARGS, channel, list_count, &client_id_list,
1685 &client_mode_list));
1688 silc_free(channel_id);
1692 /* Reply to USERS command. Received list of client ID's and theirs modes
1693 on the channel we requested. */
1695 SILC_CLIENT_CMD_REPLY_FUNC(users)
1697 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1698 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1700 SILC_LOG_DEBUG(("Start"));
1702 if (cmd->error != SILC_STATUS_OK) {
1703 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1704 "%s", silc_get_status_message(cmd->error));
1705 COMMAND_REPLY_ERROR;
1709 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
1710 silc_client_command_reply_users_cb,
1711 silc_client_command_reply_users))
1715 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1716 silc_client_command_reply_free(cmd);
1719 /* Received command reply to GETKEY command. WE've received the remote
1720 client's public key. */
1722 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1724 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1725 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1726 SilcIDPayload idp = NULL;
1727 SilcClientID *client_id = NULL;
1728 SilcClientEntry client_entry;
1729 SilcServerID *server_id = NULL;
1730 SilcServerEntry server_entry;
1732 unsigned char *tmp, *pk;
1736 SilcPublicKey public_key = NULL;
1738 SILC_LOG_DEBUG(("Start"));
1740 if (cmd->error != SILC_STATUS_OK) {
1741 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1742 "%s", silc_get_status_message(cmd->error));
1743 COMMAND_REPLY_ERROR;
1747 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1749 COMMAND_REPLY_ERROR;
1752 idp = silc_id_payload_parse(tmp, len);
1754 COMMAND_REPLY_ERROR;
1758 /* Get the public key payload */
1759 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1761 /* Decode the public key */
1762 SILC_GET16_MSB(pk_len, tmp);
1763 SILC_GET16_MSB(type, tmp + 2);
1766 if (type == SILC_SKE_PK_TYPE_SILC)
1767 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1771 id_type = silc_id_payload_get_type(idp);
1772 if (id_type == SILC_ID_CLIENT) {
1773 /* Received client's public key */
1774 client_id = silc_id_payload_get_id(idp);
1775 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1776 if (!client_entry) {
1777 COMMAND_REPLY_ERROR;
1781 /* Notify application */
1782 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1783 } else if (id_type == SILC_ID_SERVER) {
1784 /* Received server's public key */
1785 server_id = silc_id_payload_get_id(idp);
1786 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1787 if (!server_entry) {
1788 COMMAND_REPLY_ERROR;
1792 /* Notify application */
1793 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1797 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1799 silc_id_payload_free(idp);
1801 silc_pkcs_public_key_free(public_key);
1802 silc_free(client_id);
1803 silc_free(server_id);
1804 silc_client_command_reply_free(cmd);
1807 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1809 silc_client_command_reply_free(context);
1813 /******************************************************************************
1815 Internal command reply functions
1817 ******************************************************************************/
1819 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1821 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1822 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1824 COMMAND_CHECK_STATUS_I;
1826 /* Save WHOIS info */
1827 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1829 /* Pending callbacks are not executed if this was an list entry */
1830 if (cmd->status != SILC_STATUS_OK &&
1831 cmd->status != SILC_STATUS_LIST_END) {
1832 silc_client_command_reply_free(cmd);
1837 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1840 /* If we received notify for invalid ID we'll remove the ID if we
1842 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1843 SilcClientEntry client_entry;
1845 unsigned char *tmp =
1846 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1849 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1851 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1854 silc_client_del_client(cmd->client, conn, client_entry);
1855 silc_free(client_id);
1860 /* Unregister this command reply */
1861 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1862 NULL, silc_client_command_reply_whois_i,
1865 silc_client_command_reply_free(cmd);
1868 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1870 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1871 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1873 COMMAND_CHECK_STATUS_I;
1875 /* Save IDENTIFY info */
1876 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1878 /* Pending callbacks are not executed if this was an list entry */
1879 if (cmd->status != SILC_STATUS_OK &&
1880 cmd->status != SILC_STATUS_LIST_END) {
1881 silc_client_command_reply_free(cmd);
1886 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1889 /* If we received notify for invalid ID we'll remove the ID if we
1891 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1892 SilcClientEntry client_entry;
1894 unsigned char *tmp =
1895 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1898 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1900 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1903 silc_client_del_client(cmd->client, conn, client_entry);
1904 silc_free(client_id);
1909 /* Unregister this command reply */
1910 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1911 NULL, silc_client_command_reply_identify_i,
1914 silc_client_command_reply_free(cmd);
1917 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1919 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1920 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1922 SilcServerEntry server;
1923 SilcServerID *server_id = NULL;
1924 char *server_name, *server_info;
1927 COMMAND_CHECK_STATUS_I;
1930 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1934 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1938 /* Get server name */
1939 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1943 /* Get server info */
1944 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1948 /* See whether we have this server cached. If not create it. */
1949 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1951 SILC_LOG_DEBUG(("New server entry"));
1952 silc_client_add_server(cmd->client, conn, server_name, server_info,
1953 silc_id_dup(server_id, SILC_ID_SERVER));
1957 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1958 silc_free(server_id);
1960 silc_client_command_reply_free(cmd);
1963 static void silc_client_command_reply_users_i_cb(SilcClient client,
1964 SilcClientConnection conn,
1965 SilcChannelEntry *channels,
1966 SilcUInt32 channels_count,
1969 if (!channels_count) {
1970 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1971 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1973 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1974 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1975 "%s", silc_get_status_message(cmd->error));
1976 COMMAND_REPLY_ERROR;
1977 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1978 silc_client_command_reply_free(cmd);
1982 silc_client_command_reply_users_i(context, NULL);
1985 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
1987 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1989 COMMAND_CHECK_STATUS_I;
1991 /* Save USERS info */
1992 if (silc_client_command_reply_users_save(
1993 cmd, cmd->status, FALSE,
1994 silc_client_command_reply_users_i_cb,
1995 silc_client_command_reply_users_i))
1999 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2002 /* Unregister this command reply */
2003 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2004 NULL, silc_client_command_reply_users_i,
2007 silc_client_command_reply_free(cmd);
2010 /* Private range commands, specific to this implementation (and compatible
2011 with SILC Server >= 0.9). */
2013 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2015 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2016 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2018 if (cmd->error != SILC_STATUS_OK) {
2019 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2020 "%s", silc_get_status_message(cmd->error));
2021 COMMAND_REPLY_ERROR;
2025 /* Notify application */
2026 COMMAND_REPLY((ARGS));
2029 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2030 silc_client_command_reply_free(cmd);
2033 SILC_CLIENT_CMD_REPLY_FUNC(close)
2035 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2036 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2038 if (cmd->error != SILC_STATUS_OK) {
2039 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2040 "%s", silc_get_status_message(cmd->error));
2041 COMMAND_REPLY_ERROR;
2045 /* Notify application */
2046 COMMAND_REPLY((ARGS));
2049 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2050 silc_client_command_reply_free(cmd);
2053 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2055 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2056 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2058 if (cmd->error != SILC_STATUS_OK) {
2059 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2060 "%s", silc_get_status_message(cmd->error));
2061 COMMAND_REPLY_ERROR;
2065 /* Notify application */
2066 COMMAND_REPLY((ARGS));
2069 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2070 silc_client_command_reply_free(cmd);