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));
101 ctx->payload = payload;
102 ctx->args = silc_command_get_args(ctx->payload);
103 ctx->packet = packet;
104 ctx->ident = silc_command_get_ident(ctx->payload);
105 silc_command_get_status(ctx->payload, &ctx->status, &ctx->error);
107 /* Check for pending commands and mark to be exeucted */
109 silc_client_command_pending_check(sock->user_data, ctx,
110 silc_command_get(ctx->payload),
111 ctx->ident, &ctx->callbacks_count);
113 /* Execute command reply */
115 command = silc_command_get(ctx->payload);
117 /* Try to find matching the command identifier */
118 silc_list_start(client->internal->commands);
119 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
120 if (cmd->cmd == command && !cmd->ident)
122 if (cmd->cmd == command && cmd->ident == ctx->ident) {
123 (*cmd->reply)((void *)ctx, NULL);
128 if (cmd == SILC_LIST_END) {
130 /* No specific identifier for command reply, call first one found */
137 /* Free command reply context and its internals. */
139 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
142 silc_command_payload_free(cmd->payload);
148 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
152 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
153 SilcClientID *client_id;
154 SilcClientEntry client_entry = NULL;
156 unsigned char *id_data, *tmp;
157 char *nickname = NULL, *username = NULL;
158 char *realname = NULL;
159 SilcUInt32 idle = 0, mode = 0;
160 SilcBufferStruct channels, ch_user_modes;
161 bool has_channels = FALSE, has_user_modes = FALSE;
162 unsigned char *fingerprint;
163 SilcUInt32 fingerprint_len;
165 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
172 client_id = silc_id_payload_parse_id(id_data, len, NULL);
179 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
180 username = silc_argument_get_arg_type(cmd->args, 4, &len);
181 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
182 if (!nickname || !username || !realname) {
188 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
190 silc_buffer_set(&channels, tmp, len);
194 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
196 SILC_GET32_MSB(mode, tmp);
198 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
200 SILC_GET32_MSB(idle, tmp);
202 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
204 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
206 silc_buffer_set(&ch_user_modes, tmp, len);
207 has_user_modes = TRUE;
210 /* Check if we have this client cached already. */
211 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
213 SILC_LOG_DEBUG(("Adding new client entry"));
215 silc_client_add_client(cmd->client, conn, nickname, username, realname,
218 silc_client_update_client(cmd->client, conn, client_entry,
219 nickname, username, realname, mode);
220 silc_free(client_id);
223 if (fingerprint && !client_entry->fingerprint) {
224 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
225 client_entry->fingerprint_len = fingerprint_len;
228 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
229 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
231 /* Notify application */
232 if (!cmd->callbacks_count && notify)
233 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
234 has_channels ? &channels : NULL, mode, idle,
235 fingerprint, has_user_modes ? &ch_user_modes : NULL));
238 /* Received reply for WHOIS command. This maybe called several times
239 for one WHOIS command as server may reply with list of results. */
241 SILC_CLIENT_CMD_REPLY_FUNC(whois)
243 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
244 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
246 COMMAND_CHECK_STATUS;
248 /* Save WHOIS info */
249 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
251 /* Pending callbacks are not executed if this was an list entry */
252 if (cmd->status != SILC_STATUS_OK &&
253 cmd->status != SILC_STATUS_LIST_END) {
254 silc_client_command_reply_free(cmd);
259 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
262 /* If we received notify for invalid ID we'll remove the ID if we
264 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
265 SilcClientEntry client_entry;
268 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
271 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
273 client_entry = silc_client_get_client_by_id(cmd->client, conn,
276 silc_client_del_client(cmd->client, conn, client_entry);
277 silc_free(client_id);
282 silc_client_command_reply_free(cmd);
285 /* Received reply for WHOWAS command. */
287 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
289 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
290 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
291 SilcClientID *client_id;
292 SilcClientEntry client_entry = NULL;
294 unsigned char *id_data;
295 char *nickname, *username;
296 char *realname = NULL;
298 COMMAND_CHECK_STATUS;
300 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
306 client_id = silc_id_payload_parse_id(id_data, len, NULL);
312 /* Get the client entry, if exists */
313 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
314 silc_free(client_id);
316 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
317 username = silc_argument_get_arg_type(cmd->args, 4, &len);
318 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
319 if (!nickname || !username) {
324 /* Notify application. We don't save any history information to any
325 cache. Just pass the data to the application for displaying on
327 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
329 /* Pending callbacks are not executed if this was an list entry */
330 if (cmd->status != SILC_STATUS_OK &&
331 cmd->status != SILC_STATUS_LIST_END) {
332 silc_client_command_reply_free(cmd);
337 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
339 silc_client_command_reply_free(cmd);
343 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
347 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
348 SilcClient client = cmd->client;
349 SilcClientID *client_id = NULL;
350 SilcServerID *server_id = NULL;
351 SilcChannelID *channel_id = NULL;
352 SilcClientEntry client_entry;
353 SilcServerEntry server_entry;
354 SilcChannelEntry channel_entry;
356 unsigned char *id_data;
357 char *name = NULL, *info = NULL;
358 SilcIDPayload idp = NULL;
361 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
367 idp = silc_id_payload_parse(id_data, len);
374 name = silc_argument_get_arg_type(cmd->args, 3, &len);
375 info = silc_argument_get_arg_type(cmd->args, 4, &len);
377 id_type = silc_id_payload_get_type(idp);
381 client_id = silc_id_payload_get_id(idp);
383 SILC_LOG_DEBUG(("Received client information"));
385 /* Check if we have this client cached already. */
386 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
388 SILC_LOG_DEBUG(("Adding new client entry"));
390 silc_client_add_client(cmd->client, conn, name, info, NULL,
391 silc_id_dup(client_id, id_type), 0);
393 silc_client_update_client(cmd->client, conn, client_entry,
394 name, info, NULL, 0);
397 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
398 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
400 /* Notify application */
402 COMMAND_REPLY((ARGS, client_entry, name, info));
406 server_id = silc_id_payload_get_id(idp);
408 SILC_LOG_DEBUG(("Received server information"));
410 /* Check if we have this server cached already. */
411 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
413 SILC_LOG_DEBUG(("Adding new server entry"));
414 server_entry = silc_client_add_server(cmd->client, conn, name, info,
415 silc_id_dup(server_id, id_type));
423 /* Notify application */
425 COMMAND_REPLY((ARGS, server_entry, name, info));
428 case SILC_ID_CHANNEL:
429 channel_id = silc_id_payload_get_id(idp);
431 SILC_LOG_DEBUG(("Received channel information"));
433 /* Check if we have this channel cached already. */
434 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
435 if (!channel_entry) {
439 /* Add new channel entry */
440 channel_entry = silc_client_add_channel(client, conn, name, 0,
445 /* Notify application */
447 COMMAND_REPLY((ARGS, channel_entry, name, info));
451 silc_id_payload_free(idp);
452 silc_free(client_id);
453 silc_free(server_id);
454 silc_free(channel_id);
457 /* Received reply for IDENTIFY command. This maybe called several times
458 for one IDENTIFY command as server may reply with list of results.
459 This is totally silent and does not print anything on screen. */
461 SILC_CLIENT_CMD_REPLY_FUNC(identify)
463 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
464 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
466 COMMAND_CHECK_STATUS;
468 /* Save IDENTIFY info */
469 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
471 /* Pending callbacks are not executed if this was an list entry */
472 if (cmd->status != SILC_STATUS_OK &&
473 cmd->status != SILC_STATUS_LIST_END) {
474 silc_client_command_reply_free(cmd);
479 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
482 /* If we received notify for invalid ID we'll remove the ID if we
484 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
485 SilcClientEntry client_entry;
488 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
491 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
493 client_entry = silc_client_get_client_by_id(cmd->client, conn,
496 silc_client_del_client(cmd->client, conn, client_entry);
497 silc_free(client_id);
502 silc_client_command_reply_free(cmd);
505 /* Received reply for command NICK. If everything went without errors
506 we just received our new Client ID. */
508 SILC_CLIENT_CMD_REPLY_FUNC(nick)
510 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
511 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
514 SilcUInt32 argc, len;
516 SILC_LOG_DEBUG(("Start"));
518 if (cmd->error != SILC_STATUS_OK) {
519 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
520 "Cannot set nickname: %s",
521 silc_get_status_message(cmd->error));
526 argc = silc_argument_get_arg_num(cmd->args);
527 if (argc < 2 || argc > 3) {
528 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
529 "Cannot set nickname: bad reply to command");
534 /* Take received Client ID */
535 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
536 idp = silc_id_payload_parse(tmp, len);
541 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
543 /* Take the new nickname too */
544 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
546 silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
548 silc_free(conn->nickname);
549 conn->nickname = strdup(tmp);
550 conn->local_entry->nickname = conn->nickname;
551 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
552 silc_idcache_add(conn->client_cache, strdup(tmp),
553 conn->local_entry->id, conn->local_entry, 0, NULL);
556 /* Notify application */
557 COMMAND_REPLY((ARGS, conn->local_entry, conn->local_entry->nickname));
560 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
561 silc_client_command_reply_free(cmd);
564 /* Received reply to the LIST command. */
566 SILC_CLIENT_CMD_REPLY_FUNC(list)
568 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
569 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
570 unsigned char *tmp, *name, *topic;
571 SilcUInt32 usercount = 0, len;
572 SilcChannelID *channel_id = NULL;
573 SilcChannelEntry channel_entry;
575 COMMAND_CHECK_STATUS;
577 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
583 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
589 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
595 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
596 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
598 SILC_GET32_MSB(usercount, tmp);
600 /* Check whether the channel exists, and add it to cache if it doesn't. */
601 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
603 if (!channel_entry) {
604 /* Add new channel entry */
605 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
607 if (!channel_entry) {
614 /* Notify application */
615 COMMAND_REPLY((ARGS, channel_entry, name, topic, usercount));
617 /* Pending callbacks are not executed if this was an list entry */
618 if (cmd->status != SILC_STATUS_OK &&
619 cmd->status != SILC_STATUS_LIST_END) {
620 silc_client_command_reply_free(cmd);
625 silc_free(channel_id);
626 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
628 silc_client_command_reply_free(cmd);
631 /* Received reply to topic command. */
633 SILC_CLIENT_CMD_REPLY_FUNC(topic)
635 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
636 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
637 SilcChannelEntry channel;
638 SilcChannelID *channel_id = NULL;
641 SilcUInt32 argc, len;
643 if (cmd->error != SILC_STATUS_OK) {
644 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
645 "%s", silc_get_status_message(cmd->error));
650 argc = silc_argument_get_arg_num(cmd->args);
651 if (argc < 1 || argc > 3) {
656 /* Take Channel ID */
657 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
662 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
666 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
670 /* Get the channel entry */
671 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
673 silc_free(channel_id);
678 /* Notify application */
679 COMMAND_REPLY((ARGS, channel, topic));
682 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
683 silc_client_command_reply_free(cmd);
686 /* Received reply to invite command. */
688 SILC_CLIENT_CMD_REPLY_FUNC(invite)
690 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
691 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
692 SilcChannelEntry channel;
693 SilcChannelID *channel_id;
697 if (cmd->error != SILC_STATUS_OK) {
698 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
699 "%s", silc_get_status_message(cmd->error));
704 /* Take Channel ID */
705 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
709 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
713 /* Get the channel entry */
714 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
716 silc_free(channel_id);
721 /* Get the invite list */
722 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
724 /* Notify application */
725 COMMAND_REPLY((ARGS, channel, tmp));
728 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
729 silc_client_command_reply_free(cmd);
732 /* Received reply to the KILL command. */
734 SILC_CLIENT_CMD_REPLY_FUNC(kill)
736 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
737 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
739 if (cmd->error != SILC_STATUS_OK) {
740 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
741 "%s", silc_get_status_message(cmd->error));
746 /* Notify application */
747 COMMAND_REPLY((ARGS));
750 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
751 silc_client_command_reply_free(cmd);
754 /* Received reply to INFO command. We receive the server ID and some
755 information about the server user requested. */
757 SILC_CLIENT_CMD_REPLY_FUNC(info)
759 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
760 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
762 SilcServerEntry server;
763 SilcServerID *server_id = NULL;
764 char *server_name, *server_info;
767 SILC_LOG_DEBUG(("Start"));
769 if (cmd->error != SILC_STATUS_OK) {
770 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
771 silc_get_status_message(cmd->error));
777 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
781 server_id = silc_id_payload_parse_id(tmp, len, NULL);
785 /* Get server name */
786 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
790 /* Get server info */
791 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
795 /* See whether we have this server cached. If not create it. */
796 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
798 SILC_LOG_DEBUG(("New server entry"));
799 server = silc_client_add_server(cmd->client, conn, server_name,
801 silc_id_dup(server_id, SILC_ID_SERVER));
806 /* Notify application */
807 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
810 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
811 silc_free(server_id);
812 silc_client_command_reply_free(cmd);
815 /* Received reply to PING command. The reply time is shown to user. */
817 SILC_CLIENT_CMD_REPLY_FUNC(ping)
819 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
820 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
823 time_t diff, curtime;
825 if (cmd->error != SILC_STATUS_OK) {
826 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
827 "%s", silc_get_status_message(cmd->error));
832 curtime = time(NULL);
833 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
834 cmd->packet->src_id_type);
835 if (!id || !conn->ping) {
840 for (i = 0; i < conn->ping_count; i++) {
841 if (!conn->ping[i].dest_id)
843 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
844 diff = curtime - conn->ping[i].start_time;
845 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
846 "Ping reply from %s: %d second%s",
847 conn->ping[i].dest_name, diff,
848 diff == 1 ? "" : "s");
850 conn->ping[i].start_time = 0;
851 silc_free(conn->ping[i].dest_id);
852 conn->ping[i].dest_id = NULL;
853 silc_free(conn->ping[i].dest_name);
854 conn->ping[i].dest_name = NULL;
861 /* Notify application */
862 COMMAND_REPLY((ARGS));
865 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
866 silc_client_command_reply_free(cmd);
869 /* Received reply for JOIN command. */
871 SILC_CLIENT_CMD_REPLY_FUNC(join)
873 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
874 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
875 SilcChannelEntry channel;
877 SilcChannelID *channel_id;
878 SilcUInt32 argc, mode = 0, len, list_count;
879 char *topic, *tmp, *channel_name = NULL, *hmac;
880 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
883 SILC_LOG_DEBUG(("Start"));
885 if (cmd->error != SILC_STATUS_OK) {
886 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
887 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
888 "%s", silc_get_status_message(cmd->error));
893 argc = silc_argument_get_arg_num(cmd->args);
894 if (argc < 7 || argc > 14) {
895 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
896 "Cannot join channel: Bad reply packet");
901 /* Get channel name */
902 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
904 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
905 "Cannot join channel: Bad reply packet");
912 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
914 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
915 "Cannot join channel: Bad reply packet");
919 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
925 /* Get channel mode */
926 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
928 SILC_GET32_MSB(mode, tmp);
930 /* Get channel key */
931 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
933 keyp = silc_buffer_alloc(len);
934 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
935 silc_buffer_put(keyp, tmp, len);
939 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
941 /* Check whether we have this channel entry already. */
942 channel = silc_client_get_channel(cmd->client, conn, channel_name);
944 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
945 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
947 /* Create new channel entry */
948 channel = silc_client_add_channel(cmd->client, conn, channel_name,
952 conn->current_channel = channel;
955 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
957 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
958 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
959 "Cannot join channel: Unsupported HMAC `%s'", hmac);
965 /* Get the list count */
966 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
969 SILC_GET32_MSB(list_count, tmp);
971 /* Get Client ID list */
972 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
976 client_id_list = silc_buffer_alloc(len);
977 silc_buffer_pull_tail(client_id_list, len);
978 silc_buffer_put(client_id_list, tmp, len);
980 /* Get client mode list */
981 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
985 client_mode_list = silc_buffer_alloc(len);
986 silc_buffer_pull_tail(client_mode_list, len);
987 silc_buffer_put(client_mode_list, tmp, len);
989 /* Add clients we received in the reply to the channel */
990 for (i = 0; i < list_count; i++) {
993 SilcClientID *client_id;
994 SilcClientEntry client_entry;
997 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
999 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1004 SILC_GET32_MSB(mode, client_mode_list->data);
1006 /* Check if we have this client cached already. */
1007 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1008 if (!client_entry) {
1009 /* No, we don't have it, add entry for it. */
1011 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1012 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1015 /* Join client to the channel */
1016 if (!silc_client_on_channel(channel, client_entry)) {
1017 chu = silc_calloc(1, sizeof(*chu));
1018 chu->client = client_entry;
1019 chu->channel = channel;
1021 silc_hash_table_add(channel->user_list, client_entry, chu);
1022 silc_hash_table_add(client_entry->channels, channel, chu);
1025 silc_free(client_id);
1026 silc_buffer_pull(client_id_list, idp_len);
1027 silc_buffer_pull(client_mode_list, 4);
1029 silc_buffer_push(client_id_list, client_id_list->data -
1030 client_id_list->head);
1031 silc_buffer_push(client_mode_list, client_mode_list->data -
1032 client_mode_list->head);
1034 /* Save channel key */
1035 if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1036 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1038 /* Notify application */
1039 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1040 keyp ? keyp->head : NULL, NULL,
1041 NULL, topic, hmac, list_count, client_id_list,
1045 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1046 silc_client_command_reply_free(cmd);
1049 silc_buffer_free(keyp);
1051 silc_buffer_free(client_id_list);
1052 if (client_mode_list)
1053 silc_buffer_free(client_mode_list);
1056 /* Received reply for MOTD command */
1058 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1060 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1061 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1063 char *motd = NULL, *cp, line[256];
1065 if (cmd->error != SILC_STATUS_OK) {
1066 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1067 "%s", silc_get_status_message(cmd->error));
1068 COMMAND_REPLY_ERROR;
1072 argc = silc_argument_get_arg_num(cmd->args);
1074 COMMAND_REPLY_ERROR;
1079 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1081 COMMAND_REPLY_ERROR;
1088 if (cp[i++] == '\n') {
1089 memset(line, 0, sizeof(line));
1090 strncat(line, cp, i - 1);
1096 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1105 /* Notify application */
1106 COMMAND_REPLY((ARGS, motd));
1109 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1110 silc_client_command_reply_free(cmd);
1113 /* Received reply tot he UMODE command. Save the current user mode */
1115 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1117 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1118 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1122 if (cmd->error != SILC_STATUS_OK) {
1123 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1124 "%s", silc_get_status_message(cmd->error));
1125 COMMAND_REPLY_ERROR;
1129 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1131 COMMAND_REPLY_ERROR;
1135 SILC_GET32_MSB(mode, tmp);
1136 conn->local_entry->mode = mode;
1138 /* Notify application */
1139 COMMAND_REPLY((ARGS, mode));
1142 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1143 silc_client_command_reply_free(cmd);
1146 /* Received reply for CMODE command. */
1148 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1150 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1151 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1154 SilcChannelID *channel_id;
1155 SilcChannelEntry channel;
1158 if (cmd->error != SILC_STATUS_OK) {
1159 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1160 "%s", silc_get_status_message(cmd->error));
1161 COMMAND_REPLY_ERROR;
1165 /* Take Channel ID */
1166 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1169 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1173 /* Get the channel entry */
1174 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1176 silc_free(channel_id);
1177 COMMAND_REPLY_ERROR;
1181 /* Get channel mode */
1182 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1184 silc_free(channel_id);
1185 COMMAND_REPLY_ERROR;
1190 SILC_GET32_MSB(mode, tmp);
1191 channel->mode = mode;
1193 /* Notify application */
1194 COMMAND_REPLY((ARGS, channel, mode));
1196 silc_free(channel_id);
1199 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1200 silc_client_command_reply_free(cmd);
1203 /* Received reply for CUMODE command */
1205 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1207 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1208 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1209 SilcClientID *client_id;
1210 SilcChannelID *channel_id;
1211 SilcClientEntry client_entry;
1212 SilcChannelEntry channel;
1213 SilcChannelUser chu;
1214 unsigned char *modev, *tmp, *id;
1215 SilcUInt32 len, mode;
1217 if (cmd->error != SILC_STATUS_OK) {
1218 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1219 "%s", silc_get_status_message(cmd->error));
1220 COMMAND_REPLY_ERROR;
1224 /* Get channel mode */
1225 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1227 COMMAND_REPLY_ERROR;
1231 /* Take Channel ID */
1232 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1235 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1239 /* Get the channel entry */
1240 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1242 silc_free(channel_id);
1243 COMMAND_REPLY_ERROR;
1248 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1250 silc_free(channel_id);
1251 COMMAND_REPLY_ERROR;
1254 client_id = silc_id_payload_parse_id(id, len, NULL);
1256 silc_free(channel_id);
1257 COMMAND_REPLY_ERROR;
1261 /* Get client entry */
1262 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1263 if (!client_entry) {
1264 silc_free(channel_id);
1265 silc_free(client_id);
1266 COMMAND_REPLY_ERROR;
1271 SILC_GET32_MSB(mode, modev);
1272 chu = silc_client_on_channel(channel, client_entry);
1276 /* Notify application */
1277 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1278 silc_free(client_id);
1279 silc_free(channel_id);
1282 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1283 silc_client_command_reply_free(cmd);
1286 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1288 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1289 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1291 if (cmd->error != SILC_STATUS_OK) {
1292 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1293 "%s", silc_get_status_message(cmd->error));
1294 COMMAND_REPLY_ERROR;
1298 /* Notify application */
1299 COMMAND_REPLY((ARGS));
1302 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1303 silc_client_command_reply_free(cmd);
1306 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1308 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1309 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1311 if (cmd->error != SILC_STATUS_OK) {
1312 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1313 "%s", silc_get_status_message(cmd->error));
1314 COMMAND_REPLY_ERROR;
1318 /* Notify application */
1319 COMMAND_REPLY((ARGS));
1322 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1323 silc_client_command_reply_free(cmd);
1326 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1328 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1329 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1331 if (cmd->error != SILC_STATUS_OK) {
1332 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1333 "%s", silc_get_status_message(cmd->error));
1334 COMMAND_REPLY_ERROR;
1338 /* Notify application */
1339 COMMAND_REPLY((ARGS));
1342 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1343 silc_client_command_reply_free(cmd);
1346 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1348 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1349 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1352 if (cmd->error != SILC_STATUS_OK) {
1353 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1354 "%s", silc_get_status_message(cmd->error));
1355 COMMAND_REPLY_ERROR;
1359 /* Notify application */
1360 COMMAND_REPLY((ARGS));
1362 /* Generate the detachment data and deliver it to the client in the
1363 detach client operation */
1364 detach = silc_client_get_detach_data(cmd->client, conn);
1366 cmd->client->internal->ops->detach(cmd->client, conn,
1367 detach->data, detach->len);
1368 silc_buffer_free(detach);
1372 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1373 silc_client_command_reply_free(cmd);
1376 SILC_CLIENT_CMD_REPLY_FUNC(watch)
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_WATCH);
1393 silc_client_command_reply_free(cmd);
1396 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1398 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1399 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1400 SilcChannelEntry channel;
1401 SilcChannelID *channel_id;
1405 if (cmd->error != SILC_STATUS_OK) {
1406 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1407 "%s", silc_get_status_message(cmd->error));
1408 COMMAND_REPLY_ERROR;
1412 /* Take Channel ID */
1413 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1417 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1421 /* Get the channel entry */
1422 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1424 silc_free(channel_id);
1425 COMMAND_REPLY_ERROR;
1429 /* Get the ban list */
1430 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1432 /* Notify application */
1433 COMMAND_REPLY((ARGS, channel, tmp));
1436 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1437 silc_client_command_reply_free(cmd);
1440 /* Reply to LEAVE command. */
1442 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1444 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1445 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1446 SilcChannelID *channel_id;
1447 SilcChannelEntry channel = NULL;
1451 if (cmd->error != SILC_STATUS_OK) {
1452 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1453 "%s", silc_get_status_message(cmd->error));
1454 COMMAND_REPLY_ERROR;
1458 /* From protocol version 1.1 we get the channel ID of the left channel */
1459 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1461 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1465 /* Get the channel entry */
1466 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1468 silc_free(channel_id);
1469 COMMAND_REPLY_ERROR;
1473 silc_free(channel_id);
1476 /* Notify application */
1477 COMMAND_REPLY((ARGS, channel));
1480 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1481 silc_client_command_reply_free(cmd);
1484 /* Channel resolving callback for USERS command reply. */
1486 static void silc_client_command_reply_users_cb(SilcClient client,
1487 SilcClientConnection conn,
1488 SilcChannelEntry *channels,
1489 SilcUInt32 channels_count,
1492 if (!channels_count) {
1493 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1494 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1496 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1497 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1498 "%s", silc_get_status_message(cmd->error));
1499 COMMAND_REPLY_ERROR;
1500 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1501 silc_client_command_reply_free(cmd);
1505 silc_client_command_reply_users(context, NULL);
1509 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1512 SilcGetChannelCallback get_channel,
1513 SilcCommandCb get_clients)
1515 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1516 SilcChannelEntry channel;
1517 SilcClientEntry client_entry;
1518 SilcChannelUser chu;
1519 SilcChannelID *channel_id = NULL;
1520 SilcBufferStruct client_id_list, client_mode_list;
1522 SilcUInt32 tmp_len, list_count;
1524 unsigned char **res_argv = NULL;
1525 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1526 bool wait_res = FALSE;
1528 SILC_LOG_DEBUG(("Start"));
1530 /* Get channel ID */
1531 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1533 COMMAND_REPLY_ERROR;
1536 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1538 COMMAND_REPLY_ERROR;
1542 /* Get the list count */
1543 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1545 COMMAND_REPLY_ERROR;
1548 SILC_GET32_MSB(list_count, tmp);
1550 /* Get Client ID list */
1551 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1553 COMMAND_REPLY_ERROR;
1556 silc_buffer_set(&client_id_list, tmp, tmp_len);
1558 /* Get client mode list */
1559 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1561 COMMAND_REPLY_ERROR;
1564 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1566 /* Get channel entry */
1567 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1569 /* Resolve the channel from server */
1570 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1572 silc_free(channel_id);
1576 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1578 /* Cache the received Client ID's and modes. */
1579 for (i = 0; i < list_count; i++) {
1582 SilcClientID *client_id;
1585 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1587 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1592 SILC_GET32_MSB(mode, client_mode_list.data);
1594 /* Check if we have this client cached already. */
1595 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1596 if (!client_entry || !client_entry->username || !client_entry->realname) {
1598 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1599 /* Attach to this resolving and wait until it finishes */
1600 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1601 client_entry->resolve_cmd_ident,
1605 silc_buffer_pull(&client_id_list, idp_len);
1606 silc_buffer_pull(&client_mode_list, 4);
1609 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1610 client_entry->resolve_cmd_ident = conn->cmd_ident + 1;
1613 /* No we don't have it (or it is incomplete in information), query
1614 it from the server. Assemble argument table that will be sent
1615 for the WHOIS command later. */
1616 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1618 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1620 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1622 res_argv[res_argc] = client_id_list.data;
1623 res_argv_lens[res_argc] = idp_len;
1624 res_argv_types[res_argc] = res_argc + 4;
1627 if (!silc_client_on_channel(channel, client_entry)) {
1628 chu = silc_calloc(1, sizeof(*chu));
1629 chu->client = client_entry;
1631 chu->channel = channel;
1632 silc_hash_table_add(channel->user_list, client_entry, chu);
1633 silc_hash_table_add(client_entry->channels, channel, chu);
1637 silc_free(client_id);
1638 silc_buffer_pull(&client_id_list, idp_len);
1639 silc_buffer_pull(&client_mode_list, 4);
1642 /* Query the client information from server if the list included clients
1643 that we don't know about. */
1647 /* Send the WHOIS command to server */
1648 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1649 silc_client_command_reply_whois_i, 0,
1651 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1652 res_argc, res_argv, res_argv_lens,
1653 res_argv_types, conn->cmd_ident);
1654 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1655 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1658 /* Register pending command callback. After we've received the WHOIS
1659 command reply we will reprocess this command reply by re-calling this
1660 USERS command reply callback. */
1661 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1664 silc_buffer_free(res_cmd);
1665 silc_free(channel_id);
1666 silc_free(res_argv);
1667 silc_free(res_argv_lens);
1668 silc_free(res_argv_types);
1675 silc_buffer_push(&client_id_list, (client_id_list.data -
1676 client_id_list.head));
1677 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1678 client_mode_list.head));
1680 /* Notify application */
1682 COMMAND_REPLY((ARGS, channel, list_count, &client_id_list,
1683 &client_mode_list));
1686 silc_free(channel_id);
1690 /* Reply to USERS command. Received list of client ID's and theirs modes
1691 on the channel we requested. */
1693 SILC_CLIENT_CMD_REPLY_FUNC(users)
1695 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1696 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1698 SILC_LOG_DEBUG(("Start"));
1700 if (cmd->error != SILC_STATUS_OK) {
1701 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1702 "%s", silc_get_status_message(cmd->error));
1703 COMMAND_REPLY_ERROR;
1707 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
1708 silc_client_command_reply_users_cb,
1709 silc_client_command_reply_users))
1713 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1714 silc_client_command_reply_free(cmd);
1717 /* Received command reply to GETKEY command. WE've received the remote
1718 client's public key. */
1720 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1722 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1723 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1724 SilcIDPayload idp = NULL;
1725 SilcClientID *client_id = NULL;
1726 SilcClientEntry client_entry;
1727 SilcServerID *server_id = NULL;
1728 SilcServerEntry server_entry;
1730 unsigned char *tmp, *pk;
1734 SilcPublicKey public_key = NULL;
1736 SILC_LOG_DEBUG(("Start"));
1738 if (cmd->error != SILC_STATUS_OK) {
1739 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1740 "%s", silc_get_status_message(cmd->error));
1741 COMMAND_REPLY_ERROR;
1745 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1747 COMMAND_REPLY_ERROR;
1750 idp = silc_id_payload_parse(tmp, len);
1752 COMMAND_REPLY_ERROR;
1756 /* Get the public key payload */
1757 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1759 /* Decode the public key */
1760 SILC_GET16_MSB(pk_len, tmp);
1761 SILC_GET16_MSB(type, tmp + 2);
1764 if (type == SILC_SKE_PK_TYPE_SILC)
1765 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1769 id_type = silc_id_payload_get_type(idp);
1770 if (id_type == SILC_ID_CLIENT) {
1771 /* Received client's public key */
1772 client_id = silc_id_payload_get_id(idp);
1773 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1774 if (!client_entry) {
1775 COMMAND_REPLY_ERROR;
1779 /* Notify application */
1780 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1781 } else if (id_type == SILC_ID_SERVER) {
1782 /* Received server's public key */
1783 server_id = silc_id_payload_get_id(idp);
1784 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
1785 if (!server_entry) {
1786 COMMAND_REPLY_ERROR;
1790 /* Notify application */
1791 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1795 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1797 silc_id_payload_free(idp);
1799 silc_pkcs_public_key_free(public_key);
1800 silc_free(client_id);
1801 silc_free(server_id);
1802 silc_client_command_reply_free(cmd);
1805 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1807 silc_client_command_reply_free(context);
1811 /******************************************************************************
1813 Internal command reply functions
1815 ******************************************************************************/
1817 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1819 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1820 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1822 COMMAND_CHECK_STATUS_I;
1824 /* Save WHOIS info */
1825 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
1827 /* Pending callbacks are not executed if this was an list entry */
1828 if (cmd->status != SILC_STATUS_OK &&
1829 cmd->status != SILC_STATUS_LIST_END) {
1830 silc_client_command_reply_free(cmd);
1835 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1838 /* If we received notify for invalid ID we'll remove the ID if we
1840 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1841 SilcClientEntry client_entry;
1843 unsigned char *tmp =
1844 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1847 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1849 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1852 silc_client_del_client(cmd->client, conn, client_entry);
1853 silc_free(client_id);
1858 /* Unregister this command reply */
1859 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
1860 NULL, silc_client_command_reply_whois_i,
1863 silc_client_command_reply_free(cmd);
1866 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
1868 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1869 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1871 COMMAND_CHECK_STATUS_I;
1873 /* Save IDENTIFY info */
1874 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
1876 /* Pending callbacks are not executed if this was an list entry */
1877 if (cmd->status != SILC_STATUS_OK &&
1878 cmd->status != SILC_STATUS_LIST_END) {
1879 silc_client_command_reply_free(cmd);
1884 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
1887 /* If we received notify for invalid ID we'll remove the ID if we
1889 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1890 SilcClientEntry client_entry;
1892 unsigned char *tmp =
1893 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
1896 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1898 client_entry = silc_client_get_client_by_id(cmd->client, conn,
1901 silc_client_del_client(cmd->client, conn, client_entry);
1902 silc_free(client_id);
1907 /* Unregister this command reply */
1908 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
1909 NULL, silc_client_command_reply_identify_i,
1912 silc_client_command_reply_free(cmd);
1915 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
1917 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1918 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1920 SilcServerEntry server;
1921 SilcServerID *server_id = NULL;
1922 char *server_name, *server_info;
1925 COMMAND_CHECK_STATUS_I;
1928 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1932 server_id = silc_id_payload_parse_id(tmp, len, NULL);
1936 /* Get server name */
1937 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1941 /* Get server info */
1942 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
1946 /* See whether we have this server cached. If not create it. */
1947 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
1949 SILC_LOG_DEBUG(("New server entry"));
1950 silc_client_add_server(cmd->client, conn, server_name, server_info,
1951 silc_id_dup(server_id, SILC_ID_SERVER));
1955 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
1956 silc_free(server_id);
1958 silc_client_command_reply_free(cmd);
1961 static void silc_client_command_reply_users_i_cb(SilcClient client,
1962 SilcClientConnection conn,
1963 SilcChannelEntry *channels,
1964 SilcUInt32 channels_count,
1967 if (!channels_count) {
1968 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1969 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1971 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1972 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1973 "%s", silc_get_status_message(cmd->error));
1974 COMMAND_REPLY_ERROR;
1975 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1976 silc_client_command_reply_free(cmd);
1980 silc_client_command_reply_users_i(context, NULL);
1983 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
1985 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1987 COMMAND_CHECK_STATUS_I;
1989 /* Save USERS info */
1990 if (silc_client_command_reply_users_save(
1991 cmd, cmd->status, FALSE,
1992 silc_client_command_reply_users_i_cb,
1993 silc_client_command_reply_users_i))
1997 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2000 /* Unregister this command reply */
2001 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2002 NULL, silc_client_command_reply_users_i,
2005 silc_client_command_reply_free(cmd);
2008 /* Private range commands, specific to this implementation (and compatible
2009 with SILC Server >= 0.9). */
2011 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2013 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2014 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2016 if (cmd->error != SILC_STATUS_OK) {
2017 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2018 "%s", silc_get_status_message(cmd->error));
2019 COMMAND_REPLY_ERROR;
2023 /* Notify application */
2024 COMMAND_REPLY((ARGS));
2027 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2028 silc_client_command_reply_free(cmd);
2031 SILC_CLIENT_CMD_REPLY_FUNC(close)
2033 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2034 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2036 if (cmd->error != SILC_STATUS_OK) {
2037 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2038 "%s", silc_get_status_message(cmd->error));
2039 COMMAND_REPLY_ERROR;
2043 /* Notify application */
2044 COMMAND_REPLY((ARGS));
2047 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2048 silc_client_command_reply_free(cmd);
2051 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2053 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2054 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2056 if (cmd->error != SILC_STATUS_OK) {
2057 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2058 "%s", silc_get_status_message(cmd->error));
2059 COMMAND_REPLY_ERROR;
2063 /* Notify application */
2064 COMMAND_REPLY((ARGS));
2067 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2068 silc_client_command_reply_free(cmd);