5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2005 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(cmd->status); \
54 /* List of errors */ \
55 COMMAND_REPLY_ERROR(cmd->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);
184 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
188 client_id = silc_id_payload_parse_id(id_data, len, NULL);
191 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
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) {
200 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
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,
235 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
239 silc_client_update_client(cmd->client, conn, client_entry,
240 nickname, username, realname, mode);
241 silc_free(client_id);
244 if (fingerprint && !client_entry->fingerprint) {
245 client_entry->fingerprint = silc_memdup(fingerprint, fingerprint_len);
246 client_entry->fingerprint_len = fingerprint_len;
249 /* Take Requested Attributes if set. */
250 tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
252 if (client_entry->attrs)
253 silc_attribute_payload_list_free(client_entry->attrs);
254 client_entry->attrs = silc_attribute_payload_parse(tmp, len);
257 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
259 /* Notify application */
260 if (!cmd->callbacks_count && notify)
261 COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname,
262 has_channels ? &channels : NULL, mode, idle,
263 fingerprint, has_user_modes ? &ch_user_modes : NULL,
264 client_entry->attrs));
267 /* Received reply for WHOIS command. This maybe called several times
268 for one WHOIS command as server may reply with list of results. */
270 SILC_CLIENT_CMD_REPLY_FUNC(whois)
272 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
273 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
275 COMMAND_CHECK_STATUS;
277 /* Save WHOIS info */
278 silc_client_command_reply_whois_save(cmd, cmd->status, TRUE);
280 /* Pending callbacks are not executed if this was an list entry */
281 if (cmd->status != SILC_STATUS_OK &&
282 cmd->status != SILC_STATUS_LIST_END) {
283 silc_client_command_reply_free(cmd);
288 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
291 /* If we received notify for invalid ID we'll remove the ID if we
293 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
294 SilcClientEntry client_entry;
297 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
300 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
302 client_entry = silc_client_get_client_by_id(cmd->client, conn,
305 silc_client_del_client(cmd->client, conn, client_entry);
306 silc_free(client_id);
311 silc_client_command_reply_free(cmd);
314 /* Received reply for WHOWAS command. */
316 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
318 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
319 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
320 SilcClientID *client_id;
321 SilcClientEntry client_entry = NULL;
323 unsigned char *id_data;
324 char *nickname, *username;
325 char *realname = NULL;
327 COMMAND_CHECK_STATUS;
329 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
331 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
335 client_id = silc_id_payload_parse_id(id_data, len, NULL);
337 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
341 /* Get the client entry, if exists */
342 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
343 silc_free(client_id);
345 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
346 username = silc_argument_get_arg_type(cmd->args, 4, &len);
347 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
348 if (!nickname || !username) {
349 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
353 /* Notify application. We don't save any history information to any
354 cache. Just pass the data to the application for displaying on
356 COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname));
358 /* Pending callbacks are not executed if this was an list entry */
359 if (cmd->status != SILC_STATUS_OK &&
360 cmd->status != SILC_STATUS_LIST_END) {
361 silc_client_command_reply_free(cmd);
366 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
368 silc_client_command_reply_free(cmd);
372 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
376 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
377 SilcClient client = cmd->client;
378 SilcClientID *client_id = NULL;
379 SilcServerID *server_id = NULL;
380 SilcChannelID *channel_id = NULL;
381 SilcClientEntry client_entry;
382 SilcServerEntry server_entry;
383 SilcChannelEntry channel_entry;
385 unsigned char *id_data;
386 char *name = NULL, *info = NULL;
387 SilcIDPayload idp = NULL;
390 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
393 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
396 idp = silc_id_payload_parse(id_data, len);
399 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
403 name = silc_argument_get_arg_type(cmd->args, 3, &len);
404 info = silc_argument_get_arg_type(cmd->args, 4, &len);
406 id_type = silc_id_payload_get_type(idp);
410 client_id = silc_id_payload_get_id(idp);
412 SILC_LOG_DEBUG(("Received client information"));
414 /* Check if we have this client cached already. */
415 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
417 SILC_LOG_DEBUG(("Adding new client entry"));
419 silc_client_add_client(cmd->client, conn, name, info, NULL,
420 silc_id_dup(client_id, id_type), 0);
423 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
427 silc_client_update_client(cmd->client, conn, client_entry,
428 name, info, NULL, 0);
431 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
433 /* Notify application */
435 COMMAND_REPLY((SILC_ARGS, client_entry, name, info));
439 server_id = silc_id_payload_get_id(idp);
441 SILC_LOG_DEBUG(("Received server information"));
443 /* Check if we have this server cached already. */
444 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
446 SILC_LOG_DEBUG(("Adding new server entry"));
447 server_entry = silc_client_add_server(cmd->client, conn, name, info,
448 silc_id_dup(server_id, id_type));
451 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
455 silc_client_update_server(client, conn, server_entry, name, info);
458 server_entry->resolve_cmd_ident = 0;
460 /* Notify application */
462 COMMAND_REPLY((SILC_ARGS, server_entry, name, info));
465 case SILC_ID_CHANNEL:
466 channel_id = silc_id_payload_get_id(idp);
468 SILC_LOG_DEBUG(("Received channel information"));
470 /* Check if we have this channel cached already. */
471 channel_entry = silc_client_get_channel_by_id(client, conn, channel_id);
472 if (!channel_entry) {
476 /* Add new channel entry */
477 channel_entry = silc_client_add_channel(client, conn, name, 0,
479 if (!channel_entry) {
481 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
487 /* Notify application */
489 COMMAND_REPLY((SILC_ARGS, channel_entry, name, info));
493 silc_id_payload_free(idp);
494 silc_free(client_id);
495 silc_free(server_id);
496 silc_free(channel_id);
499 /* Received reply for IDENTIFY command. This maybe called several times
500 for one IDENTIFY command as server may reply with list of results.
501 This is totally silent and does not print anything on screen. */
503 SILC_CLIENT_CMD_REPLY_FUNC(identify)
505 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
506 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
508 COMMAND_CHECK_STATUS;
510 /* Save IDENTIFY info */
511 silc_client_command_reply_identify_save(cmd, cmd->status, TRUE);
513 /* Pending callbacks are not executed if this was an list entry */
514 if (cmd->status != SILC_STATUS_OK &&
515 cmd->status != SILC_STATUS_LIST_END) {
516 silc_client_command_reply_free(cmd);
521 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
524 /* If we received notify for invalid ID we'll remove the ID if we
526 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
527 SilcClientEntry client_entry;
530 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
533 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
535 client_entry = silc_client_get_client_by_id(cmd->client, conn,
538 silc_client_del_client(cmd->client, conn, client_entry);
539 silc_free(client_id);
544 silc_client_command_reply_free(cmd);
547 /* Received reply for command NICK. If everything went without errors
548 we just received our new Client ID. */
550 SILC_CLIENT_CMD_REPLY_FUNC(nick)
552 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
553 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
556 SilcUInt32 argc, len;
557 SilcClientID old_client_id;
559 SILC_LOG_DEBUG(("Start"));
561 if (cmd->error != SILC_STATUS_OK) {
562 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
563 "Cannot set nickname: %s",
564 silc_get_status_message(cmd->error));
565 COMMAND_REPLY_ERROR(cmd->error);
569 argc = silc_argument_get_arg_num(cmd->args);
570 if (argc < 2 || argc > 3) {
571 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
572 "Cannot set nickname: bad reply to command");
573 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
577 /* Save old Client ID */
578 old_client_id = *conn->local_id;
580 /* Take received Client ID */
581 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
582 idp = silc_id_payload_parse(tmp, len);
584 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
587 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
589 /* Take the new nickname too */
590 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
592 silc_idcache_del_by_context(conn->internal->client_cache,
595 silc_free(conn->nickname);
596 conn->nickname = strdup(tmp);
597 conn->local_entry->nickname = conn->nickname;
599 /* Normalize nickname */
600 tmp = silc_identifier_check(conn->nickname, strlen(conn->nickname),
601 SILC_STRING_UTF8, 128, NULL);
603 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_NICKNAME);
607 silc_client_nickname_format(cmd->client, conn, conn->local_entry);
609 silc_idcache_add(conn->internal->client_cache, tmp,
610 conn->local_entry->id, conn->local_entry, 0, NULL);
613 /* Notify application */
614 COMMAND_REPLY((SILC_ARGS, conn->local_entry, conn->local_entry->nickname,
615 (const SilcClientID *)&old_client_id));
618 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
619 silc_client_command_reply_free(cmd);
622 /* Received reply to the LIST command. */
624 SILC_CLIENT_CMD_REPLY_FUNC(list)
626 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
627 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
628 unsigned char *tmp, *name, *topic;
629 SilcUInt32 usercount = 0, len;
630 SilcChannelID *channel_id = NULL;
631 SilcChannelEntry channel_entry;
633 COMMAND_CHECK_STATUS;
635 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
637 /* There were no channels in the network. */
638 COMMAND_REPLY((SILC_ARGS, NULL, NULL, 0));
642 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
644 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
648 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
650 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
654 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
655 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
657 SILC_GET32_MSB(usercount, tmp);
659 /* Check whether the channel exists, and add it to cache if it doesn't. */
660 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
662 if (!channel_entry) {
663 /* Add new channel entry */
664 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
666 if (!channel_entry) {
667 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
673 /* Notify application */
674 COMMAND_REPLY((SILC_ARGS, channel_entry, name, topic, usercount));
676 /* Pending callbacks are not executed if this was an list entry */
677 if (cmd->status != SILC_STATUS_OK &&
678 cmd->status != SILC_STATUS_LIST_END) {
679 silc_client_command_reply_free(cmd);
684 silc_free(channel_id);
685 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
687 silc_client_command_reply_free(cmd);
690 /* Received reply to topic command. */
692 SILC_CLIENT_CMD_REPLY_FUNC(topic)
694 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
695 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
696 SilcChannelEntry channel;
697 SilcChannelID *channel_id = NULL;
700 SilcUInt32 argc, len;
702 if (cmd->error != SILC_STATUS_OK) {
703 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
704 "Cannot set topic: %s", silc_get_status_message(cmd->error));
705 COMMAND_REPLY_ERROR(cmd->error);
709 argc = silc_argument_get_arg_num(cmd->args);
710 if (argc < 1 || argc > 3) {
711 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
715 /* Take Channel ID */
716 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
721 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
725 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
729 /* Get the channel entry */
730 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
732 silc_free(channel_id);
733 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
738 silc_free(channel->topic);
739 channel->topic = silc_memdup(topic, strlen(topic));
742 /* Notify application */
743 COMMAND_REPLY((SILC_ARGS, channel, topic));
746 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
747 silc_client_command_reply_free(cmd);
750 /* Received reply to invite command. */
752 SILC_CLIENT_CMD_REPLY_FUNC(invite)
754 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
755 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
756 SilcChannelEntry channel;
757 SilcChannelID *channel_id;
760 SilcBufferStruct buf;
762 if (cmd->error != SILC_STATUS_OK) {
763 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
764 "Cannot invite: %s", silc_get_status_message(cmd->error));
765 COMMAND_REPLY_ERROR(cmd->error);
769 /* Take Channel ID */
770 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
774 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
778 /* Get the channel entry */
779 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
781 silc_free(channel_id);
782 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
786 /* Get the invite list */
787 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
789 silc_buffer_set(&buf, tmp, len);
791 /* Notify application */
792 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
795 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
796 silc_client_command_reply_free(cmd);
799 /* Received reply to the KILL command. */
801 SILC_CLIENT_CMD_REPLY_FUNC(kill)
803 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
804 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
805 SilcClientID *client_id;
806 SilcClientEntry client_entry = NULL;
808 unsigned char *id_data;
810 if (cmd->error != SILC_STATUS_OK) {
811 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
812 "Cannot kill: %s", silc_get_status_message(cmd->error));
813 COMMAND_REPLY_ERROR(cmd->error);
817 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
819 client_id = silc_id_payload_parse_id(id_data, len, NULL);
821 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
825 /* Get the client entry, if exists */
826 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
827 silc_free(client_id);
830 /* Notify application */
831 COMMAND_REPLY((SILC_ARGS, client_entry));
834 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
835 silc_client_command_reply_free(cmd);
838 /* Received reply to INFO command. We receive the server ID and some
839 information about the server user requested. */
841 SILC_CLIENT_CMD_REPLY_FUNC(info)
843 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
844 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
846 SilcServerEntry server;
847 SilcServerID *server_id = NULL;
848 char *server_name, *server_info;
851 SILC_LOG_DEBUG(("Start"));
853 if (cmd->error != SILC_STATUS_OK) {
854 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
855 silc_get_status_message(cmd->error));
856 COMMAND_REPLY_ERROR(cmd->error);
861 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
865 server_id = silc_id_payload_parse_id(tmp, len, NULL);
869 /* Get server name */
870 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
874 /* Get server info */
875 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
879 /* See whether we have this server cached. If not create it. */
880 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
882 SILC_LOG_DEBUG(("New server entry"));
883 server = silc_client_add_server(cmd->client, conn, server_name,
885 silc_id_dup(server_id, SILC_ID_SERVER));
890 /* Notify application */
891 COMMAND_REPLY((SILC_ARGS, server, server->server_name, server->server_info));
894 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
895 silc_free(server_id);
896 silc_client_command_reply_free(cmd);
899 /* Received reply to STATS command. */
901 SILC_CLIENT_CMD_REPLY_FUNC(stats)
903 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
904 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
905 unsigned char *tmp, *buf = NULL;
906 SilcUInt32 len, buf_len = 0;
908 if (cmd->error != SILC_STATUS_OK) {
909 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
910 "%s", silc_get_status_message(cmd->error));
911 COMMAND_REPLY_ERROR(cmd->error);
916 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
920 /* Get statistics structure */
921 buf = silc_argument_get_arg_type(cmd->args, 3, &buf_len);
923 /* Notify application */
924 COMMAND_REPLY((SILC_ARGS, buf, buf_len));
927 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
928 silc_client_command_reply_free(cmd);
931 /* Received reply to PING command. The reply time is shown to user. */
933 SILC_CLIENT_CMD_REPLY_FUNC(ping)
935 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
936 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
939 time_t diff, curtime;
941 if (cmd->error != SILC_STATUS_OK) {
942 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
943 "%s", silc_get_status_message(cmd->error));
944 COMMAND_REPLY_ERROR(cmd->error);
948 curtime = time(NULL);
949 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
950 cmd->packet->src_id_type);
951 if (!id || !conn->internal->ping) {
952 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
956 for (i = 0; i < conn->internal->ping_count; i++) {
957 if (!conn->internal->ping[i].dest_id)
959 if (SILC_ID_SERVER_COMPARE(conn->internal->ping[i].dest_id, id)) {
960 diff = curtime - conn->internal->ping[i].start_time;
961 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
962 "Ping reply from %s: %d second%s",
963 conn->internal->ping[i].dest_name, diff,
964 diff == 1 ? "" : "s");
966 conn->internal->ping[i].start_time = 0;
967 silc_free(conn->internal->ping[i].dest_id);
968 conn->internal->ping[i].dest_id = NULL;
969 silc_free(conn->internal->ping[i].dest_name);
970 conn->internal->ping[i].dest_name = NULL;
977 /* Notify application */
978 COMMAND_REPLY((SILC_ARGS));
981 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
982 silc_client_command_reply_free(cmd);
985 /* Received reply for JOIN command. */
987 SILC_CLIENT_CMD_REPLY_FUNC(join)
989 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
990 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
991 SilcChannelEntry channel;
993 SilcChannelID *channel_id;
994 SilcUInt32 argc, mode = 0, len, list_count;
995 char *topic, *tmp, *channel_name = NULL, *hmac;
996 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
997 SilcBufferStruct chpklist;
1000 SILC_LOG_DEBUG(("Start"));
1002 if (cmd->error != SILC_STATUS_OK) {
1003 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
1004 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1005 "Cannot join channel: %s", silc_get_status_message(cmd->error));
1006 COMMAND_REPLY_ERROR(cmd->error);
1010 argc = silc_argument_get_arg_num(cmd->args);
1012 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1013 "Cannot join channel: Bad reply packet");
1014 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1018 /* Get channel name */
1019 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1021 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1022 "Cannot join channel: Bad reply packet");
1023 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1028 /* Get Channel ID */
1029 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1031 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1032 "Cannot join channel: Bad reply packet");
1033 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1036 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1038 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1042 /* Get channel mode */
1043 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1045 SILC_GET32_MSB(mode, tmp);
1047 /* Get channel key */
1048 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1050 keyp = silc_buffer_alloc(len);
1051 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1052 silc_buffer_put(keyp, tmp, len);
1056 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1058 /* Check whether we have this channel entry already. */
1059 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1061 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
1062 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
1064 /* Create new channel entry */
1065 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1069 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_CHANNEL);
1073 conn->current_channel = channel;
1074 channel->mode = mode;
1077 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1079 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1080 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1081 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1082 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1087 /* Get the list count */
1088 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1091 SILC_GET32_MSB(list_count, tmp);
1093 /* Get Client ID list */
1094 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1098 client_id_list = silc_buffer_alloc(len);
1099 silc_buffer_pull_tail(client_id_list, len);
1100 silc_buffer_put(client_id_list, tmp, len);
1102 /* Get client mode list */
1103 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1107 client_mode_list = silc_buffer_alloc(len);
1108 silc_buffer_pull_tail(client_mode_list, len);
1109 silc_buffer_put(client_mode_list, tmp, len);
1111 /* Add clients we received in the reply to the channel */
1112 for (i = 0; i < list_count; i++) {
1115 SilcClientID *client_id;
1116 SilcClientEntry client_entry;
1119 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1121 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1126 SILC_GET32_MSB(mode, client_mode_list->data);
1128 /* Check if we have this client cached already. */
1129 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1130 if (!client_entry) {
1131 /* No, we don't have it, add entry for it. */
1133 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1134 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1139 /* Join client to the channel */
1140 if (!silc_client_on_channel(channel, client_entry)) {
1141 chu = silc_calloc(1, sizeof(*chu));
1142 chu->client = client_entry;
1143 chu->channel = channel;
1145 silc_hash_table_add(channel->user_list, client_entry, chu);
1146 silc_hash_table_add(client_entry->channels, channel, chu);
1149 silc_free(client_id);
1150 silc_buffer_pull(client_id_list, idp_len);
1151 silc_buffer_pull(client_mode_list, 4);
1153 silc_buffer_push(client_id_list, client_id_list->data -
1154 client_id_list->head);
1155 silc_buffer_push(client_mode_list, client_mode_list->data -
1156 client_mode_list->head);
1158 /* Save channel key */
1160 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1162 /* Get founder key */
1163 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
1165 if (channel->founder_key)
1166 silc_pkcs_public_key_free(channel->founder_key);
1167 channel->founder_key = NULL;
1168 silc_pkcs_public_key_payload_decode(tmp, len, &channel->founder_key);
1171 /* Get user limit */
1172 tmp = silc_argument_get_arg_type(cmd->args, 17, &len);
1173 if (tmp && len == 4)
1174 SILC_GET32_MSB(channel->user_limit, tmp);
1175 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1176 channel->user_limit = 0;
1178 /* Get channel public key list */
1179 tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
1181 silc_buffer_set(&chpklist, tmp, len);
1184 silc_free(channel->topic);
1185 channel->topic = silc_memdup(topic, strlen(topic));
1188 /* Notify application */
1189 COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0,
1190 keyp ? keyp->head : NULL, NULL,
1191 NULL, topic, hmac, list_count, client_id_list,
1192 client_mode_list, channel->founder_key,
1193 tmp ? &chpklist : NULL, channel->user_limit));
1196 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1197 silc_client_command_reply_free(cmd);
1198 silc_buffer_free(keyp);
1199 silc_buffer_free(client_id_list);
1200 silc_buffer_free(client_mode_list);
1203 /* Received reply for MOTD command */
1205 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1207 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1208 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1210 char *motd = NULL, *cp, line[256];
1212 if (cmd->error != SILC_STATUS_OK) {
1213 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1214 "%s", silc_get_status_message(cmd->error));
1215 COMMAND_REPLY_ERROR(cmd->error);
1219 argc = silc_argument_get_arg_num(cmd->args);
1221 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1226 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1228 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1235 if (cp[i++] == '\n') {
1236 memset(line, 0, sizeof(line));
1237 silc_strncat(line, sizeof(line), cp, i - 1);
1243 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1252 /* Notify application */
1253 COMMAND_REPLY((SILC_ARGS, motd));
1256 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1257 silc_client_command_reply_free(cmd);
1260 /* Received reply tot he UMODE command. Save the current user mode */
1262 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1264 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1265 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1269 if (cmd->error != SILC_STATUS_OK) {
1270 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1271 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1272 COMMAND_REPLY_ERROR(cmd->error);
1276 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1278 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1282 SILC_GET32_MSB(mode, tmp);
1283 conn->local_entry->mode = mode;
1285 /* Notify application */
1286 COMMAND_REPLY((SILC_ARGS, mode));
1289 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1290 silc_client_command_reply_free(cmd);
1293 /* Received reply for CMODE command. */
1295 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1297 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1298 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1301 SilcChannelID *channel_id;
1302 SilcChannelEntry channel;
1304 SilcPublicKey public_key = NULL;
1305 SilcBufferStruct channel_pubkeys;
1307 if (cmd->error != SILC_STATUS_OK) {
1308 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1309 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1310 COMMAND_REPLY_ERROR(cmd->error);
1314 /* Take Channel ID */
1315 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1318 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1322 /* Get the channel entry */
1323 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1325 silc_free(channel_id);
1326 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1330 /* Get channel mode */
1331 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1333 silc_free(channel_id);
1334 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1339 SILC_GET32_MSB(mode, tmp);
1340 channel->mode = mode;
1342 /* Get founder public key */
1343 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
1345 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1349 /* Get user limit */
1350 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
1351 if (tmp && len == 4)
1352 SILC_GET32_MSB(channel->user_limit, tmp);
1353 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1354 channel->user_limit = 0;
1356 /* Get channel public key(s) */
1357 tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
1359 silc_buffer_set(&channel_pubkeys, tmp, len);
1361 /* Notify application */
1362 COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
1363 tmp ? &channel_pubkeys : NULL, channel->user_limit));
1365 silc_free(channel_id);
1369 silc_pkcs_public_key_free(public_key);
1370 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1371 silc_client_command_reply_free(cmd);
1374 /* Received reply for CUMODE command */
1376 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1378 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1379 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1380 SilcClientID *client_id;
1381 SilcChannelID *channel_id;
1382 SilcClientEntry client_entry;
1383 SilcChannelEntry channel;
1384 SilcChannelUser chu;
1385 unsigned char *modev, *tmp, *id;
1386 SilcUInt32 len, mode;
1388 if (cmd->error != SILC_STATUS_OK) {
1389 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1390 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1391 COMMAND_REPLY_ERROR(cmd->error);
1395 /* Get channel mode */
1396 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1398 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1402 /* Take Channel ID */
1403 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1406 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1410 /* Get the channel entry */
1411 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1413 silc_free(channel_id);
1414 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1419 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1421 silc_free(channel_id);
1422 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1425 client_id = silc_id_payload_parse_id(id, len, NULL);
1427 silc_free(channel_id);
1428 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1432 /* Get client entry */
1433 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1434 if (!client_entry) {
1435 silc_free(channel_id);
1436 silc_free(client_id);
1437 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1442 SILC_GET32_MSB(mode, modev);
1443 chu = silc_client_on_channel(channel, client_entry);
1447 /* Notify application */
1448 COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry));
1449 silc_free(client_id);
1450 silc_free(channel_id);
1453 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1454 silc_client_command_reply_free(cmd);
1457 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1459 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1460 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1461 SilcClientID *client_id = NULL;
1462 SilcChannelID *channel_id = NULL;
1463 SilcClientEntry client_entry = NULL;
1464 SilcChannelEntry channel = NULL;
1468 if (cmd->error != SILC_STATUS_OK) {
1469 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1470 "Cannot kick: %s", silc_get_status_message(cmd->error));
1471 COMMAND_REPLY_ERROR(cmd->error);
1475 /* Take Channel ID */
1476 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1478 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1480 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1484 /* Get the channel entry */
1485 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1487 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1493 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1495 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1497 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1501 /* Get client entry */
1502 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1503 if (!client_entry) {
1504 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1509 /* Notify application */
1510 COMMAND_REPLY((SILC_ARGS, channel, client_entry));
1513 silc_free(channel_id);
1514 silc_free(client_id);
1515 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1516 silc_client_command_reply_free(cmd);
1519 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1521 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1522 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1524 if (cmd->error != SILC_STATUS_OK) {
1525 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1526 "%s", silc_get_status_message(cmd->error));
1527 COMMAND_REPLY_ERROR(cmd->error);
1531 /* Notify application */
1532 COMMAND_REPLY((SILC_ARGS));
1535 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1536 silc_client_command_reply_free(cmd);
1539 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1541 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1542 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1544 if (cmd->error != SILC_STATUS_OK) {
1545 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1546 "%s", silc_get_status_message(cmd->error));
1547 COMMAND_REPLY_ERROR(cmd->error);
1551 /* Notify application */
1552 COMMAND_REPLY((SILC_ARGS));
1555 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1556 silc_client_command_reply_free(cmd);
1559 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1561 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1562 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1565 if (cmd->error != SILC_STATUS_OK) {
1566 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1567 "%s", silc_get_status_message(cmd->error));
1568 COMMAND_REPLY_ERROR(cmd->error);
1572 /* Notify application */
1573 COMMAND_REPLY((SILC_ARGS));
1575 /* Generate the detachment data and deliver it to the client in the
1576 detach client operation */
1577 detach = silc_client_get_detach_data(cmd->client, conn);
1579 cmd->client->internal->ops->detach(cmd->client, conn,
1580 detach->data, detach->len);
1581 silc_buffer_free(detach);
1585 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1586 silc_client_command_reply_free(cmd);
1589 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1591 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1592 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1594 if (cmd->error != SILC_STATUS_OK) {
1595 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1596 "%s", silc_get_status_message(cmd->error));
1597 COMMAND_REPLY_ERROR(cmd->error);
1601 /* Notify application */
1602 COMMAND_REPLY((SILC_ARGS));
1605 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1606 silc_client_command_reply_free(cmd);
1609 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1611 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1612 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1613 SilcChannelEntry channel;
1614 SilcChannelID *channel_id;
1617 SilcBufferStruct buf;
1619 if (cmd->error != SILC_STATUS_OK) {
1620 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1621 "%s", silc_get_status_message(cmd->error));
1622 COMMAND_REPLY_ERROR(cmd->error);
1626 /* Take Channel ID */
1627 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1631 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1635 /* Get the channel entry */
1636 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1638 silc_free(channel_id);
1639 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1643 /* Get the ban list */
1644 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1646 silc_buffer_set(&buf, tmp, len);
1648 /* Notify application */
1649 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
1652 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1653 silc_client_command_reply_free(cmd);
1656 /* Reply to LEAVE command. */
1658 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1660 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1661 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1662 SilcChannelID *channel_id;
1663 SilcChannelEntry channel = NULL;
1664 SilcChannelUser chu;
1668 if (cmd->error != SILC_STATUS_OK) {
1669 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1670 "%s", silc_get_status_message(cmd->error));
1671 COMMAND_REPLY_ERROR(cmd->error);
1675 /* From protocol version 1.1 we get the channel ID of the left channel */
1676 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1678 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1682 /* Get the channel entry */
1683 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1685 silc_free(channel_id);
1686 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1690 /* Remove us from this channel. */
1691 chu = silc_client_on_channel(channel, conn->local_entry);
1693 silc_hash_table_del(chu->client->channels, chu->channel);
1694 silc_hash_table_del(chu->channel->user_list, chu->client);
1698 silc_free(channel_id);
1701 /* Notify application */
1702 COMMAND_REPLY((SILC_ARGS, channel));
1704 /* Now delete the channel. */
1706 silc_client_del_channel(cmd->client, conn, channel);
1709 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1710 silc_client_command_reply_free(cmd);
1713 /* Channel resolving callback for USERS command reply. */
1715 static void silc_client_command_reply_users_cb(SilcClient client,
1716 SilcClientConnection conn,
1717 SilcChannelEntry *channels,
1718 SilcUInt32 channels_count,
1721 if (!channels_count) {
1722 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1723 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1725 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1726 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1727 "%s", silc_get_status_message(cmd->error));
1728 COMMAND_REPLY_ERROR(cmd->error);
1729 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1730 silc_client_command_reply_free(cmd);
1734 silc_client_command_reply_users(context, NULL);
1738 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1742 SilcGetChannelCallback get_channel,
1743 SilcCommandCb get_clients)
1745 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1746 SilcChannelEntry channel;
1747 SilcClientEntry client_entry;
1748 SilcChannelUser chu;
1749 SilcChannelID *channel_id = NULL;
1750 SilcBufferStruct client_id_list, client_mode_list;
1752 SilcUInt32 tmp_len, list_count;
1754 unsigned char **res_argv = NULL;
1755 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1756 bool wait_res = FALSE;
1758 SILC_LOG_DEBUG(("Start"));
1760 /* Get channel ID */
1761 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1763 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1766 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1768 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1772 /* Get the list count */
1773 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1775 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1778 SILC_GET32_MSB(list_count, tmp);
1780 /* Get Client ID list */
1781 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1783 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1786 silc_buffer_set(&client_id_list, tmp, tmp_len);
1788 /* Get client mode list */
1789 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1791 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1794 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1796 /* Get channel entry */
1797 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1799 /* Resolve the channel from server */
1800 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1802 silc_free(channel_id);
1806 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1808 /* Cache the received Client ID's and modes. */
1809 for (i = 0; i < list_count; i++) {
1812 SilcClientID *client_id;
1815 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1817 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1822 SILC_GET32_MSB(mode, client_mode_list.data);
1824 /* Check if we have this client cached already. */
1825 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1826 if (!client_entry || !client_entry->username || !client_entry->realname) {
1828 /* No we don't have it (or it is incomplete in information), query
1829 it from the server. Assemble argument table that will be sent
1830 for the WHOIS command later. */
1831 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1833 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1835 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1837 res_argv[res_argc] = client_id_list.data;
1838 res_argv_lens[res_argc] = idp_len;
1839 res_argv_types[res_argc] = res_argc + 4;
1843 if (!silc_client_on_channel(channel, client_entry)) {
1844 chu = silc_calloc(1, sizeof(*chu));
1845 chu->client = client_entry;
1847 chu->channel = channel;
1848 silc_hash_table_add(channel->user_list, client_entry, chu);
1849 silc_hash_table_add(client_entry->channels, channel, chu);
1853 silc_free(client_id);
1854 silc_buffer_pull(&client_id_list, idp_len);
1855 silc_buffer_pull(&client_mode_list, 4);
1858 /* Query the client information from server if the list included clients
1859 that we don't know about. */
1863 /* Send the WHOIS command to server */
1864 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1865 silc_client_command_reply_whois_i, 0,
1867 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1868 res_argc, res_argv, res_argv_lens,
1869 res_argv_types, conn->cmd_ident);
1870 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1871 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1874 /* Register pending command callback. After we've received the WHOIS
1875 command reply we will reprocess this command reply by re-calling this
1876 USERS command reply callback. */
1877 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1880 silc_buffer_free(res_cmd);
1881 silc_free(channel_id);
1882 silc_free(res_argv);
1883 silc_free(res_argv_lens);
1884 silc_free(res_argv_types);
1891 silc_buffer_push(&client_id_list, (client_id_list.data -
1892 client_id_list.head));
1893 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1894 client_mode_list.head));
1896 /* Notify application */
1898 COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list,
1899 &client_mode_list));
1902 silc_free(channel_id);
1906 /* Reply to USERS command. Received list of client ID's and theirs modes
1907 on the channel we requested. */
1909 SILC_CLIENT_CMD_REPLY_FUNC(users)
1911 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1912 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1913 SilcClientCommandReplyContext r = (SilcClientCommandReplyContext)context2;
1915 SILC_LOG_DEBUG(("Start"));
1917 if (cmd->error != SILC_STATUS_OK) {
1918 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1919 "Query failed: %s", silc_get_status_message(cmd->error));
1920 COMMAND_REPLY_ERROR(cmd->error);
1924 if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) {
1925 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1926 /* Do not resolve anymore. Server may be sending us some non-existent
1927 Client ID (a bug in server), and we want to show the users list
1929 silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE,
1930 silc_client_command_reply_users_cb,
1931 silc_client_command_reply_users);
1934 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1935 "Query failed: %s", silc_get_status_message(cmd->error));
1936 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1941 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE,
1942 silc_client_command_reply_users_cb,
1943 silc_client_command_reply_users))
1947 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1948 silc_client_command_reply_free(cmd);
1951 /* Received command reply to GETKEY command. WE've received the remote
1952 client's public key. */
1954 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1956 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1957 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1958 SilcIDPayload idp = NULL;
1959 SilcClientID *client_id = NULL;
1960 SilcClientEntry client_entry;
1961 SilcServerID *server_id = NULL;
1962 SilcServerEntry server_entry;
1966 SilcPublicKey public_key = NULL;
1968 SILC_LOG_DEBUG(("Start"));
1970 if (cmd->error != SILC_STATUS_OK) {
1971 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1972 "%s", silc_get_status_message(cmd->error));
1973 COMMAND_REPLY_ERROR(cmd->error);
1977 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1979 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1982 idp = silc_id_payload_parse(tmp, len);
1984 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1988 /* Get the public key payload */
1989 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1991 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1996 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2000 id_type = silc_id_payload_get_type(idp);
2001 if (id_type == SILC_ID_CLIENT) {
2002 /* Received client's public key */
2003 client_id = silc_id_payload_get_id(idp);
2004 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
2005 if (!client_entry) {
2006 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2010 /* Save fingerprint */
2011 if (!client_entry->fingerprint) {
2012 client_entry->fingerprint = silc_calloc(20, sizeof(unsigned char));
2013 client_entry->fingerprint_len = 20;
2014 silc_hash_make(cmd->client->sha1hash, tmp + 4, len - 4,
2015 client_entry->fingerprint);
2017 if (!client_entry->public_key) {
2018 client_entry->public_key = public_key;
2022 /* Notify application */
2023 COMMAND_REPLY((SILC_ARGS, id_type, client_entry,
2024 client_entry->public_key));
2025 } else if (id_type == SILC_ID_SERVER) {
2026 /* Received server's public key */
2027 server_id = silc_id_payload_get_id(idp);
2028 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
2029 if (!server_entry) {
2030 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2034 /* Notify application */
2035 COMMAND_REPLY((SILC_ARGS, id_type, server_entry, public_key));
2039 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
2041 silc_id_payload_free(idp);
2043 silc_pkcs_public_key_free(public_key);
2044 silc_free(client_id);
2045 silc_free(server_id);
2046 silc_client_command_reply_free(cmd);
2049 SILC_CLIENT_CMD_REPLY_FUNC(quit)
2051 silc_client_command_reply_free(context);
2055 /******************************************************************************
2057 Internal command reply functions
2059 ******************************************************************************/
2061 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
2063 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2064 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2066 COMMAND_CHECK_STATUS_I;
2068 /* Save WHOIS info */
2069 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
2071 /* Pending callbacks are not executed if this was an list entry */
2072 if (cmd->status != SILC_STATUS_OK &&
2073 cmd->status != SILC_STATUS_LIST_END) {
2074 silc_client_command_reply_free(cmd);
2079 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
2082 /* If we received notify for invalid ID we'll remove the ID if we
2084 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2085 SilcClientEntry client_entry;
2087 unsigned char *tmp =
2088 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2091 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2093 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2096 silc_client_del_client(cmd->client, conn, client_entry);
2097 silc_free(client_id);
2102 /* Unregister this command reply */
2103 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2104 NULL, silc_client_command_reply_whois_i,
2107 silc_client_command_reply_free(cmd);
2110 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2112 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2113 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2115 COMMAND_CHECK_STATUS_I;
2117 /* Save IDENTIFY info */
2118 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
2120 /* Pending callbacks are not executed if this was an list entry */
2121 if (cmd->status != SILC_STATUS_OK &&
2122 cmd->status != SILC_STATUS_LIST_END) {
2123 silc_client_command_reply_free(cmd);
2128 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2131 /* If we received notify for invalid ID we'll remove the ID if we
2133 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2134 SilcClientEntry client_entry;
2136 unsigned char *tmp =
2137 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2140 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2142 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2145 silc_client_del_client(cmd->client, conn, client_entry);
2146 silc_free(client_id);
2151 /* Unregister this command reply */
2152 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2153 NULL, silc_client_command_reply_identify_i,
2156 silc_client_command_reply_free(cmd);
2159 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2161 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2162 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2164 SilcServerEntry server;
2165 SilcServerID *server_id = NULL;
2166 char *server_name, *server_info;
2169 COMMAND_CHECK_STATUS_I;
2172 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2176 server_id = silc_id_payload_parse_id(tmp, len, NULL);
2180 /* Get server name */
2181 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2185 /* Get server info */
2186 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2190 /* See whether we have this server cached. If not create it. */
2191 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
2193 SILC_LOG_DEBUG(("New server entry"));
2194 silc_client_add_server(cmd->client, conn, server_name, server_info,
2195 silc_id_dup(server_id, SILC_ID_SERVER));
2199 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2200 silc_free(server_id);
2202 silc_client_command_reply_free(cmd);
2205 static void silc_client_command_reply_users_i_cb(SilcClient client,
2206 SilcClientConnection conn,
2207 SilcChannelEntry *channels,
2208 SilcUInt32 channels_count,
2211 if (!channels_count) {
2212 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2213 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2215 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2216 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2217 "%s", silc_get_status_message(cmd->error));
2218 COMMAND_REPLY_ERROR(cmd->error);
2219 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2220 silc_client_command_reply_free(cmd);
2224 silc_client_command_reply_users_i(context, NULL);
2227 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2229 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2231 COMMAND_CHECK_STATUS_I;
2233 /* Save USERS info */
2234 if (silc_client_command_reply_users_save(
2235 cmd, cmd->status, FALSE, TRUE,
2236 silc_client_command_reply_users_i_cb,
2237 silc_client_command_reply_users_i))
2241 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2244 /* Unregister this command reply */
2245 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2246 NULL, silc_client_command_reply_users_i,
2249 silc_client_command_reply_free(cmd);
2252 /* Private range commands, specific to this implementation (and compatible
2253 with SILC Server >= 0.9). */
2255 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2257 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2258 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2260 if (cmd->error != SILC_STATUS_OK) {
2261 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2262 "%s", silc_get_status_message(cmd->error));
2263 COMMAND_REPLY_ERROR(cmd->error);
2267 /* Notify application */
2268 COMMAND_REPLY((SILC_ARGS));
2271 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2272 silc_client_command_reply_free(cmd);
2275 SILC_CLIENT_CMD_REPLY_FUNC(close)
2277 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2278 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2280 if (cmd->error != SILC_STATUS_OK) {
2281 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2282 "%s", silc_get_status_message(cmd->error));
2283 COMMAND_REPLY_ERROR(cmd->error);
2287 /* Notify application */
2288 COMMAND_REPLY((SILC_ARGS));
2291 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2292 silc_client_command_reply_free(cmd);
2295 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2297 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2298 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2300 if (cmd->error != SILC_STATUS_OK) {
2301 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2302 "%s", silc_get_status_message(cmd->error));
2303 COMMAND_REPLY_ERROR(cmd->error);
2307 /* Notify application */
2308 COMMAND_REPLY((SILC_ARGS));
2311 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2312 silc_client_command_reply_free(cmd);