5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 * Command reply functions are "the otherside" of the command functions.
22 * Reply to a command sent by server is handled by these functions.
24 * The arguments received from server are also passed to the calling
25 * application through command_reply client operation. The arguments are
26 * exactly same and in same order as the server sent it. However, ID's are
27 * not sent to the application. Instead, corresponding ID entry is sent
28 * to the application. For example, instead of sending Client ID the
29 * corresponding SilcClientEntry is sent to the application. The case is
30 * same with for example Channel ID's. This way application has all the
31 * necessary data already in hand without redundant searching. If ID is
32 * received but ID entry does not exist, NULL is sent.
35 #include "clientlibincludes.h"
36 #include "client_internal.h"
38 const SilcCommandStatusMessage silc_command_status_messages[] = {
40 { STAT(NO_SUCH_NICK), "There was no such nickname" },
41 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
42 { STAT(NO_SUCH_SERVER), "No such server" },
43 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
44 { STAT(NO_RECIPIENT), "No recipient given" },
45 { STAT(UNKNOWN_COMMAND), "Unknown command" },
46 { STAT(WILDCARDS), "Unknown command" },
47 { STAT(NO_CLIENT_ID), "No Client ID given" },
48 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
49 { STAT(NO_SERVER_ID), "No Server ID given" },
50 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
51 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
52 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
53 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
54 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
55 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
56 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
57 { STAT(USER_ON_CHANNEL), "User already on the channel" },
58 { STAT(NOT_REGISTERED), "You have not registered" },
59 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
60 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
61 { STAT(PERM_DENIED), "Permission denied" },
62 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
63 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
64 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
65 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
66 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
67 { STAT(UNKNOWN_MODE), "Unknown mode" },
68 { STAT(NOT_YOU), "Cannot change mode for other users" },
69 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
70 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
71 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
72 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
73 { STAT(BAD_NICKNAME), "Bad nickname" },
74 { STAT(BAD_CHANNEL), "Bad channel name" },
75 { STAT(AUTH_FAILED), "Authentication failed" },
76 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
77 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
81 /* Command reply operation that is called at the end of all command replys.
82 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
83 #define COMMAND_REPLY(args) cmd->client->internal->ops->command_reply args
84 #define ARGS cmd->client, cmd->sock->user_data, \
85 cmd->payload, TRUE, silc_command_get(cmd->payload), status
87 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
88 #define COMMAND_REPLY_ERROR cmd->client->internal->ops-> \
89 command_reply(cmd->client, cmd->sock->user_data, cmd->payload, \
90 FALSE, silc_command_get(cmd->payload), status)
92 #define SAY cmd->client->internal->ops->say
94 /* All functions that call the COMMAND_CHECK_STATUS or the
95 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
97 #define COMMAND_CHECK_STATUS \
99 SILC_LOG_DEBUG(("Start")); \
100 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
101 if (status != SILC_STATUS_OK) { \
102 COMMAND_REPLY_ERROR; \
107 #define COMMAND_CHECK_STATUS_LIST \
109 SILC_LOG_DEBUG(("Start")); \
110 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
111 if (status != SILC_STATUS_OK && \
112 status != SILC_STATUS_LIST_START && \
113 status != SILC_STATUS_LIST_ITEM && \
114 status != SILC_STATUS_LIST_END) { \
115 COMMAND_REPLY_ERROR; \
120 /* Process received command reply. */
122 void silc_client_command_reply_process(SilcClient client,
123 SilcSocketConnection sock,
124 SilcPacketContext *packet)
126 SilcBuffer buffer = packet->buffer;
127 SilcClientCommand cmd;
128 SilcClientCommandReplyContext ctx;
129 SilcCommandPayload payload;
131 SilcCommandCb reply = NULL;
133 /* Get command reply payload from packet */
134 payload = silc_command_payload_parse(buffer->data, buffer->len);
136 /* Silently ignore bad reply packet */
137 SILC_LOG_DEBUG(("Bad command reply packet"));
141 /* Allocate command reply context. This must be free'd by the
142 command reply routine receiving it. */
143 ctx = silc_calloc(1, sizeof(*ctx));
144 ctx->client = client;
146 ctx->payload = payload;
147 ctx->args = silc_command_get_args(ctx->payload);
148 ctx->packet = packet;
149 ctx->ident = silc_command_get_ident(ctx->payload);
151 /* Check for pending commands and mark to be exeucted */
152 silc_client_command_pending_check(sock->user_data, ctx,
153 silc_command_get(ctx->payload),
156 /* Execute command reply */
158 command = silc_command_get(ctx->payload);
160 /* Try to find matching the command identifier */
161 silc_list_start(client->internal->commands);
162 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
163 if (cmd->cmd == command && !cmd->ident)
165 if (cmd->cmd == command && cmd->ident == ctx->ident) {
166 (*cmd->reply)((void *)ctx, NULL);
171 if (cmd == SILC_LIST_END) {
173 /* No specific identifier for command reply, call first one found */
180 /* Returns status message string */
182 char *silc_client_command_status_message(SilcCommandStatus status)
186 for (i = 0; silc_command_status_messages[i].message; i++) {
187 if (silc_command_status_messages[i].status == status)
191 if (silc_command_status_messages[i].message == NULL)
194 return silc_command_status_messages[i].message;
197 /* Free command reply context and its internals. */
199 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
202 silc_command_payload_free(cmd->payload);
208 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
209 SilcCommandStatus status,
212 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
213 SilcClientID *client_id;
214 SilcIDCacheEntry id_cache = NULL;
215 SilcClientEntry client_entry = NULL;
218 unsigned char *id_data, *tmp;
219 char *nickname = NULL, *username = NULL;
220 char *realname = NULL;
221 uint32 idle = 0, mode = 0;
222 SilcBuffer channels = NULL;
223 unsigned char *fingerprint;
224 uint32 fingerprint_len;
226 argc = silc_argument_get_arg_num(cmd->args);
228 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
235 client_id = silc_id_payload_parse_id(id_data, len);
242 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
243 username = silc_argument_get_arg_type(cmd->args, 4, &len);
244 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
245 if (!nickname || !username || !realname) {
251 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
253 channels = silc_buffer_alloc(len);
254 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
255 silc_buffer_put(channels, tmp, len);
258 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
260 SILC_GET32_MSB(mode, tmp);
262 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
264 SILC_GET32_MSB(idle, tmp);
266 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
268 /* Check if we have this client cached already. */
269 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
271 silc_hash_client_id_compare, NULL,
273 SILC_LOG_DEBUG(("Adding new client entry"));
275 silc_client_add_client(cmd->client, conn, nickname, username, realname,
278 client_entry = (SilcClientEntry)id_cache->context;
279 silc_client_update_client(cmd->client, conn, client_entry,
280 nickname, username, realname, mode);
281 silc_free(client_id);
284 if (fingerprint && !client_entry->fingerprint) {
285 client_entry->fingerprint =
286 silc_calloc(fingerprint_len,
287 sizeof(*client_entry->fingerprint));
288 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
289 client_entry->fingerprint_len = fingerprint_len;
292 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
293 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
295 /* Notify application */
296 if (!cmd->callback && notify)
297 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
298 channels, mode, idle, fingerprint));
301 silc_buffer_free(channels);
304 /* Received reply for WHOIS command. This maybe called several times
305 for one WHOIS command as server may reply with list of results. */
307 SILC_CLIENT_CMD_REPLY_FUNC(whois)
309 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
310 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
311 SilcCommandStatus status;
313 COMMAND_CHECK_STATUS_LIST;
315 /* Save WHOIS info */
316 silc_client_command_reply_whois_save(cmd, status, TRUE);
318 /* Pending callbacks are not executed if this was an list entry */
319 if (status != SILC_STATUS_OK &&
320 status != SILC_STATUS_LIST_END) {
321 silc_client_command_reply_free(cmd);
326 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
327 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
329 /* If we received notify for invalid ID we'll remove the ID if we
331 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
332 SilcClientEntry client_entry;
335 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
338 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
340 client_entry = silc_client_get_client_by_id(cmd->client, conn,
343 silc_client_del_client(cmd->client, conn, client_entry);
344 silc_free(client_id);
349 silc_client_command_reply_free(cmd);
352 /* Received reply for WHOWAS command. */
354 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
356 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
357 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
358 SilcCommandStatus status;
359 SilcClientID *client_id;
360 SilcIDCacheEntry id_cache = NULL;
361 SilcClientEntry client_entry = NULL;
363 unsigned char *id_data;
364 char *nickname, *username;
365 char *realname = NULL;
367 COMMAND_CHECK_STATUS_LIST;
369 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
375 client_id = silc_id_payload_parse_id(id_data, len);
381 /* Get the client entry, if exists */
382 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
384 silc_hash_client_id_compare, NULL,
386 client_entry = (SilcClientEntry)id_cache->context;
387 silc_free(client_id);
389 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
390 username = silc_argument_get_arg_type(cmd->args, 4, &len);
391 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
392 if (!nickname || !username) {
397 /* Notify application. We don't save any history information to any
398 cache. Just pass the data to the application for displaying on
400 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
402 /* Pending callbacks are not executed if this was an list entry */
403 if (status != SILC_STATUS_OK &&
404 status != SILC_STATUS_LIST_END) {
405 silc_client_command_reply_free(cmd);
410 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
411 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS);
412 silc_client_command_reply_free(cmd);
416 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
417 SilcCommandStatus status,
420 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
421 SilcClient client = cmd->client;
422 SilcClientID *client_id = NULL;
423 SilcServerID *server_id = NULL;
424 SilcChannelID *channel_id = NULL;
425 SilcIDCacheEntry id_cache = NULL;
426 SilcClientEntry client_entry;
427 SilcServerEntry server_entry;
428 SilcChannelEntry channel_entry;
431 unsigned char *id_data;
432 char *name = NULL, *info = NULL;
433 SilcIDPayload idp = NULL;
436 argc = silc_argument_get_arg_num(cmd->args);
438 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
444 idp = silc_id_payload_parse(id_data, len);
451 name = silc_argument_get_arg_type(cmd->args, 3, &len);
452 info = silc_argument_get_arg_type(cmd->args, 4, &len);
454 id_type = silc_id_payload_get_type(idp);
458 client_id = silc_id_payload_get_id(idp);
460 SILC_LOG_DEBUG(("Received client information"));
462 /* Check if we have this client cached already. */
463 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
466 silc_hash_client_id_compare, NULL,
468 SILC_LOG_DEBUG(("Adding new client entry"));
470 silc_client_add_client(cmd->client, conn, name, info, NULL,
471 silc_id_dup(client_id, id_type), 0);
473 client_entry = (SilcClientEntry)id_cache->context;
474 silc_client_update_client(cmd->client, conn, client_entry,
475 name, info, NULL, 0);
478 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
479 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
481 /* Notify application */
483 COMMAND_REPLY((ARGS, client_entry, name, info));
487 server_id = silc_id_payload_get_id(idp);
489 SILC_LOG_DEBUG(("Received server information"));
491 /* Check if we have this server cached already. */
492 if (!silc_idcache_find_by_id_one(conn->server_cache,
493 (void *)server_id, &id_cache)) {
494 SILC_LOG_DEBUG(("Adding new server entry"));
496 server_entry = silc_calloc(1, sizeof(*server_entry));
497 server_entry->server_id = silc_id_dup(server_id, id_type);
499 server_entry->server_name = strdup(name);
501 server_entry->server_info = strdup(info);
503 /* Add server to cache */
504 silc_idcache_add(conn->server_cache, server_entry->server_name,
505 server_entry->server_id, (void *)server_entry,
508 server_entry = (SilcServerEntry)id_cache->context;
511 /* Notify application */
513 COMMAND_REPLY((ARGS, server_entry, name, info));
516 case SILC_ID_CHANNEL:
517 channel_id = silc_id_payload_get_id(idp);
519 SILC_LOG_DEBUG(("Received channel information"));
521 /* Check if we have this channel cached already. */
522 if (!silc_idcache_find_by_id_one(conn->channel_cache,
523 (void *)channel_id, &id_cache)) {
527 SILC_LOG_DEBUG(("Adding new channel entry"));
528 channel_entry = silc_client_new_channel_id(client, conn->sock,
529 strdup(name), 0, idp);
531 channel_entry = (SilcChannelEntry)id_cache->context;
534 /* Notify application */
536 COMMAND_REPLY((ARGS, channel_entry, name, info));
540 silc_id_payload_free(idp);
541 silc_free(client_id);
542 silc_free(server_id);
543 silc_free(channel_id);
546 /* Received reply for IDENTIFY command. This maybe called several times
547 for one IDENTIFY command as server may reply with list of results.
548 This is totally silent and does not print anything on screen. */
550 SILC_CLIENT_CMD_REPLY_FUNC(identify)
552 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
553 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
554 SilcCommandStatus status;
556 COMMAND_CHECK_STATUS_LIST;
558 /* Save IDENTIFY info */
559 silc_client_command_reply_identify_save(cmd, status, TRUE);
561 /* Pending callbacks are not executed if this was an list entry */
562 if (status != SILC_STATUS_OK &&
563 status != SILC_STATUS_LIST_END) {
564 silc_client_command_reply_free(cmd);
569 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
570 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
572 /* If we received notify for invalid ID we'll remove the ID if we
574 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
575 SilcClientEntry client_entry;
578 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
581 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
583 client_entry = silc_client_get_client_by_id(cmd->client, conn,
586 silc_client_del_client(cmd->client, conn, client_entry);
587 silc_free(client_id);
592 silc_client_command_reply_free(cmd);
595 /* Received reply for command NICK. If everything went without errors
596 we just received our new Client ID. */
598 SILC_CLIENT_CMD_REPLY_FUNC(nick)
600 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
601 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
602 SilcCommandStatus status;
607 SILC_LOG_DEBUG(("Start"));
609 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
610 if (status != SILC_STATUS_OK) {
611 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
612 "Cannot set nickname: %s", silc_client_command_status_message(status));
617 argc = silc_argument_get_arg_num(cmd->args);
618 if (argc < 2 || argc > 2) {
619 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
620 "Cannot set nickname: bad reply to command");
625 /* Take received Client ID */
626 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
627 idp = silc_id_payload_parse(tmp, len);
632 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
634 /* Notify application */
635 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
636 COMMAND_REPLY((ARGS, conn->local_entry));
637 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
638 silc_client_command_reply_free(cmd);
642 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
643 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
644 silc_client_command_reply_free(cmd);
647 /* Received reply to the LIST command. */
649 SILC_CLIENT_CMD_REPLY_FUNC(list)
651 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
652 SilcCommandStatus status;
653 unsigned char *tmp, *name, *topic;
654 uint32 usercount = 0;
656 COMMAND_CHECK_STATUS_LIST;
658 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
659 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
660 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
662 SILC_GET32_MSB(usercount, tmp);
664 /* Notify application */
665 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
667 /* Pending callbacks are not executed if this was an list entry */
668 if (status != SILC_STATUS_OK &&
669 status != SILC_STATUS_LIST_END) {
670 silc_client_command_reply_free(cmd);
675 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
676 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
677 silc_client_command_reply_free(cmd);
680 /* Received reply to topic command. */
682 SILC_CLIENT_CMD_REPLY_FUNC(topic)
684 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
685 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
686 SilcCommandStatus status;
687 SilcChannelEntry channel;
688 SilcChannelID *channel_id = NULL;
689 SilcIDCacheEntry id_cache = NULL;
694 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
695 if (status != SILC_STATUS_OK) {
696 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
697 "%s", silc_client_command_status_message(status));
702 argc = silc_argument_get_arg_num(cmd->args);
703 if (argc < 1 || argc > 3) {
708 /* Take Channel ID */
709 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
714 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
718 channel_id = silc_id_payload_parse_id(tmp, len);
722 /* Get the channel entry */
723 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
725 silc_free(channel_id);
730 channel = (SilcChannelEntry)id_cache->context;
732 /* Notify application */
733 COMMAND_REPLY((ARGS, channel, topic));
736 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
737 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
738 silc_client_command_reply_free(cmd);
741 /* Received reply to invite command. */
743 SILC_CLIENT_CMD_REPLY_FUNC(invite)
745 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
746 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
747 SilcCommandStatus status;
748 SilcChannelEntry channel;
749 SilcChannelID *channel_id;
750 SilcIDCacheEntry id_cache;
754 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
755 SILC_GET16_MSB(status, tmp);
756 if (status != SILC_STATUS_OK) {
757 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
758 "%s", silc_client_command_status_message(status));
763 /* Take Channel ID */
764 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
768 channel_id = silc_id_payload_parse_id(tmp, len);
772 /* Get the channel entry */
773 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
775 silc_free(channel_id);
780 channel = (SilcChannelEntry)id_cache->context;
782 /* Get the invite list */
783 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
785 /* Notify application */
786 COMMAND_REPLY((ARGS, channel, tmp));
789 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
790 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
791 silc_client_command_reply_free(cmd);
794 /* Received reply to the KILL command. */
796 SILC_CLIENT_CMD_REPLY_FUNC(kill)
798 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
799 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
800 SilcCommandStatus status;
802 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
803 if (status != SILC_STATUS_OK) {
804 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
805 "%s", silc_client_command_status_message(status));
810 /* Notify application */
811 COMMAND_REPLY((ARGS));
814 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
815 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
816 silc_client_command_reply_free(cmd);
819 /* Received reply to INFO command. We receive the server ID and some
820 information about the server user requested. */
822 SILC_CLIENT_CMD_REPLY_FUNC(info)
824 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
825 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
826 SilcCommandStatus status;
828 SilcIDCacheEntry id_cache;
829 SilcServerEntry server;
830 SilcServerID *server_id = NULL;
831 char *server_name, *server_info;
834 SILC_LOG_DEBUG(("Start"));
836 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
837 SILC_GET16_MSB(status, tmp);
838 if (status != SILC_STATUS_OK) {
839 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
840 silc_client_command_status_message(status));
846 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
850 server_id = silc_id_payload_parse_id(tmp, len);
854 /* Get server name */
855 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
859 /* Get server info */
860 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
864 /* See whether we have this server cached. If not create it. */
865 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
867 SILC_LOG_DEBUG(("New server entry"));
869 server = silc_calloc(1, sizeof(*server));
870 server->server_name = strdup(server_name);
871 server->server_info = strdup(server_info);
872 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
874 /* Add it to the cache */
875 silc_idcache_add(conn->server_cache, server->server_name,
876 server->server_id, (void *)server, 0, NULL);
878 server = (SilcServerEntry)id_cache->context;
881 /* Notify application */
882 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
885 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
886 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
887 silc_free(server_id);
888 silc_client_command_reply_free(cmd);
891 /* Received reply to PING command. The reply time is shown to user. */
893 SILC_CLIENT_CMD_REPLY_FUNC(ping)
895 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
896 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
897 SilcCommandStatus status;
900 time_t diff, curtime;
902 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
903 if (status != SILC_STATUS_OK) {
904 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
905 "%s", silc_client_command_status_message(status));
910 curtime = time(NULL);
911 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
912 cmd->packet->src_id_type);
913 if (!id || !conn->ping) {
918 for (i = 0; i < conn->ping_count; i++) {
919 if (!conn->ping[i].dest_id)
921 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
922 diff = curtime - conn->ping[i].start_time;
923 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
924 "Ping reply from %s: %d second%s",
925 conn->ping[i].dest_name, diff,
926 diff == 1 ? "" : "s");
928 conn->ping[i].start_time = 0;
929 silc_free(conn->ping[i].dest_id);
930 conn->ping[i].dest_id = NULL;
931 silc_free(conn->ping[i].dest_name);
932 conn->ping[i].dest_name = NULL;
939 /* Notify application */
940 COMMAND_REPLY((ARGS));
943 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
944 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
945 silc_client_command_reply_free(cmd);
948 /* Received reply for JOIN command. */
950 SILC_CLIENT_CMD_REPLY_FUNC(join)
952 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
953 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
954 SilcCommandStatus status;
955 SilcIDPayload idp = NULL;
956 SilcChannelEntry channel;
957 SilcIDCacheEntry id_cache = NULL;
959 uint32 argc, mode, len, list_count;
960 char *topic, *tmp, *channel_name = NULL, *hmac;
961 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
964 SILC_LOG_DEBUG(("Start"));
966 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
967 if (status != SILC_STATUS_OK) {
968 if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
969 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
970 "%s", silc_client_command_status_message(status));
975 argc = silc_argument_get_arg_num(cmd->args);
976 if (argc < 7 || argc > 14) {
977 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
978 "Cannot join channel: Bad reply packet");
983 /* Get channel name */
984 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
986 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
987 "Cannot join channel: Bad reply packet");
991 channel_name = strdup(tmp);
994 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
996 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
997 "Cannot join channel: Bad reply packet");
999 silc_free(channel_name);
1002 idp = silc_id_payload_parse(tmp, len);
1004 COMMAND_REPLY_ERROR;
1005 silc_free(channel_name);
1009 /* Get channel mode */
1010 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1012 SILC_GET32_MSB(mode, tmp);
1016 /* Get channel key */
1017 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1019 keyp = silc_buffer_alloc(len);
1020 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1021 silc_buffer_put(keyp, tmp, len);
1025 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1027 /* If we have the channel entry, remove it and create a new one */
1028 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1030 silc_client_del_channel(cmd->client, conn, channel);
1032 /* Save received Channel ID. This actually creates the channel */
1033 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
1035 silc_id_payload_free(idp);
1037 conn->current_channel = channel;
1040 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1042 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1043 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1044 "Cannot join channel: Unsupported HMAC `%s'", hmac);
1045 COMMAND_REPLY_ERROR;
1046 silc_free(channel_name);
1051 /* Get the list count */
1052 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1055 SILC_GET32_MSB(list_count, tmp);
1057 /* Get Client ID list */
1058 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1062 client_id_list = silc_buffer_alloc(len);
1063 silc_buffer_pull_tail(client_id_list, len);
1064 silc_buffer_put(client_id_list, tmp, len);
1066 /* Get client mode list */
1067 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1071 client_mode_list = silc_buffer_alloc(len);
1072 silc_buffer_pull_tail(client_mode_list, len);
1073 silc_buffer_put(client_mode_list, tmp, len);
1075 /* Add clients we received in the reply to the channel */
1076 for (i = 0; i < list_count; i++) {
1079 SilcClientID *client_id;
1080 SilcClientEntry client_entry;
1083 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1085 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1090 SILC_GET32_MSB(mode, client_mode_list->data);
1092 /* Check if we have this client cached already. */
1093 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1096 silc_hash_client_id_compare, NULL,
1098 /* No, we don't have it, add entry for it. */
1100 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1101 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1103 /* Yes, we have it already */
1104 client_entry = (SilcClientEntry)id_cache->context;
1107 /* Join the client to the channel */
1108 chu = silc_calloc(1, sizeof(*chu));
1109 chu->client = client_entry;
1111 silc_list_add(channel->clients, chu);
1112 silc_free(client_id);
1114 silc_buffer_pull(client_id_list, idp_len);
1115 silc_buffer_pull(client_mode_list, 4);
1117 silc_buffer_push(client_id_list, client_id_list->data -
1118 client_id_list->head);
1119 silc_buffer_push(client_mode_list, client_mode_list->data -
1120 client_mode_list->head);
1122 /* Save channel key */
1123 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1124 silc_client_save_channel_key(conn, keyp, channel);
1126 /* Client is now joined to the channel */
1127 channel->on_channel = TRUE;
1129 /* Notify application */
1130 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1131 keyp ? keyp->head : NULL, NULL,
1132 NULL, topic, hmac, list_count, client_id_list,
1136 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1137 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1138 silc_client_command_reply_free(cmd);
1141 silc_buffer_free(keyp);
1143 silc_buffer_free(client_id_list);
1144 if (client_mode_list)
1145 silc_buffer_free(client_mode_list);
1148 /* Received reply for MOTD command */
1150 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1152 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1153 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1154 SilcCommandStatus status;
1157 char *motd = NULL, *cp, line[256];
1159 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1160 SILC_GET16_MSB(status, tmp);
1161 if (status != SILC_STATUS_OK) {
1162 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1163 "%s", silc_client_command_status_message(status));
1164 COMMAND_REPLY_ERROR;
1168 argc = silc_argument_get_arg_num(cmd->args);
1170 COMMAND_REPLY_ERROR;
1175 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1177 COMMAND_REPLY_ERROR;
1184 if (cp[i++] == '\n') {
1185 memset(line, 0, sizeof(line));
1186 strncat(line, cp, i - 1);
1192 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
1201 /* Notify application */
1202 COMMAND_REPLY((ARGS, motd));
1205 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1206 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1207 silc_client_command_reply_free(cmd);
1210 /* Received reply tot he UMODE command. Save the current user mode */
1212 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1214 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1215 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1216 SilcCommandStatus status;
1220 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1221 SILC_GET16_MSB(status, tmp);
1222 if (status != SILC_STATUS_OK) {
1223 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1224 "%s", silc_client_command_status_message(status));
1225 COMMAND_REPLY_ERROR;
1229 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1231 COMMAND_REPLY_ERROR;
1235 SILC_GET32_MSB(mode, tmp);
1236 conn->local_entry->mode = mode;
1238 /* Notify application */
1239 COMMAND_REPLY((ARGS, mode));
1242 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1243 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1244 silc_client_command_reply_free(cmd);
1247 /* Received reply for CMODE command. */
1249 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1251 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1252 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1253 SilcCommandStatus status;
1256 SilcIDCacheEntry id_cache;
1257 SilcChannelID *channel_id;
1258 SilcChannelEntry channel;
1261 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1262 if (status != SILC_STATUS_OK) {
1263 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1264 "%s", silc_client_command_status_message(status));
1265 COMMAND_REPLY_ERROR;
1269 /* Take Channel ID */
1270 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1273 channel_id = silc_id_payload_parse_id(tmp, len);
1277 /* Get the channel entry */
1278 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1280 silc_free(channel_id);
1281 COMMAND_REPLY_ERROR;
1285 channel = (SilcChannelEntry)id_cache->context;
1287 /* Get channel mode */
1288 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1290 silc_free(channel_id);
1291 COMMAND_REPLY_ERROR;
1296 SILC_GET32_MSB(mode, tmp);
1297 channel->mode = mode;
1299 /* Notify application */
1300 COMMAND_REPLY((ARGS, channel, mode));
1302 silc_free(channel_id);
1305 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1306 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1307 silc_client_command_reply_free(cmd);
1310 /* Received reply for CUMODE command */
1312 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1314 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1315 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1316 SilcCommandStatus status;
1317 SilcIDCacheEntry id_cache = NULL;
1318 SilcClientID *client_id;
1319 SilcChannelID *channel_id;
1320 SilcClientEntry client_entry;
1321 SilcChannelEntry channel;
1322 SilcChannelUser chu;
1323 unsigned char *modev, *tmp, *id;
1326 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1327 if (status != SILC_STATUS_OK) {
1328 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1329 "%s", silc_client_command_status_message(status));
1330 COMMAND_REPLY_ERROR;
1334 /* Get channel mode */
1335 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1337 COMMAND_REPLY_ERROR;
1341 /* Take Channel ID */
1342 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1345 channel_id = silc_id_payload_parse_id(tmp, len);
1349 /* Get the channel entry */
1350 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1352 silc_free(channel_id);
1353 COMMAND_REPLY_ERROR;
1357 channel = (SilcChannelEntry)id_cache->context;
1360 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1362 silc_free(channel_id);
1363 COMMAND_REPLY_ERROR;
1366 client_id = silc_id_payload_parse_id(id, len);
1368 silc_free(channel_id);
1369 COMMAND_REPLY_ERROR;
1373 /* Get client entry */
1374 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1376 silc_hash_client_id_compare, NULL,
1378 silc_free(channel_id);
1379 silc_free(client_id);
1380 COMMAND_REPLY_ERROR;
1384 client_entry = (SilcClientEntry)id_cache->context;
1387 SILC_GET32_MSB(mode, modev);
1388 silc_list_start(channel->clients);
1389 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1390 if (chu->client == client_entry) {
1396 /* Notify application */
1397 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1398 silc_free(client_id);
1399 silc_free(channel_id);
1402 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1403 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1404 silc_client_command_reply_free(cmd);
1407 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1409 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1410 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1411 SilcCommandStatus status;
1414 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1415 SILC_GET16_MSB(status, tmp);
1416 if (status != SILC_STATUS_OK) {
1417 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1418 "%s", silc_client_command_status_message(status));
1419 COMMAND_REPLY_ERROR;
1423 /* Notify application */
1424 COMMAND_REPLY((ARGS));
1427 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1428 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1429 silc_client_command_reply_free(cmd);
1432 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1434 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1435 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1436 SilcCommandStatus status;
1439 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1440 SILC_GET16_MSB(status, tmp);
1441 if (status != SILC_STATUS_OK) {
1442 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1443 "%s", silc_client_command_status_message(status));
1444 COMMAND_REPLY_ERROR;
1448 /* Notify application */
1449 COMMAND_REPLY((ARGS));
1452 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1453 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1454 silc_client_command_reply_free(cmd);
1457 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1459 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1460 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1461 SilcCommandStatus status;
1464 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1465 SILC_GET16_MSB(status, tmp);
1466 if (status != SILC_STATUS_OK) {
1467 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1468 "%s", silc_client_command_status_message(status));
1469 COMMAND_REPLY_ERROR;
1473 /* Notify application */
1474 COMMAND_REPLY((ARGS));
1477 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1478 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1479 silc_client_command_reply_free(cmd);
1482 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1484 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1485 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1486 SilcCommandStatus status;
1489 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1490 SILC_GET16_MSB(status, tmp);
1491 if (status != SILC_STATUS_OK) {
1492 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1493 "%s", silc_client_command_status_message(status));
1494 COMMAND_REPLY_ERROR;
1498 /* Notify application */
1499 COMMAND_REPLY((ARGS));
1502 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1503 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1504 silc_client_command_reply_free(cmd);
1507 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1509 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1510 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1511 SilcCommandStatus status;
1512 SilcIDCacheEntry id_cache = NULL;
1513 SilcChannelEntry channel;
1514 SilcChannelID *channel_id;
1518 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1519 SILC_GET16_MSB(status, tmp);
1520 if (status != SILC_STATUS_OK) {
1521 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1522 "%s", silc_client_command_status_message(status));
1523 COMMAND_REPLY_ERROR;
1527 /* Take Channel ID */
1528 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1532 channel_id = silc_id_payload_parse_id(tmp, len);
1536 /* Get the channel entry */
1537 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1539 silc_free(channel_id);
1540 COMMAND_REPLY_ERROR;
1544 channel = (SilcChannelEntry)id_cache->context;
1546 /* Get the ban list */
1547 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1549 /* Notify application */
1550 COMMAND_REPLY((ARGS, channel, tmp));
1553 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1554 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1555 silc_client_command_reply_free(cmd);
1558 SILC_CLIENT_CMD_REPLY_FUNC(close)
1560 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1561 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1562 SilcCommandStatus status;
1565 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1566 SILC_GET16_MSB(status, tmp);
1567 if (status != SILC_STATUS_OK) {
1568 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1569 "%s", silc_client_command_status_message(status));
1570 COMMAND_REPLY_ERROR;
1574 /* Notify application */
1575 COMMAND_REPLY((ARGS));
1578 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1579 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1580 silc_client_command_reply_free(cmd);
1583 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1585 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1586 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1587 SilcCommandStatus status;
1590 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1591 SILC_GET16_MSB(status, tmp);
1592 if (status != SILC_STATUS_OK) {
1593 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1594 "%s", silc_client_command_status_message(status));
1595 COMMAND_REPLY_ERROR;
1599 /* Notify application */
1600 COMMAND_REPLY((ARGS));
1603 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1604 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1605 silc_client_command_reply_free(cmd);
1608 /* Reply to LEAVE command. */
1610 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1612 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1613 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1614 SilcCommandStatus status;
1617 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1618 SILC_GET16_MSB(status, tmp);
1619 if (status != SILC_STATUS_OK) {
1620 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1621 "%s", silc_client_command_status_message(status));
1622 COMMAND_REPLY_ERROR;
1626 /* Notify application */
1627 COMMAND_REPLY((ARGS));
1630 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1631 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1632 silc_client_command_reply_free(cmd);
1635 /* Reply to USERS command. Received list of client ID's and theirs modes
1636 on the channel we requested. */
1638 SILC_CLIENT_CMD_REPLY_FUNC(users)
1640 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1641 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1642 SilcCommandStatus status;
1643 SilcIDCacheEntry id_cache = NULL;
1644 SilcChannelEntry channel;
1645 SilcChannelUser chu;
1646 SilcChannelID *channel_id = NULL;
1647 SilcBuffer client_id_list = NULL;
1648 SilcBuffer client_mode_list = NULL;
1650 uint32 tmp_len, list_count;
1652 unsigned char **res_argv = NULL;
1653 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1655 SILC_LOG_DEBUG(("Start"));
1657 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1658 SILC_GET16_MSB(status, tmp);
1659 if (status != SILC_STATUS_OK) {
1660 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1661 "%s", silc_client_command_status_message(status));
1662 COMMAND_REPLY_ERROR;
1666 /* Get channel ID */
1667 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1669 COMMAND_REPLY_ERROR;
1672 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1674 COMMAND_REPLY_ERROR;
1678 /* Get the list count */
1679 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1681 COMMAND_REPLY_ERROR;
1684 SILC_GET32_MSB(list_count, tmp);
1686 /* Get Client ID list */
1687 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1689 COMMAND_REPLY_ERROR;
1693 client_id_list = silc_buffer_alloc(tmp_len);
1694 silc_buffer_pull_tail(client_id_list, tmp_len);
1695 silc_buffer_put(client_id_list, tmp, tmp_len);
1697 /* Get client mode list */
1698 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1700 COMMAND_REPLY_ERROR;
1704 client_mode_list = silc_buffer_alloc(tmp_len);
1705 silc_buffer_pull_tail(client_mode_list, tmp_len);
1706 silc_buffer_put(client_mode_list, tmp, tmp_len);
1708 /* Get channel entry */
1709 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1711 /* Resolve the channel from server */
1712 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1714 /* Register pending command callback. After we've received the channel
1715 information we will reprocess this command reply by re-calling this
1716 USERS command reply callback. */
1717 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1718 NULL, silc_client_command_reply_users, cmd);
1721 channel = (SilcChannelEntry)id_cache->context;
1724 /* Remove old client list from channel. */
1725 silc_list_start(channel->clients);
1726 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1727 silc_list_del(channel->clients, chu);
1731 /* Cache the received Client ID's and modes. */
1732 for (i = 0; i < list_count; i++) {
1735 SilcClientID *client_id;
1736 SilcClientEntry client;
1739 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1741 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1746 SILC_GET32_MSB(mode, client_mode_list->data);
1748 /* Check if we have this client cached already. */
1750 silc_idcache_find_by_id_one_ext(conn->client_cache,
1753 silc_hash_client_id_compare, NULL,
1756 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1757 !((SilcClientEntry)id_cache->context)->realname) {
1759 if (id_cache && id_cache->context) {
1760 SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
1761 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1762 silc_buffer_pull(client_id_list, idp_len);
1763 silc_buffer_pull(client_mode_list, 4);
1766 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1769 /* No we don't have it (or it is incomplete in information), query
1770 it from the server. Assemble argument table that will be sent
1771 for the WHOIS command later. */
1772 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1774 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1776 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1778 res_argv[res_argc] = client_id_list->data;
1779 res_argv_lens[res_argc] = idp_len;
1780 res_argv_types[res_argc] = res_argc + 3;
1783 /* Found the client, join it to the channel */
1784 client = (SilcClientEntry)id_cache->context;
1785 chu = silc_calloc(1, sizeof(*chu));
1786 chu->client = client;
1788 silc_list_add(channel->clients, chu);
1790 silc_free(client_id);
1794 silc_buffer_pull(client_id_list, idp_len);
1795 silc_buffer_pull(client_mode_list, 4);
1798 /* Query the client information from server if the list included clients
1799 that we don't know about. */
1803 /* Send the WHOIS command to server */
1804 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1805 silc_client_command_reply_whois_i, 0,
1807 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1808 res_argc, res_argv, res_argv_lens,
1809 res_argv_types, conn->cmd_ident);
1810 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1811 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1814 /* Register pending command callback. After we've received the WHOIS
1815 command reply we will reprocess this command reply by re-calling this
1816 USERS command reply callback. */
1817 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1818 NULL, silc_client_command_reply_users, cmd);
1820 silc_buffer_free(res_cmd);
1822 silc_free(channel_id);
1824 silc_free(res_argv);
1825 silc_free(res_argv_lens);
1826 silc_free(res_argv_types);
1830 /* Notify application */
1831 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1834 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1835 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1836 silc_client_command_reply_free(cmd);
1837 silc_free(channel_id);
1839 silc_buffer_free(client_id_list);
1840 if (client_mode_list)
1841 silc_buffer_free(client_mode_list);
1844 /* Received command reply to GETKEY command. WE've received the remote
1845 client's public key. */
1847 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1849 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1850 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1851 SilcCommandStatus status;
1852 SilcIDCacheEntry id_cache;
1853 SilcIDPayload idp = NULL;
1854 SilcClientID *client_id = NULL;
1855 SilcClientEntry client_entry;
1856 SilcServerID *server_id = NULL;
1857 SilcServerEntry server_entry;
1859 unsigned char *tmp, *pk;
1863 SilcPublicKey public_key = NULL;
1865 SILC_LOG_DEBUG(("Start"));
1867 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1868 SILC_GET16_MSB(status, tmp);
1869 if (status != SILC_STATUS_OK) {
1870 SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1871 "%s", silc_client_command_status_message(status));
1872 COMMAND_REPLY_ERROR;
1876 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1878 COMMAND_REPLY_ERROR;
1881 idp = silc_id_payload_parse(tmp, len);
1883 COMMAND_REPLY_ERROR;
1887 /* Get the public key payload */
1888 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1890 /* Decode the public key */
1891 SILC_GET16_MSB(pk_len, tmp);
1892 SILC_GET16_MSB(type, tmp + 2);
1895 if (type != SILC_SKE_PK_TYPE_SILC) {
1896 COMMAND_REPLY_ERROR;
1900 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1901 COMMAND_REPLY_ERROR;
1906 id_type = silc_id_payload_get_type(idp);
1907 if (id_type == SILC_ID_CLIENT) {
1908 /* Received client's public key */
1909 client_id = silc_id_payload_get_id(idp);
1910 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1913 silc_hash_client_id_compare, NULL,
1915 COMMAND_REPLY_ERROR;
1919 client_entry = (SilcClientEntry)id_cache->context;
1921 /* Notify application */
1922 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1923 } else if (id_type == SILC_ID_SERVER) {
1924 /* Received server's public key */
1925 server_id = silc_id_payload_get_id(idp);
1926 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1928 COMMAND_REPLY_ERROR;
1932 server_entry = (SilcServerEntry)id_cache->context;
1934 /* Notify application */
1935 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1939 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1940 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1942 silc_id_payload_free(idp);
1944 silc_pkcs_public_key_free(public_key);
1945 silc_free(client_id);
1946 silc_free(server_id);
1947 silc_client_command_reply_free(cmd);
1950 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1952 silc_client_command_reply_free(context);
1956 /******************************************************************************
1958 Internal command reply functions
1960 ******************************************************************************/
1962 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1964 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1965 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1966 SilcCommandStatus status;
1968 SILC_LOG_DEBUG(("Start"));
1970 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1971 if (status != SILC_STATUS_OK &&
1972 status != SILC_STATUS_LIST_START &&
1973 status != SILC_STATUS_LIST_ITEM &&
1974 status != SILC_STATUS_LIST_END)
1977 /* Save WHOIS info */
1978 silc_client_command_reply_whois_save(cmd, status, FALSE);
1980 /* Pending callbacks are not executed if this was an list entry */
1981 if (status != SILC_STATUS_OK &&
1982 status != SILC_STATUS_LIST_END) {
1983 silc_client_command_reply_free(cmd);
1988 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
1989 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
1991 /* If we received notify for invalid ID we'll remove the ID if we
1993 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1994 SilcClientEntry client_entry;
1996 unsigned char *tmp =
1997 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2000 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
2002 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2005 silc_client_del_client(cmd->client, conn, client_entry);
2006 silc_free(client_id);
2011 /* Unregister this command reply */
2012 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2013 NULL, silc_client_command_reply_whois_i,
2016 silc_client_command_reply_free(cmd);
2019 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2021 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2022 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2023 SilcCommandStatus status;
2025 SILC_LOG_DEBUG(("Start"));
2027 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
2028 if (status != SILC_STATUS_OK &&
2029 status != SILC_STATUS_LIST_START &&
2030 status != SILC_STATUS_LIST_ITEM &&
2031 status != SILC_STATUS_LIST_END)
2034 /* Save IDENTIFY info */
2035 silc_client_command_reply_identify_save(cmd, status, FALSE);
2037 /* Pending callbacks are not executed if this was an list entry */
2038 if (status != SILC_STATUS_OK &&
2039 status != SILC_STATUS_LIST_END) {
2040 silc_client_command_reply_free(cmd);
2045 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2046 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
2048 /* If we received notify for invalid ID we'll remove the ID if we
2050 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2051 SilcClientEntry client_entry;
2053 unsigned char *tmp =
2054 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2057 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
2059 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2062 silc_client_del_client(cmd->client, conn, client_entry);
2063 silc_free(client_id);
2068 /* Unregister this command reply */
2069 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2070 NULL, silc_client_command_reply_identify_i,
2073 silc_client_command_reply_free(cmd);
2076 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2078 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2079 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2080 SilcCommandStatus status;
2082 SilcIDCacheEntry id_cache;
2083 SilcServerEntry server;
2084 SilcServerID *server_id = NULL;
2085 char *server_name, *server_info;
2088 SILC_LOG_DEBUG(("Start"));
2090 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
2091 SILC_GET16_MSB(status, tmp);
2092 if (status != SILC_STATUS_OK)
2096 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2100 server_id = silc_id_payload_parse_id(tmp, len);
2104 /* Get server name */
2105 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2109 /* Get server info */
2110 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2114 /* See whether we have this server cached. If not create it. */
2115 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
2117 SILC_LOG_DEBUG(("New server entry"));
2118 server = silc_calloc(1, sizeof(*server));
2119 server->server_name = strdup(server_name);
2120 server->server_info = strdup(server_info);
2121 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
2123 /* Add it to the cache */
2124 silc_idcache_add(conn->server_cache, server->server_name,
2125 server->server_id, (void *)server, 0, NULL);
2129 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2130 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
2131 silc_free(server_id);
2132 silc_client_command_reply_free(cmd);