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 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
641 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
643 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
647 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
649 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
653 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
654 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
656 SILC_GET32_MSB(usercount, tmp);
658 /* Check whether the channel exists, and add it to cache if it doesn't. */
659 channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
661 if (!channel_entry) {
662 /* Add new channel entry */
663 channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
665 if (!channel_entry) {
666 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
672 /* Notify application */
673 COMMAND_REPLY((SILC_ARGS, channel_entry, name, topic, usercount));
675 /* Pending callbacks are not executed if this was an list entry */
676 if (cmd->status != SILC_STATUS_OK &&
677 cmd->status != SILC_STATUS_LIST_END) {
678 silc_client_command_reply_free(cmd);
683 silc_free(channel_id);
684 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
686 silc_client_command_reply_free(cmd);
689 /* Received reply to topic command. */
691 SILC_CLIENT_CMD_REPLY_FUNC(topic)
693 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
694 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
695 SilcChannelEntry channel;
696 SilcChannelID *channel_id = NULL;
699 SilcUInt32 argc, len;
701 if (cmd->error != SILC_STATUS_OK) {
702 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
703 "Cannot set topic: %s", silc_get_status_message(cmd->error));
704 COMMAND_REPLY_ERROR(cmd->error);
708 argc = silc_argument_get_arg_num(cmd->args);
709 if (argc < 1 || argc > 3) {
710 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
714 /* Take Channel ID */
715 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
720 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
724 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
728 /* Get the channel entry */
729 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
731 silc_free(channel_id);
732 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
737 silc_free(channel->topic);
738 channel->topic = silc_memdup(topic, strlen(topic));
741 /* Notify application */
742 COMMAND_REPLY((SILC_ARGS, channel, topic));
745 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
746 silc_client_command_reply_free(cmd);
749 /* Received reply to invite command. */
751 SILC_CLIENT_CMD_REPLY_FUNC(invite)
753 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
754 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
755 SilcChannelEntry channel;
756 SilcChannelID *channel_id;
759 SilcBufferStruct buf;
761 if (cmd->error != SILC_STATUS_OK) {
762 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
763 "Cannot invite: %s", silc_get_status_message(cmd->error));
764 COMMAND_REPLY_ERROR(cmd->error);
768 /* Take Channel ID */
769 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
773 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
777 /* Get the channel entry */
778 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
780 silc_free(channel_id);
781 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
785 /* Get the invite list */
786 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
788 silc_buffer_set(&buf, tmp, len);
790 /* Notify application */
791 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
794 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
795 silc_client_command_reply_free(cmd);
798 /* Received reply to the KILL command. */
800 SILC_CLIENT_CMD_REPLY_FUNC(kill)
802 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
803 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
804 SilcClientID *client_id;
805 SilcClientEntry client_entry = NULL;
807 unsigned char *id_data;
809 if (cmd->error != SILC_STATUS_OK) {
810 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
811 "Cannot kill: %s", silc_get_status_message(cmd->error));
812 COMMAND_REPLY_ERROR(cmd->error);
816 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
818 client_id = silc_id_payload_parse_id(id_data, len, NULL);
820 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
824 /* Get the client entry, if exists */
825 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
826 silc_free(client_id);
829 /* Notify application */
830 COMMAND_REPLY((SILC_ARGS, client_entry));
833 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
834 silc_client_command_reply_free(cmd);
837 /* Received reply to INFO command. We receive the server ID and some
838 information about the server user requested. */
840 SILC_CLIENT_CMD_REPLY_FUNC(info)
842 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
843 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
845 SilcServerEntry server;
846 SilcServerID *server_id = NULL;
847 char *server_name, *server_info;
850 SILC_LOG_DEBUG(("Start"));
852 if (cmd->error != SILC_STATUS_OK) {
853 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
854 silc_get_status_message(cmd->error));
855 COMMAND_REPLY_ERROR(cmd->error);
860 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
864 server_id = silc_id_payload_parse_id(tmp, len, NULL);
868 /* Get server name */
869 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
873 /* Get server info */
874 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
878 /* See whether we have this server cached. If not create it. */
879 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
881 SILC_LOG_DEBUG(("New server entry"));
882 server = silc_client_add_server(cmd->client, conn, server_name,
884 silc_id_dup(server_id, SILC_ID_SERVER));
889 /* Notify application */
890 COMMAND_REPLY((SILC_ARGS, server, server->server_name, server->server_info));
893 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
894 silc_free(server_id);
895 silc_client_command_reply_free(cmd);
898 /* Received reply to STATS command. */
900 SILC_CLIENT_CMD_REPLY_FUNC(stats)
902 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
903 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
904 unsigned char *tmp, *buf = NULL;
905 SilcUInt32 len, buf_len = 0;
907 if (cmd->error != SILC_STATUS_OK) {
908 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
909 "%s", silc_get_status_message(cmd->error));
910 COMMAND_REPLY_ERROR(cmd->error);
915 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
919 /* Get statistics structure */
920 buf = silc_argument_get_arg_type(cmd->args, 3, &buf_len);
922 /* Notify application */
923 COMMAND_REPLY((SILC_ARGS, buf, buf_len));
926 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
927 silc_client_command_reply_free(cmd);
930 /* Received reply to PING command. The reply time is shown to user. */
932 SILC_CLIENT_CMD_REPLY_FUNC(ping)
934 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
935 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
938 time_t diff, curtime;
940 if (cmd->error != SILC_STATUS_OK) {
941 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
942 "%s", silc_get_status_message(cmd->error));
943 COMMAND_REPLY_ERROR(cmd->error);
947 curtime = time(NULL);
948 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
949 cmd->packet->src_id_type);
950 if (!id || !conn->internal->ping) {
951 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
955 for (i = 0; i < conn->internal->ping_count; i++) {
956 if (!conn->internal->ping[i].dest_id)
958 if (SILC_ID_SERVER_COMPARE(conn->internal->ping[i].dest_id, id)) {
959 diff = curtime - conn->internal->ping[i].start_time;
960 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
961 "Ping reply from %s: %d second%s",
962 conn->internal->ping[i].dest_name, diff,
963 diff == 1 ? "" : "s");
965 conn->internal->ping[i].start_time = 0;
966 silc_free(conn->internal->ping[i].dest_id);
967 conn->internal->ping[i].dest_id = NULL;
968 silc_free(conn->internal->ping[i].dest_name);
969 conn->internal->ping[i].dest_name = NULL;
976 /* Notify application */
977 COMMAND_REPLY((SILC_ARGS));
980 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
981 silc_client_command_reply_free(cmd);
984 /* Received reply for JOIN command. */
986 SILC_CLIENT_CMD_REPLY_FUNC(join)
988 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
989 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
990 SilcChannelEntry channel;
992 SilcChannelID *channel_id;
993 SilcUInt32 argc, mode = 0, len, list_count;
994 char *topic, *tmp, *channel_name = NULL, *hmac;
995 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
996 SilcBufferStruct chpklist;
999 SILC_LOG_DEBUG(("Start"));
1001 if (cmd->error != SILC_STATUS_OK) {
1002 if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
1003 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1004 "Cannot join channel: %s", silc_get_status_message(cmd->error));
1005 COMMAND_REPLY_ERROR(cmd->error);
1009 argc = silc_argument_get_arg_num(cmd->args);
1011 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1012 "Cannot join channel: Bad reply packet");
1013 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1017 /* Get channel name */
1018 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1020 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1021 "Cannot join channel: Bad reply packet");
1022 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1027 /* Get Channel ID */
1028 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1030 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1031 "Cannot join channel: Bad reply packet");
1032 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1035 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1037 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1041 /* Get channel mode */
1042 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1044 SILC_GET32_MSB(mode, tmp);
1046 /* Get channel key */
1047 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1049 keyp = silc_buffer_alloc(len);
1050 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1051 silc_buffer_put(keyp, tmp, len);
1055 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1057 /* Check whether we have this channel entry already. */
1058 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1060 if (!SILC_ID_CHANNEL_COMPARE(channel->id, channel_id))
1061 silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
1063 /* Create new channel entry */
1064 channel = silc_client_add_channel(cmd->client, conn, channel_name,
1068 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_BAD_CHANNEL);
1072 conn->current_channel = channel;
1073 channel->mode = mode;
1076 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1078 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1079 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1080 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1081 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1086 /* Get the list count */
1087 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1090 SILC_GET32_MSB(list_count, tmp);
1092 /* Get Client ID list */
1093 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1097 client_id_list = silc_buffer_alloc(len);
1098 silc_buffer_pull_tail(client_id_list, len);
1099 silc_buffer_put(client_id_list, tmp, len);
1101 /* Get client mode list */
1102 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1106 client_mode_list = silc_buffer_alloc(len);
1107 silc_buffer_pull_tail(client_mode_list, len);
1108 silc_buffer_put(client_mode_list, tmp, len);
1110 /* Add clients we received in the reply to the channel */
1111 for (i = 0; i < list_count; i++) {
1114 SilcClientID *client_id;
1115 SilcClientEntry client_entry;
1118 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1120 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len, NULL);
1125 SILC_GET32_MSB(mode, client_mode_list->data);
1127 /* Check if we have this client cached already. */
1128 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1129 if (!client_entry) {
1130 /* No, we don't have it, add entry for it. */
1132 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1133 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1138 /* Join client to the channel */
1139 if (!silc_client_on_channel(channel, client_entry)) {
1140 chu = silc_calloc(1, sizeof(*chu));
1141 chu->client = client_entry;
1142 chu->channel = channel;
1144 silc_hash_table_add(channel->user_list, client_entry, chu);
1145 silc_hash_table_add(client_entry->channels, channel, chu);
1148 silc_free(client_id);
1149 silc_buffer_pull(client_id_list, idp_len);
1150 silc_buffer_pull(client_mode_list, 4);
1152 silc_buffer_push(client_id_list, client_id_list->data -
1153 client_id_list->head);
1154 silc_buffer_push(client_mode_list, client_mode_list->data -
1155 client_mode_list->head);
1157 /* Save channel key */
1159 silc_client_save_channel_key(cmd->client, conn, keyp, channel);
1161 /* Get founder key */
1162 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
1164 if (channel->founder_key)
1165 silc_pkcs_public_key_free(channel->founder_key);
1166 channel->founder_key = NULL;
1167 silc_pkcs_public_key_payload_decode(tmp, len, &channel->founder_key);
1170 /* Get user limit */
1171 tmp = silc_argument_get_arg_type(cmd->args, 17, &len);
1172 if (tmp && len == 4)
1173 SILC_GET32_MSB(channel->user_limit, tmp);
1174 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1175 channel->user_limit = 0;
1177 /* Get channel public key list */
1178 tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
1180 silc_buffer_set(&chpklist, tmp, len);
1183 silc_free(channel->topic);
1184 channel->topic = silc_memdup(topic, strlen(topic));
1187 /* Notify application */
1188 COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0,
1189 keyp ? keyp->head : NULL, NULL,
1190 NULL, topic, hmac, list_count, client_id_list,
1191 client_mode_list, channel->founder_key,
1192 tmp ? &chpklist : NULL, channel->user_limit));
1195 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1196 silc_client_command_reply_free(cmd);
1197 silc_buffer_free(keyp);
1198 silc_buffer_free(client_id_list);
1199 silc_buffer_free(client_mode_list);
1202 /* Received reply for MOTD command */
1204 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1206 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1207 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1209 char *motd = NULL, *cp, line[256];
1211 if (cmd->error != SILC_STATUS_OK) {
1212 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1213 "%s", silc_get_status_message(cmd->error));
1214 COMMAND_REPLY_ERROR(cmd->error);
1218 argc = silc_argument_get_arg_num(cmd->args);
1220 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1225 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1227 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1234 if (cp[i++] == '\n') {
1235 memset(line, 0, sizeof(line));
1236 silc_strncat(line, sizeof(line), cp, i - 1);
1242 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1251 /* Notify application */
1252 COMMAND_REPLY((SILC_ARGS, motd));
1255 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1256 silc_client_command_reply_free(cmd);
1259 /* Received reply tot he UMODE command. Save the current user mode */
1261 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1263 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1264 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1268 if (cmd->error != SILC_STATUS_OK) {
1269 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1270 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1271 COMMAND_REPLY_ERROR(cmd->error);
1275 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1277 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1281 SILC_GET32_MSB(mode, tmp);
1282 conn->local_entry->mode = mode;
1284 /* Notify application */
1285 COMMAND_REPLY((SILC_ARGS, mode));
1288 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1289 silc_client_command_reply_free(cmd);
1292 /* Received reply for CMODE command. */
1294 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1296 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1297 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1300 SilcChannelID *channel_id;
1301 SilcChannelEntry channel;
1303 SilcPublicKey public_key = NULL;
1304 SilcBufferStruct channel_pubkeys;
1306 if (cmd->error != SILC_STATUS_OK) {
1307 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1308 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1309 COMMAND_REPLY_ERROR(cmd->error);
1313 /* Take Channel ID */
1314 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1317 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1321 /* Get the channel entry */
1322 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1324 silc_free(channel_id);
1325 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1329 /* Get channel mode */
1330 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1332 silc_free(channel_id);
1333 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1338 SILC_GET32_MSB(mode, tmp);
1339 channel->mode = mode;
1341 /* Get founder public key */
1342 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
1344 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1348 /* Get user limit */
1349 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
1350 if (tmp && len == 4)
1351 SILC_GET32_MSB(channel->user_limit, tmp);
1352 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
1353 channel->user_limit = 0;
1355 /* Get channel public key(s) */
1356 tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
1358 silc_buffer_set(&channel_pubkeys, tmp, len);
1360 /* Notify application */
1361 COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
1362 tmp ? &channel_pubkeys : NULL, channel->user_limit));
1364 silc_free(channel_id);
1368 silc_pkcs_public_key_free(public_key);
1369 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1370 silc_client_command_reply_free(cmd);
1373 /* Received reply for CUMODE command */
1375 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1377 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1378 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1379 SilcClientID *client_id;
1380 SilcChannelID *channel_id;
1381 SilcClientEntry client_entry;
1382 SilcChannelEntry channel;
1383 SilcChannelUser chu;
1384 unsigned char *modev, *tmp, *id;
1385 SilcUInt32 len, mode;
1387 if (cmd->error != SILC_STATUS_OK) {
1388 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1389 "Cannot change mode: %s", silc_get_status_message(cmd->error));
1390 COMMAND_REPLY_ERROR(cmd->error);
1394 /* Get channel mode */
1395 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1397 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1401 /* Take Channel ID */
1402 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1405 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1409 /* Get the channel entry */
1410 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1412 silc_free(channel_id);
1413 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1418 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1420 silc_free(channel_id);
1421 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1424 client_id = silc_id_payload_parse_id(id, len, NULL);
1426 silc_free(channel_id);
1427 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1431 /* Get client entry */
1432 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1433 if (!client_entry) {
1434 silc_free(channel_id);
1435 silc_free(client_id);
1436 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1441 SILC_GET32_MSB(mode, modev);
1442 chu = silc_client_on_channel(channel, client_entry);
1446 /* Notify application */
1447 COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry));
1448 silc_free(client_id);
1449 silc_free(channel_id);
1452 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1453 silc_client_command_reply_free(cmd);
1456 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1458 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1459 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1460 SilcClientID *client_id = NULL;
1461 SilcChannelID *channel_id = NULL;
1462 SilcClientEntry client_entry = NULL;
1463 SilcChannelEntry channel = NULL;
1467 if (cmd->error != SILC_STATUS_OK) {
1468 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1469 "Cannot kick: %s", silc_get_status_message(cmd->error));
1470 COMMAND_REPLY_ERROR(cmd->error);
1474 /* Take Channel ID */
1475 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1477 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1479 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1483 /* Get the channel entry */
1484 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1486 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1492 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1494 client_id = silc_id_payload_parse_id(tmp, len, NULL);
1496 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1500 /* Get client entry */
1501 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1502 if (!client_entry) {
1503 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1508 /* Notify application */
1509 COMMAND_REPLY((SILC_ARGS, channel, client_entry));
1512 silc_free(channel_id);
1513 silc_free(client_id);
1514 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1515 silc_client_command_reply_free(cmd);
1518 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1520 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1521 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1523 if (cmd->error != SILC_STATUS_OK) {
1524 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1525 "%s", silc_get_status_message(cmd->error));
1526 COMMAND_REPLY_ERROR(cmd->error);
1530 /* Notify application */
1531 COMMAND_REPLY((SILC_ARGS));
1534 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1535 silc_client_command_reply_free(cmd);
1538 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1540 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1541 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1543 if (cmd->error != SILC_STATUS_OK) {
1544 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1545 "%s", silc_get_status_message(cmd->error));
1546 COMMAND_REPLY_ERROR(cmd->error);
1550 /* Notify application */
1551 COMMAND_REPLY((SILC_ARGS));
1554 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1555 silc_client_command_reply_free(cmd);
1558 SILC_CLIENT_CMD_REPLY_FUNC(detach)
1560 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1561 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1564 if (cmd->error != SILC_STATUS_OK) {
1565 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1566 "%s", silc_get_status_message(cmd->error));
1567 COMMAND_REPLY_ERROR(cmd->error);
1571 /* Notify application */
1572 COMMAND_REPLY((SILC_ARGS));
1574 /* Generate the detachment data and deliver it to the client in the
1575 detach client operation */
1576 detach = silc_client_get_detach_data(cmd->client, conn);
1578 cmd->client->internal->ops->detach(cmd->client, conn,
1579 detach->data, detach->len);
1580 silc_buffer_free(detach);
1584 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_DETACH);
1585 silc_client_command_reply_free(cmd);
1588 SILC_CLIENT_CMD_REPLY_FUNC(watch)
1590 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1591 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1593 if (cmd->error != SILC_STATUS_OK) {
1594 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1595 "%s", silc_get_status_message(cmd->error));
1596 COMMAND_REPLY_ERROR(cmd->error);
1600 /* Notify application */
1601 COMMAND_REPLY((SILC_ARGS));
1604 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1605 silc_client_command_reply_free(cmd);
1608 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1610 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1611 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1612 SilcChannelEntry channel;
1613 SilcChannelID *channel_id;
1616 SilcBufferStruct buf;
1618 if (cmd->error != SILC_STATUS_OK) {
1619 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1620 "%s", silc_get_status_message(cmd->error));
1621 COMMAND_REPLY_ERROR(cmd->error);
1625 /* Take Channel ID */
1626 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1630 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1634 /* Get the channel entry */
1635 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1637 silc_free(channel_id);
1638 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1642 /* Get the ban list */
1643 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1645 silc_buffer_set(&buf, tmp, len);
1647 /* Notify application */
1648 COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
1651 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1652 silc_client_command_reply_free(cmd);
1655 /* Reply to LEAVE command. */
1657 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1659 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1660 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1661 SilcChannelID *channel_id;
1662 SilcChannelEntry channel = NULL;
1663 SilcChannelUser chu;
1667 if (cmd->error != SILC_STATUS_OK) {
1668 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1669 "%s", silc_get_status_message(cmd->error));
1670 COMMAND_REPLY_ERROR(cmd->error);
1674 /* From protocol version 1.1 we get the channel ID of the left channel */
1675 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1677 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1681 /* Get the channel entry */
1682 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1684 silc_free(channel_id);
1685 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1689 /* Remove us from this channel. */
1690 chu = silc_client_on_channel(channel, conn->local_entry);
1692 silc_hash_table_del(chu->client->channels, chu->channel);
1693 silc_hash_table_del(chu->channel->user_list, chu->client);
1697 silc_free(channel_id);
1700 /* Notify application */
1701 COMMAND_REPLY((SILC_ARGS, channel));
1703 /* Now delete the channel. */
1705 silc_client_del_channel(cmd->client, conn, channel);
1708 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1709 silc_client_command_reply_free(cmd);
1712 /* Channel resolving callback for USERS command reply. */
1714 static void silc_client_command_reply_users_cb(SilcClient client,
1715 SilcClientConnection conn,
1716 SilcChannelEntry *channels,
1717 SilcUInt32 channels_count,
1720 if (!channels_count) {
1721 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1722 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1724 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
1725 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1726 "%s", silc_get_status_message(cmd->error));
1727 COMMAND_REPLY_ERROR(cmd->error);
1728 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1729 silc_client_command_reply_free(cmd);
1733 silc_client_command_reply_users(context, NULL);
1737 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
1741 SilcGetChannelCallback get_channel,
1742 SilcCommandCb get_clients)
1744 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1745 SilcChannelEntry channel;
1746 SilcClientEntry client_entry;
1747 SilcChannelUser chu;
1748 SilcChannelID *channel_id = NULL;
1749 SilcBufferStruct client_id_list, client_mode_list;
1751 SilcUInt32 tmp_len, list_count;
1753 unsigned char **res_argv = NULL;
1754 SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1755 bool wait_res = FALSE;
1757 SILC_LOG_DEBUG(("Start"));
1759 /* Get channel ID */
1760 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1762 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1765 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1767 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1771 /* Get the list count */
1772 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1774 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1777 SILC_GET32_MSB(list_count, tmp);
1779 /* Get Client ID list */
1780 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1782 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1785 silc_buffer_set(&client_id_list, tmp, tmp_len);
1787 /* Get client mode list */
1788 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1790 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1793 silc_buffer_set(&client_mode_list, tmp, tmp_len);
1795 /* Get channel entry */
1796 channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
1798 /* Resolve the channel from server */
1799 silc_client_get_channel_by_id_resolve(cmd->client, conn, channel_id,
1801 silc_free(channel_id);
1805 SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count));
1807 /* Cache the received Client ID's and modes. */
1808 for (i = 0; i < list_count; i++) {
1811 SilcClientID *client_id;
1814 SILC_GET16_MSB(idp_len, client_id_list.data + 2);
1816 client_id = silc_id_payload_parse_id(client_id_list.data, idp_len, NULL);
1821 SILC_GET32_MSB(mode, client_mode_list.data);
1823 /* Check if we have this client cached already. */
1824 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
1825 if (!client_entry || !client_entry->username || !client_entry->realname) {
1827 /* No we don't have it (or it is incomplete in information), query
1828 it from the server. Assemble argument table that will be sent
1829 for the WHOIS command later. */
1830 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1832 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1834 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1836 res_argv[res_argc] = client_id_list.data;
1837 res_argv_lens[res_argc] = idp_len;
1838 res_argv_types[res_argc] = res_argc + 4;
1842 if (!silc_client_on_channel(channel, client_entry)) {
1843 chu = silc_calloc(1, sizeof(*chu));
1844 chu->client = client_entry;
1846 chu->channel = channel;
1847 silc_hash_table_add(channel->user_list, client_entry, chu);
1848 silc_hash_table_add(client_entry->channels, channel, chu);
1852 silc_free(client_id);
1853 silc_buffer_pull(&client_id_list, idp_len);
1854 silc_buffer_pull(&client_mode_list, 4);
1857 /* Query the client information from server if the list included clients
1858 that we don't know about. */
1862 /* Send the WHOIS command to server */
1863 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1864 silc_client_command_reply_whois_i, 0,
1866 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1867 res_argc, res_argv, res_argv_lens,
1868 res_argv_types, conn->cmd_ident);
1869 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1870 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1873 /* Register pending command callback. After we've received the WHOIS
1874 command reply we will reprocess this command reply by re-calling this
1875 USERS command reply callback. */
1876 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1879 silc_buffer_free(res_cmd);
1880 silc_free(channel_id);
1881 silc_free(res_argv);
1882 silc_free(res_argv_lens);
1883 silc_free(res_argv_types);
1890 silc_buffer_push(&client_id_list, (client_id_list.data -
1891 client_id_list.head));
1892 silc_buffer_push(&client_mode_list, (client_mode_list.data -
1893 client_mode_list.head));
1895 /* Notify application */
1897 COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list,
1898 &client_mode_list));
1901 silc_free(channel_id);
1905 /* Reply to USERS command. Received list of client ID's and theirs modes
1906 on the channel we requested. */
1908 SILC_CLIENT_CMD_REPLY_FUNC(users)
1910 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1911 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1912 SilcClientCommandReplyContext r = (SilcClientCommandReplyContext)context2;
1914 SILC_LOG_DEBUG(("Start"));
1916 if (cmd->error != SILC_STATUS_OK) {
1917 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1918 "Query failed: %s", silc_get_status_message(cmd->error));
1919 COMMAND_REPLY_ERROR(cmd->error);
1923 if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) {
1924 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1925 /* Do not resolve anymore. Server may be sending us some non-existent
1926 Client ID (a bug in server), and we want to show the users list
1928 silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE,
1929 silc_client_command_reply_users_cb,
1930 silc_client_command_reply_users);
1933 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1934 "Query failed: %s", silc_get_status_message(cmd->error));
1935 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1940 if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE,
1941 silc_client_command_reply_users_cb,
1942 silc_client_command_reply_users))
1946 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1947 silc_client_command_reply_free(cmd);
1950 /* Received command reply to GETKEY command. WE've received the remote
1951 client's public key. */
1953 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1955 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1956 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1957 SilcIDPayload idp = NULL;
1958 SilcClientID *client_id = NULL;
1959 SilcClientEntry client_entry;
1960 SilcServerID *server_id = NULL;
1961 SilcServerEntry server_entry;
1965 SilcPublicKey public_key = NULL;
1967 SILC_LOG_DEBUG(("Start"));
1969 if (cmd->error != SILC_STATUS_OK) {
1970 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1971 "%s", silc_get_status_message(cmd->error));
1972 COMMAND_REPLY_ERROR(cmd->error);
1976 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1978 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1981 idp = silc_id_payload_parse(tmp, len);
1983 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1987 /* Get the public key payload */
1988 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1990 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1995 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1999 id_type = silc_id_payload_get_type(idp);
2000 if (id_type == SILC_ID_CLIENT) {
2001 /* Received client's public key */
2002 client_id = silc_id_payload_get_id(idp);
2003 client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
2004 if (!client_entry) {
2005 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2009 /* Save fingerprint */
2010 if (!client_entry->fingerprint) {
2011 client_entry->fingerprint = silc_calloc(20, sizeof(unsigned char));
2012 client_entry->fingerprint_len = 20;
2013 silc_hash_make(cmd->client->sha1hash, tmp + 4, len - 4,
2014 client_entry->fingerprint);
2016 if (!client_entry->public_key) {
2017 client_entry->public_key = public_key;
2021 /* Notify application */
2022 COMMAND_REPLY((SILC_ARGS, id_type, client_entry,
2023 client_entry->public_key));
2024 } else if (id_type == SILC_ID_SERVER) {
2025 /* Received server's public key */
2026 server_id = silc_id_payload_get_id(idp);
2027 server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
2028 if (!server_entry) {
2029 COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
2033 /* Notify application */
2034 COMMAND_REPLY((SILC_ARGS, id_type, server_entry, public_key));
2038 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
2040 silc_id_payload_free(idp);
2042 silc_pkcs_public_key_free(public_key);
2043 silc_free(client_id);
2044 silc_free(server_id);
2045 silc_client_command_reply_free(cmd);
2048 SILC_CLIENT_CMD_REPLY_FUNC(quit)
2050 silc_client_command_reply_free(context);
2054 /******************************************************************************
2056 Internal command reply functions
2058 ******************************************************************************/
2060 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
2062 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2063 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2065 COMMAND_CHECK_STATUS_I;
2067 /* Save WHOIS info */
2068 silc_client_command_reply_whois_save(cmd, cmd->status, FALSE);
2070 /* Pending callbacks are not executed if this was an list entry */
2071 if (cmd->status != SILC_STATUS_OK &&
2072 cmd->status != SILC_STATUS_LIST_END) {
2073 silc_client_command_reply_free(cmd);
2078 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
2081 /* If we received notify for invalid ID we'll remove the ID if we
2083 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2084 SilcClientEntry client_entry;
2086 unsigned char *tmp =
2087 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2090 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2092 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2095 silc_client_del_client(cmd->client, conn, client_entry);
2096 silc_free(client_id);
2101 /* Unregister this command reply */
2102 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2103 NULL, silc_client_command_reply_whois_i,
2106 silc_client_command_reply_free(cmd);
2109 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2111 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2112 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2114 COMMAND_CHECK_STATUS_I;
2116 /* Save IDENTIFY info */
2117 silc_client_command_reply_identify_save(cmd, cmd->status, FALSE);
2119 /* Pending callbacks are not executed if this was an list entry */
2120 if (cmd->status != SILC_STATUS_OK &&
2121 cmd->status != SILC_STATUS_LIST_END) {
2122 silc_client_command_reply_free(cmd);
2127 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2130 /* If we received notify for invalid ID we'll remove the ID if we
2132 if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2133 SilcClientEntry client_entry;
2135 unsigned char *tmp =
2136 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2139 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
2141 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2144 silc_client_del_client(cmd->client, conn, client_entry);
2145 silc_free(client_id);
2150 /* Unregister this command reply */
2151 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2152 NULL, silc_client_command_reply_identify_i,
2155 silc_client_command_reply_free(cmd);
2158 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2160 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2161 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2163 SilcServerEntry server;
2164 SilcServerID *server_id = NULL;
2165 char *server_name, *server_info;
2168 COMMAND_CHECK_STATUS_I;
2171 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2175 server_id = silc_id_payload_parse_id(tmp, len, NULL);
2179 /* Get server name */
2180 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2184 /* Get server info */
2185 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2189 /* See whether we have this server cached. If not create it. */
2190 server = silc_client_get_server_by_id(cmd->client, conn, server_id);
2192 SILC_LOG_DEBUG(("New server entry"));
2193 silc_client_add_server(cmd->client, conn, server_name, server_info,
2194 silc_id_dup(server_id, SILC_ID_SERVER));
2198 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2199 silc_free(server_id);
2201 silc_client_command_reply_free(cmd);
2204 static void silc_client_command_reply_users_i_cb(SilcClient client,
2205 SilcClientConnection conn,
2206 SilcChannelEntry *channels,
2207 SilcUInt32 channels_count,
2210 if (!channels_count) {
2211 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2212 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2214 cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
2215 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2216 "%s", silc_get_status_message(cmd->error));
2217 COMMAND_REPLY_ERROR(cmd->error);
2218 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2219 silc_client_command_reply_free(cmd);
2223 silc_client_command_reply_users_i(context, NULL);
2226 SILC_CLIENT_CMD_REPLY_FUNC(users_i)
2228 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2230 COMMAND_CHECK_STATUS_I;
2232 /* Save USERS info */
2233 if (silc_client_command_reply_users_save(
2234 cmd, cmd->status, FALSE, TRUE,
2235 silc_client_command_reply_users_i_cb,
2236 silc_client_command_reply_users_i))
2240 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
2243 /* Unregister this command reply */
2244 silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS,
2245 NULL, silc_client_command_reply_users_i,
2248 silc_client_command_reply_free(cmd);
2251 /* Private range commands, specific to this implementation (and compatible
2252 with SILC Server >= 0.9). */
2254 SILC_CLIENT_CMD_REPLY_FUNC(connect)
2256 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2257 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2259 if (cmd->error != SILC_STATUS_OK) {
2260 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2261 "%s", silc_get_status_message(cmd->error));
2262 COMMAND_REPLY_ERROR(cmd->error);
2266 /* Notify application */
2267 COMMAND_REPLY((SILC_ARGS));
2270 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
2271 silc_client_command_reply_free(cmd);
2274 SILC_CLIENT_CMD_REPLY_FUNC(close)
2276 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2277 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2279 if (cmd->error != SILC_STATUS_OK) {
2280 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2281 "%s", silc_get_status_message(cmd->error));
2282 COMMAND_REPLY_ERROR(cmd->error);
2286 /* Notify application */
2287 COMMAND_REPLY((SILC_ARGS));
2290 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
2291 silc_client_command_reply_free(cmd);
2294 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
2296 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2297 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2299 if (cmd->error != SILC_STATUS_OK) {
2300 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
2301 "%s", silc_get_status_message(cmd->error));
2302 COMMAND_REPLY_ERROR(cmd->error);
2306 /* Notify application */
2307 COMMAND_REPLY((SILC_ARGS));
2310 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
2311 silc_client_command_reply_free(cmd);