5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2001 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 /* All functions that call the COMMAND_CHECK_STATUS or the
93 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
95 #define COMMAND_CHECK_STATUS \
97 SILC_LOG_DEBUG(("Start")); \
98 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
99 if (status != SILC_STATUS_OK) { \
100 COMMAND_REPLY_ERROR; \
105 #define COMMAND_CHECK_STATUS_LIST \
107 SILC_LOG_DEBUG(("Start")); \
108 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
109 if (status != SILC_STATUS_OK && \
110 status != SILC_STATUS_LIST_START && \
111 status != SILC_STATUS_LIST_ITEM && \
112 status != SILC_STATUS_LIST_END) { \
113 COMMAND_REPLY_ERROR; \
118 /* Process received command reply. */
120 void silc_client_command_reply_process(SilcClient client,
121 SilcSocketConnection sock,
122 SilcPacketContext *packet)
124 SilcBuffer buffer = packet->buffer;
125 SilcClientCommand cmd;
126 SilcClientCommandReplyContext ctx;
127 SilcCommandPayload payload;
129 SilcCommandCb reply = NULL;
131 /* Get command reply payload from packet */
132 payload = silc_command_payload_parse(buffer->data, buffer->len);
134 /* Silently ignore bad reply packet */
135 SILC_LOG_DEBUG(("Bad command reply packet"));
139 /* Allocate command reply context. This must be free'd by the
140 command reply routine receiving it. */
141 ctx = silc_calloc(1, sizeof(*ctx));
142 ctx->client = client;
144 ctx->payload = payload;
145 ctx->args = silc_command_get_args(ctx->payload);
146 ctx->packet = packet;
147 ctx->ident = silc_command_get_ident(ctx->payload);
149 /* Check for pending commands and mark to be exeucted */
150 silc_client_command_pending_check(sock->user_data, ctx,
151 silc_command_get(ctx->payload),
154 /* Execute command reply */
156 command = silc_command_get(ctx->payload);
158 /* Try to find matching the command identifier */
159 silc_list_start(client->internal->commands);
160 while ((cmd = silc_list_get(client->internal->commands)) != SILC_LIST_END) {
161 if (cmd->cmd == command && !cmd->ident)
163 if (cmd->cmd == command && cmd->ident == ctx->ident) {
164 (*cmd->reply)((void *)ctx, NULL);
169 if (cmd == SILC_LIST_END) {
171 /* No specific identifier for command reply, call first one found */
178 /* Returns status message string */
180 char *silc_client_command_status_message(SilcCommandStatus status)
184 for (i = 0; silc_command_status_messages[i].message; i++) {
185 if (silc_command_status_messages[i].status == status)
189 if (silc_command_status_messages[i].message == NULL)
192 return silc_command_status_messages[i].message;
195 /* Free command reply context and its internals. */
197 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
200 silc_command_payload_free(cmd->payload);
206 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
207 SilcCommandStatus status,
210 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
211 SilcClientID *client_id;
212 SilcIDCacheEntry id_cache = NULL;
213 SilcClientEntry client_entry = NULL;
216 unsigned char *id_data, *tmp;
217 char *nickname = NULL, *username = NULL;
218 char *realname = NULL;
219 uint32 idle = 0, mode = 0;
220 SilcBuffer channels = NULL;
221 unsigned char *fingerprint;
222 uint32 fingerprint_len;
224 argc = silc_argument_get_arg_num(cmd->args);
226 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
233 client_id = silc_id_payload_parse_id(id_data, len);
240 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
241 username = silc_argument_get_arg_type(cmd->args, 4, &len);
242 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
243 if (!nickname || !username || !realname) {
249 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
251 channels = silc_buffer_alloc(len);
252 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
253 silc_buffer_put(channels, tmp, len);
256 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
258 SILC_GET32_MSB(mode, tmp);
260 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
262 SILC_GET32_MSB(idle, tmp);
264 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
266 /* Check if we have this client cached already. */
267 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
269 silc_hash_client_id_compare, NULL,
271 SILC_LOG_DEBUG(("Adding new client entry"));
273 silc_client_add_client(cmd->client, conn, nickname, username, realname,
276 client_entry = (SilcClientEntry)id_cache->context;
277 silc_client_update_client(cmd->client, conn, client_entry,
278 nickname, username, realname, mode);
279 silc_free(client_id);
282 if (fingerprint && !client_entry->fingerprint) {
283 client_entry->fingerprint =
284 silc_calloc(fingerprint_len,
285 sizeof(*client_entry->fingerprint));
286 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
287 client_entry->fingerprint_len = fingerprint_len;
290 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
291 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
293 /* Notify application */
294 if (!cmd->callback && notify)
295 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
296 channels, mode, idle, fingerprint));
299 silc_buffer_free(channels);
302 /* Received reply for WHOIS command. This maybe called several times
303 for one WHOIS command as server may reply with list of results. */
305 SILC_CLIENT_CMD_REPLY_FUNC(whois)
307 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
308 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
309 SilcCommandStatus status;
311 COMMAND_CHECK_STATUS_LIST;
313 /* Save WHOIS info */
314 silc_client_command_reply_whois_save(cmd, status, TRUE);
316 /* Pending callbacks are not executed if this was an list entry */
317 if (status != SILC_STATUS_OK &&
318 status != SILC_STATUS_LIST_END) {
319 silc_client_command_reply_free(cmd);
324 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
325 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
327 /* If we received notify for invalid ID we'll remove the ID if we
329 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
330 SilcClientEntry client_entry;
333 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
336 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
338 client_entry = silc_client_get_client_by_id(cmd->client, conn,
341 silc_client_del_client(cmd->client, conn, client_entry);
342 silc_free(client_id);
347 silc_client_command_reply_free(cmd);
350 /* Received reply for WHOWAS command. */
352 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
354 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
355 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
356 SilcCommandStatus status;
357 SilcClientID *client_id;
358 SilcIDCacheEntry id_cache = NULL;
359 SilcClientEntry client_entry = NULL;
361 unsigned char *id_data;
362 char *nickname, *username;
363 char *realname = NULL;
365 COMMAND_CHECK_STATUS_LIST;
367 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
373 client_id = silc_id_payload_parse_id(id_data, len);
379 /* Get the client entry, if exists */
380 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
382 silc_hash_client_id_compare, NULL,
384 client_entry = (SilcClientEntry)id_cache->context;
385 silc_free(client_id);
387 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
388 username = silc_argument_get_arg_type(cmd->args, 4, &len);
389 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
390 if (!nickname || !username) {
395 /* Notify application. We don't save any history information to any
396 cache. Just pass the data to the application for displaying on
398 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
400 /* Pending callbacks are not executed if this was an list entry */
401 if (status != SILC_STATUS_OK &&
402 status != SILC_STATUS_LIST_END) {
403 silc_client_command_reply_free(cmd);
408 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
409 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS);
410 silc_client_command_reply_free(cmd);
414 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
415 SilcCommandStatus status,
418 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
419 SilcClient client = cmd->client;
420 SilcClientID *client_id = NULL;
421 SilcServerID *server_id = NULL;
422 SilcChannelID *channel_id = NULL;
423 SilcIDCacheEntry id_cache = NULL;
424 SilcClientEntry client_entry;
425 SilcServerEntry server_entry;
426 SilcChannelEntry channel_entry;
429 unsigned char *id_data;
430 char *name = NULL, *info = NULL;
431 SilcIDPayload idp = NULL;
434 argc = silc_argument_get_arg_num(cmd->args);
436 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
442 idp = silc_id_payload_parse(id_data, len);
449 name = silc_argument_get_arg_type(cmd->args, 3, &len);
450 info = silc_argument_get_arg_type(cmd->args, 4, &len);
452 id_type = silc_id_payload_get_type(idp);
456 client_id = silc_id_payload_get_id(idp);
458 SILC_LOG_DEBUG(("Received client information"));
460 /* Check if we have this client cached already. */
461 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
464 silc_hash_client_id_compare, NULL,
466 SILC_LOG_DEBUG(("Adding new client entry"));
468 silc_client_add_client(cmd->client, conn, name, info, NULL,
469 silc_id_dup(client_id, id_type), 0);
471 client_entry = (SilcClientEntry)id_cache->context;
472 silc_client_update_client(cmd->client, conn, client_entry,
473 name, info, NULL, 0);
476 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
477 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
479 /* Notify application */
481 COMMAND_REPLY((ARGS, client_entry, name, info));
485 server_id = silc_id_payload_get_id(idp);
487 SILC_LOG_DEBUG(("Received server information"));
489 /* Check if we have this server cached already. */
490 if (!silc_idcache_find_by_id_one(conn->server_cache,
491 (void *)server_id, &id_cache)) {
492 SILC_LOG_DEBUG(("Adding new server entry"));
494 server_entry = silc_calloc(1, sizeof(*server_entry));
495 server_entry->server_id = silc_id_dup(server_id, id_type);
497 server_entry->server_name = strdup(name);
499 server_entry->server_info = strdup(info);
501 /* Add server to cache */
502 silc_idcache_add(conn->server_cache, server_entry->server_name,
503 server_entry->server_id, (void *)server_entry,
506 server_entry = (SilcServerEntry)id_cache->context;
509 /* Notify application */
511 COMMAND_REPLY((ARGS, server_entry, name, info));
514 case SILC_ID_CHANNEL:
515 channel_id = silc_id_payload_get_id(idp);
517 SILC_LOG_DEBUG(("Received channel information"));
519 /* Check if we have this channel cached already. */
520 if (!silc_idcache_find_by_id_one(conn->channel_cache,
521 (void *)channel_id, &id_cache)) {
525 SILC_LOG_DEBUG(("Adding new channel entry"));
526 channel_entry = silc_client_new_channel_id(client, conn->sock,
527 strdup(name), 0, idp);
529 channel_entry = (SilcChannelEntry)id_cache->context;
532 /* Notify application */
534 COMMAND_REPLY((ARGS, channel_entry, name, info));
538 silc_id_payload_free(idp);
539 silc_free(client_id);
540 silc_free(server_id);
541 silc_free(channel_id);
544 /* Received reply for IDENTIFY command. This maybe called several times
545 for one IDENTIFY command as server may reply with list of results.
546 This is totally silent and does not print anything on screen. */
548 SILC_CLIENT_CMD_REPLY_FUNC(identify)
550 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
551 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
552 SilcCommandStatus status;
554 COMMAND_CHECK_STATUS_LIST;
556 /* Save IDENTIFY info */
557 silc_client_command_reply_identify_save(cmd, status, TRUE);
559 /* Pending callbacks are not executed if this was an list entry */
560 if (status != SILC_STATUS_OK &&
561 status != SILC_STATUS_LIST_END) {
562 silc_client_command_reply_free(cmd);
567 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
568 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
570 /* If we received notify for invalid ID we'll remove the ID if we
572 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
573 SilcClientEntry client_entry;
576 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
579 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
581 client_entry = silc_client_get_client_by_id(cmd->client, conn,
584 silc_client_del_client(cmd->client, conn, client_entry);
585 silc_free(client_id);
590 silc_client_command_reply_free(cmd);
593 /* Received reply for command NICK. If everything went without errors
594 we just received our new Client ID. */
596 SILC_CLIENT_CMD_REPLY_FUNC(nick)
598 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
599 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
600 SilcCommandStatus status;
605 SILC_LOG_DEBUG(("Start"));
607 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
608 if (status != SILC_STATUS_OK) {
609 cmd->client->internal->ops->say(
611 conn, SILC_CLIENT_MESSAGE_ERROR,
612 "Cannot set nickname: %s",
613 silc_client_command_status_message(status));
618 argc = silc_argument_get_arg_num(cmd->args);
619 if (argc < 2 || argc > 2) {
620 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
621 "Cannot set nickname: bad reply to command");
626 /* Take received Client ID */
627 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
628 idp = silc_id_payload_parse(tmp, len);
633 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
635 /* Notify application */
636 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
637 COMMAND_REPLY((ARGS, conn->local_entry));
638 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
639 silc_client_command_reply_free(cmd);
643 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
644 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
645 silc_client_command_reply_free(cmd);
648 /* Received reply to the LIST command. */
650 SILC_CLIENT_CMD_REPLY_FUNC(list)
652 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
653 SilcCommandStatus status;
654 unsigned char *tmp, *name, *topic;
655 uint32 usercount = 0;
657 COMMAND_CHECK_STATUS_LIST;
659 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
660 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
661 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
663 SILC_GET32_MSB(usercount, tmp);
665 /* Notify application */
666 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
668 /* Pending callbacks are not executed if this was an list entry */
669 if (status != SILC_STATUS_OK &&
670 status != SILC_STATUS_LIST_END) {
671 silc_client_command_reply_free(cmd);
676 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
677 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
678 silc_client_command_reply_free(cmd);
681 /* Received reply to topic command. */
683 SILC_CLIENT_CMD_REPLY_FUNC(topic)
685 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
686 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
687 SilcCommandStatus status;
688 SilcChannelEntry channel;
689 SilcChannelID *channel_id = NULL;
690 SilcIDCacheEntry id_cache = NULL;
695 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
696 if (status != SILC_STATUS_OK) {
697 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
698 "%s", silc_client_command_status_message(status));
703 argc = silc_argument_get_arg_num(cmd->args);
704 if (argc < 1 || argc > 3) {
709 /* Take Channel ID */
710 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
715 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
719 channel_id = silc_id_payload_parse_id(tmp, len);
723 /* Get the channel entry */
724 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
726 silc_free(channel_id);
731 channel = (SilcChannelEntry)id_cache->context;
733 /* Notify application */
734 COMMAND_REPLY((ARGS, channel, topic));
737 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
738 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
739 silc_client_command_reply_free(cmd);
742 /* Received reply to invite command. */
744 SILC_CLIENT_CMD_REPLY_FUNC(invite)
746 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
747 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
748 SilcCommandStatus status;
749 SilcChannelEntry channel;
750 SilcChannelID *channel_id;
751 SilcIDCacheEntry id_cache;
755 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
756 SILC_GET16_MSB(status, tmp);
757 if (status != SILC_STATUS_OK) {
758 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
759 "%s", silc_client_command_status_message(status));
764 /* Take Channel ID */
765 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
769 channel_id = silc_id_payload_parse_id(tmp, len);
773 /* Get the channel entry */
774 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
776 silc_free(channel_id);
781 channel = (SilcChannelEntry)id_cache->context;
783 /* Get the invite list */
784 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
786 /* Notify application */
787 COMMAND_REPLY((ARGS, channel, tmp));
790 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
791 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
792 silc_client_command_reply_free(cmd);
795 /* Received reply to the KILL command. */
797 SILC_CLIENT_CMD_REPLY_FUNC(kill)
799 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
800 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
801 SilcCommandStatus status;
803 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
804 if (status != SILC_STATUS_OK) {
805 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
806 "%s", silc_client_command_status_message(status));
811 /* Notify application */
812 COMMAND_REPLY((ARGS));
815 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
816 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
817 silc_client_command_reply_free(cmd);
820 /* Received reply to INFO command. We receive the server ID and some
821 information about the server user requested. */
823 SILC_CLIENT_CMD_REPLY_FUNC(info)
825 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
826 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
827 SilcCommandStatus status;
829 SilcIDCacheEntry id_cache;
830 SilcServerEntry server;
831 SilcServerID *server_id = NULL;
832 char *server_name, *server_info;
835 SILC_LOG_DEBUG(("Start"));
837 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
838 SILC_GET16_MSB(status, tmp);
839 if (status != SILC_STATUS_OK) {
840 cmd->client->internal->ops->say(
842 SILC_CLIENT_MESSAGE_ERROR,
844 silc_client_command_status_message(status));
850 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
854 server_id = silc_id_payload_parse_id(tmp, len);
858 /* Get server name */
859 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
863 /* Get server info */
864 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
868 /* See whether we have this server cached. If not create it. */
869 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
871 SILC_LOG_DEBUG(("New server entry"));
873 server = silc_calloc(1, sizeof(*server));
874 server->server_name = strdup(server_name);
875 server->server_info = strdup(server_info);
876 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
878 /* Add it to the cache */
879 silc_idcache_add(conn->server_cache, server->server_name,
880 server->server_id, (void *)server, 0, NULL);
882 server = (SilcServerEntry)id_cache->context;
885 /* Notify application */
886 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
889 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
890 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
891 silc_free(server_id);
892 silc_client_command_reply_free(cmd);
895 /* Received reply to PING command. The reply time is shown to user. */
897 SILC_CLIENT_CMD_REPLY_FUNC(ping)
899 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
900 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
901 SilcCommandStatus status;
904 time_t diff, curtime;
906 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
907 if (status != SILC_STATUS_OK) {
908 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
909 "%s", silc_client_command_status_message(status));
914 curtime = time(NULL);
915 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
916 cmd->packet->src_id_type);
917 if (!id || !conn->ping) {
922 for (i = 0; i < conn->ping_count; i++) {
923 if (!conn->ping[i].dest_id)
925 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
926 diff = curtime - conn->ping[i].start_time;
927 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
928 "Ping reply from %s: %d second%s",
929 conn->ping[i].dest_name, diff,
930 diff == 1 ? "" : "s");
932 conn->ping[i].start_time = 0;
933 silc_free(conn->ping[i].dest_id);
934 conn->ping[i].dest_id = NULL;
935 silc_free(conn->ping[i].dest_name);
936 conn->ping[i].dest_name = NULL;
943 /* Notify application */
944 COMMAND_REPLY((ARGS));
947 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
948 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
949 silc_client_command_reply_free(cmd);
952 /* Received reply for JOIN command. */
954 SILC_CLIENT_CMD_REPLY_FUNC(join)
956 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
957 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
958 SilcCommandStatus status;
959 SilcIDPayload idp = NULL;
960 SilcChannelEntry channel;
961 SilcIDCacheEntry id_cache = NULL;
963 uint32 argc, mode, len, list_count;
964 char *topic, *tmp, *channel_name = NULL, *hmac;
965 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
968 SILC_LOG_DEBUG(("Start"));
970 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
971 if (status != SILC_STATUS_OK) {
972 if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
973 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
974 "%s", silc_client_command_status_message(status));
979 argc = silc_argument_get_arg_num(cmd->args);
980 if (argc < 7 || argc > 14) {
981 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
982 "Cannot join channel: Bad reply packet");
987 /* Get channel name */
988 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
990 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
991 "Cannot join channel: Bad reply packet");
995 channel_name = strdup(tmp);
998 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1000 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1001 "Cannot join channel: Bad reply packet");
1002 COMMAND_REPLY_ERROR;
1003 silc_free(channel_name);
1006 idp = silc_id_payload_parse(tmp, len);
1008 COMMAND_REPLY_ERROR;
1009 silc_free(channel_name);
1013 /* Get channel mode */
1014 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1016 SILC_GET32_MSB(mode, tmp);
1020 /* Get channel key */
1021 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1023 keyp = silc_buffer_alloc(len);
1024 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1025 silc_buffer_put(keyp, tmp, len);
1029 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1031 /* If we have the channel entry, remove it and create a new one */
1032 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1034 silc_client_del_channel(cmd->client, conn, channel);
1036 /* Save received Channel ID. This actually creates the channel */
1037 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
1039 silc_id_payload_free(idp);
1041 conn->current_channel = channel;
1044 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1046 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1047 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1048 "Cannot join channel: Unsupported HMAC `%s'",
1050 COMMAND_REPLY_ERROR;
1051 silc_free(channel_name);
1056 /* Get the list count */
1057 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1060 SILC_GET32_MSB(list_count, tmp);
1062 /* Get Client ID list */
1063 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1067 client_id_list = silc_buffer_alloc(len);
1068 silc_buffer_pull_tail(client_id_list, len);
1069 silc_buffer_put(client_id_list, tmp, len);
1071 /* Get client mode list */
1072 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1076 client_mode_list = silc_buffer_alloc(len);
1077 silc_buffer_pull_tail(client_mode_list, len);
1078 silc_buffer_put(client_mode_list, tmp, len);
1080 /* Add clients we received in the reply to the channel */
1081 for (i = 0; i < list_count; i++) {
1084 SilcClientID *client_id;
1085 SilcClientEntry client_entry;
1088 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1090 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1095 SILC_GET32_MSB(mode, client_mode_list->data);
1097 /* Check if we have this client cached already. */
1098 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1101 silc_hash_client_id_compare, NULL,
1103 /* No, we don't have it, add entry for it. */
1105 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1106 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1108 /* Yes, we have it already */
1109 client_entry = (SilcClientEntry)id_cache->context;
1112 /* Join the client to the channel */
1113 chu = silc_calloc(1, sizeof(*chu));
1114 chu->client = client_entry;
1116 silc_list_add(channel->clients, chu);
1117 silc_free(client_id);
1119 silc_buffer_pull(client_id_list, idp_len);
1120 silc_buffer_pull(client_mode_list, 4);
1122 silc_buffer_push(client_id_list, client_id_list->data -
1123 client_id_list->head);
1124 silc_buffer_push(client_mode_list, client_mode_list->data -
1125 client_mode_list->head);
1127 /* Save channel key */
1128 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1129 silc_client_save_channel_key(conn, keyp, channel);
1131 /* Client is now joined to the channel */
1132 channel->on_channel = TRUE;
1134 /* Notify application */
1135 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1136 keyp ? keyp->head : NULL, NULL,
1137 NULL, topic, hmac, list_count, client_id_list,
1141 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1142 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1143 silc_client_command_reply_free(cmd);
1146 silc_buffer_free(keyp);
1148 silc_buffer_free(client_id_list);
1149 if (client_mode_list)
1150 silc_buffer_free(client_mode_list);
1153 /* Received reply for MOTD command */
1155 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1157 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1158 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1159 SilcCommandStatus status;
1162 char *motd = NULL, *cp, line[256];
1164 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1165 SILC_GET16_MSB(status, tmp);
1166 if (status != SILC_STATUS_OK) {
1167 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1168 "%s", silc_client_command_status_message(status));
1169 COMMAND_REPLY_ERROR;
1173 argc = silc_argument_get_arg_num(cmd->args);
1175 COMMAND_REPLY_ERROR;
1180 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1182 COMMAND_REPLY_ERROR;
1189 if (cp[i++] == '\n') {
1190 memset(line, 0, sizeof(line));
1191 strncat(line, cp, i - 1);
1197 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1207 /* Notify application */
1208 COMMAND_REPLY((ARGS, motd));
1211 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1212 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1213 silc_client_command_reply_free(cmd);
1216 /* Received reply tot he UMODE command. Save the current user mode */
1218 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1220 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1221 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1222 SilcCommandStatus status;
1226 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1227 SILC_GET16_MSB(status, tmp);
1228 if (status != SILC_STATUS_OK) {
1229 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1230 "%s", silc_client_command_status_message(status));
1231 COMMAND_REPLY_ERROR;
1235 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1237 COMMAND_REPLY_ERROR;
1241 SILC_GET32_MSB(mode, tmp);
1242 conn->local_entry->mode = mode;
1244 /* Notify application */
1245 COMMAND_REPLY((ARGS, mode));
1248 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1249 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1250 silc_client_command_reply_free(cmd);
1253 /* Received reply for CMODE command. */
1255 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1257 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1258 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1259 SilcCommandStatus status;
1262 SilcIDCacheEntry id_cache;
1263 SilcChannelID *channel_id;
1264 SilcChannelEntry channel;
1267 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1268 if (status != SILC_STATUS_OK) {
1269 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1270 "%s", silc_client_command_status_message(status));
1271 COMMAND_REPLY_ERROR;
1275 /* Take Channel ID */
1276 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1279 channel_id = silc_id_payload_parse_id(tmp, len);
1283 /* Get the channel entry */
1284 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1286 silc_free(channel_id);
1287 COMMAND_REPLY_ERROR;
1291 channel = (SilcChannelEntry)id_cache->context;
1293 /* Get channel mode */
1294 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1296 silc_free(channel_id);
1297 COMMAND_REPLY_ERROR;
1302 SILC_GET32_MSB(mode, tmp);
1303 channel->mode = mode;
1305 /* Notify application */
1306 COMMAND_REPLY((ARGS, channel, mode));
1308 silc_free(channel_id);
1311 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1312 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1313 silc_client_command_reply_free(cmd);
1316 /* Received reply for CUMODE command */
1318 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1320 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1321 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1322 SilcCommandStatus status;
1323 SilcIDCacheEntry id_cache = NULL;
1324 SilcClientID *client_id;
1325 SilcChannelID *channel_id;
1326 SilcClientEntry client_entry;
1327 SilcChannelEntry channel;
1328 SilcChannelUser chu;
1329 unsigned char *modev, *tmp, *id;
1332 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1333 if (status != SILC_STATUS_OK) {
1334 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1335 "%s", silc_client_command_status_message(status));
1336 COMMAND_REPLY_ERROR;
1340 /* Get channel mode */
1341 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1343 COMMAND_REPLY_ERROR;
1347 /* Take Channel ID */
1348 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1351 channel_id = silc_id_payload_parse_id(tmp, len);
1355 /* Get the channel entry */
1356 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1358 silc_free(channel_id);
1359 COMMAND_REPLY_ERROR;
1363 channel = (SilcChannelEntry)id_cache->context;
1366 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1368 silc_free(channel_id);
1369 COMMAND_REPLY_ERROR;
1372 client_id = silc_id_payload_parse_id(id, len);
1374 silc_free(channel_id);
1375 COMMAND_REPLY_ERROR;
1379 /* Get client entry */
1380 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1382 silc_hash_client_id_compare, NULL,
1384 silc_free(channel_id);
1385 silc_free(client_id);
1386 COMMAND_REPLY_ERROR;
1390 client_entry = (SilcClientEntry)id_cache->context;
1393 SILC_GET32_MSB(mode, modev);
1394 silc_list_start(channel->clients);
1395 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1396 if (chu->client == client_entry) {
1402 /* Notify application */
1403 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1404 silc_free(client_id);
1405 silc_free(channel_id);
1408 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1409 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1410 silc_client_command_reply_free(cmd);
1413 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1415 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1416 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1417 SilcCommandStatus status;
1420 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1421 SILC_GET16_MSB(status, tmp);
1422 if (status != SILC_STATUS_OK) {
1423 cmd->client->internal->ops->say(
1424 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1425 "%s", silc_client_command_status_message(status));
1426 COMMAND_REPLY_ERROR;
1430 /* Notify application */
1431 COMMAND_REPLY((ARGS));
1434 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1435 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1436 silc_client_command_reply_free(cmd);
1439 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1441 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1442 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1443 SilcCommandStatus status;
1446 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1447 SILC_GET16_MSB(status, tmp);
1448 if (status != SILC_STATUS_OK) {
1449 cmd->client->internal->ops->say(
1450 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1451 "%s", silc_client_command_status_message(status));
1452 COMMAND_REPLY_ERROR;
1456 /* Notify application */
1457 COMMAND_REPLY((ARGS));
1460 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1461 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1462 silc_client_command_reply_free(cmd);
1465 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1467 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1468 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1469 SilcCommandStatus status;
1472 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1473 SILC_GET16_MSB(status, tmp);
1474 if (status != SILC_STATUS_OK) {
1475 cmd->client->internal->ops->say(
1477 SILC_CLIENT_MESSAGE_ERROR,
1478 "%s", silc_client_command_status_message(status));
1479 COMMAND_REPLY_ERROR;
1483 /* Notify application */
1484 COMMAND_REPLY((ARGS));
1487 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1488 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1489 silc_client_command_reply_free(cmd);
1492 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1494 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1495 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1496 SilcCommandStatus status;
1499 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1500 SILC_GET16_MSB(status, tmp);
1501 if (status != SILC_STATUS_OK) {
1502 cmd->client->internal->ops->say(
1503 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1504 "%s", silc_client_command_status_message(status));
1505 COMMAND_REPLY_ERROR;
1509 /* Notify application */
1510 COMMAND_REPLY((ARGS));
1513 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1514 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1515 silc_client_command_reply_free(cmd);
1518 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1520 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1521 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1522 SilcCommandStatus status;
1523 SilcIDCacheEntry id_cache = NULL;
1524 SilcChannelEntry channel;
1525 SilcChannelID *channel_id;
1529 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1530 SILC_GET16_MSB(status, tmp);
1531 if (status != SILC_STATUS_OK) {
1532 cmd->client->internal->ops->say(
1533 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1534 "%s", silc_client_command_status_message(status));
1535 COMMAND_REPLY_ERROR;
1539 /* Take Channel ID */
1540 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1544 channel_id = silc_id_payload_parse_id(tmp, len);
1548 /* Get the channel entry */
1549 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1551 silc_free(channel_id);
1552 COMMAND_REPLY_ERROR;
1556 channel = (SilcChannelEntry)id_cache->context;
1558 /* Get the ban list */
1559 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1561 /* Notify application */
1562 COMMAND_REPLY((ARGS, channel, tmp));
1565 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1566 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1567 silc_client_command_reply_free(cmd);
1570 SILC_CLIENT_CMD_REPLY_FUNC(close)
1572 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1573 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1574 SilcCommandStatus status;
1577 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1578 SILC_GET16_MSB(status, tmp);
1579 if (status != SILC_STATUS_OK) {
1580 cmd->client->internal->ops->say(
1581 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1582 "%s", silc_client_command_status_message(status));
1583 COMMAND_REPLY_ERROR;
1587 /* Notify application */
1588 COMMAND_REPLY((ARGS));
1591 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1592 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1593 silc_client_command_reply_free(cmd);
1596 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1598 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1599 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1600 SilcCommandStatus status;
1603 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1604 SILC_GET16_MSB(status, tmp);
1605 if (status != SILC_STATUS_OK) {
1606 cmd->client->internal->ops->say(
1607 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1608 "%s", silc_client_command_status_message(status));
1609 COMMAND_REPLY_ERROR;
1613 /* Notify application */
1614 COMMAND_REPLY((ARGS));
1617 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1618 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1619 silc_client_command_reply_free(cmd);
1622 /* Reply to LEAVE command. */
1624 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1626 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1627 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1628 SilcCommandStatus status;
1631 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1632 SILC_GET16_MSB(status, tmp);
1633 if (status != SILC_STATUS_OK) {
1634 cmd->client->internal->ops->say(
1635 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1636 "%s", silc_client_command_status_message(status));
1637 COMMAND_REPLY_ERROR;
1641 /* Notify application */
1642 COMMAND_REPLY((ARGS));
1645 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1646 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1647 silc_client_command_reply_free(cmd);
1650 /* Reply to USERS command. Received list of client ID's and theirs modes
1651 on the channel we requested. */
1653 SILC_CLIENT_CMD_REPLY_FUNC(users)
1655 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1656 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1657 SilcCommandStatus status;
1658 SilcIDCacheEntry id_cache = NULL;
1659 SilcChannelEntry channel;
1660 SilcChannelUser chu;
1661 SilcChannelID *channel_id = NULL;
1662 SilcBuffer client_id_list = NULL;
1663 SilcBuffer client_mode_list = NULL;
1665 uint32 tmp_len, list_count;
1667 unsigned char **res_argv = NULL;
1668 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1670 SILC_LOG_DEBUG(("Start"));
1672 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1673 SILC_GET16_MSB(status, tmp);
1674 if (status != SILC_STATUS_OK) {
1675 cmd->client->internal->ops->say(
1676 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1677 "%s", silc_client_command_status_message(status));
1678 COMMAND_REPLY_ERROR;
1682 /* Get channel ID */
1683 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1685 COMMAND_REPLY_ERROR;
1688 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1690 COMMAND_REPLY_ERROR;
1694 /* Get the list count */
1695 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1697 COMMAND_REPLY_ERROR;
1700 SILC_GET32_MSB(list_count, tmp);
1702 /* Get Client ID list */
1703 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1705 COMMAND_REPLY_ERROR;
1709 client_id_list = silc_buffer_alloc(tmp_len);
1710 silc_buffer_pull_tail(client_id_list, tmp_len);
1711 silc_buffer_put(client_id_list, tmp, tmp_len);
1713 /* Get client mode list */
1714 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1716 COMMAND_REPLY_ERROR;
1720 client_mode_list = silc_buffer_alloc(tmp_len);
1721 silc_buffer_pull_tail(client_mode_list, tmp_len);
1722 silc_buffer_put(client_mode_list, tmp, tmp_len);
1724 /* Get channel entry */
1725 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1727 /* Resolve the channel from server */
1728 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1730 /* Register pending command callback. After we've received the channel
1731 information we will reprocess this command reply by re-calling this
1732 USERS command reply callback. */
1733 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1734 NULL, silc_client_command_reply_users, cmd);
1737 channel = (SilcChannelEntry)id_cache->context;
1740 /* Remove old client list from channel. */
1741 silc_list_start(channel->clients);
1742 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1743 silc_list_del(channel->clients, chu);
1747 /* Cache the received Client ID's and modes. */
1748 for (i = 0; i < list_count; i++) {
1751 SilcClientID *client_id;
1752 SilcClientEntry client;
1755 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1757 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1762 SILC_GET32_MSB(mode, client_mode_list->data);
1764 /* Check if we have this client cached already. */
1766 silc_idcache_find_by_id_one_ext(conn->client_cache,
1769 silc_hash_client_id_compare, NULL,
1772 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1773 !((SilcClientEntry)id_cache->context)->realname) {
1775 if (id_cache && id_cache->context) {
1776 SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
1777 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1778 silc_buffer_pull(client_id_list, idp_len);
1779 silc_buffer_pull(client_mode_list, 4);
1782 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1785 /* No we don't have it (or it is incomplete in information), query
1786 it from the server. Assemble argument table that will be sent
1787 for the WHOIS command later. */
1788 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1790 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1792 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1794 res_argv[res_argc] = client_id_list->data;
1795 res_argv_lens[res_argc] = idp_len;
1796 res_argv_types[res_argc] = res_argc + 3;
1799 /* Found the client, join it to the channel */
1800 client = (SilcClientEntry)id_cache->context;
1801 chu = silc_calloc(1, sizeof(*chu));
1802 chu->client = client;
1804 silc_list_add(channel->clients, chu);
1806 silc_free(client_id);
1810 silc_buffer_pull(client_id_list, idp_len);
1811 silc_buffer_pull(client_mode_list, 4);
1814 /* Query the client information from server if the list included clients
1815 that we don't know about. */
1819 /* Send the WHOIS command to server */
1820 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1821 silc_client_command_reply_whois_i, 0,
1823 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1824 res_argc, res_argv, res_argv_lens,
1825 res_argv_types, conn->cmd_ident);
1826 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1827 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1830 /* Register pending command callback. After we've received the WHOIS
1831 command reply we will reprocess this command reply by re-calling this
1832 USERS command reply callback. */
1833 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1834 NULL, silc_client_command_reply_users, cmd);
1836 silc_buffer_free(res_cmd);
1838 silc_free(channel_id);
1840 silc_free(res_argv);
1841 silc_free(res_argv_lens);
1842 silc_free(res_argv_types);
1846 /* Notify application */
1847 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1850 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1851 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1852 silc_client_command_reply_free(cmd);
1853 silc_free(channel_id);
1855 silc_buffer_free(client_id_list);
1856 if (client_mode_list)
1857 silc_buffer_free(client_mode_list);
1860 /* Received command reply to GETKEY command. WE've received the remote
1861 client's public key. */
1863 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1865 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1866 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1867 SilcCommandStatus status;
1868 SilcIDCacheEntry id_cache;
1869 SilcIDPayload idp = NULL;
1870 SilcClientID *client_id = NULL;
1871 SilcClientEntry client_entry;
1872 SilcServerID *server_id = NULL;
1873 SilcServerEntry server_entry;
1875 unsigned char *tmp, *pk;
1879 SilcPublicKey public_key = NULL;
1881 SILC_LOG_DEBUG(("Start"));
1883 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1884 SILC_GET16_MSB(status, tmp);
1885 if (status != SILC_STATUS_OK) {
1886 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1887 "%s", silc_client_command_status_message(status));
1888 COMMAND_REPLY_ERROR;
1892 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1894 COMMAND_REPLY_ERROR;
1897 idp = silc_id_payload_parse(tmp, len);
1899 COMMAND_REPLY_ERROR;
1903 /* Get the public key payload */
1904 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1906 /* Decode the public key */
1907 SILC_GET16_MSB(pk_len, tmp);
1908 SILC_GET16_MSB(type, tmp + 2);
1911 if (type != SILC_SKE_PK_TYPE_SILC) {
1912 COMMAND_REPLY_ERROR;
1916 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1917 COMMAND_REPLY_ERROR;
1922 id_type = silc_id_payload_get_type(idp);
1923 if (id_type == SILC_ID_CLIENT) {
1924 /* Received client's public key */
1925 client_id = silc_id_payload_get_id(idp);
1926 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1929 silc_hash_client_id_compare, NULL,
1931 COMMAND_REPLY_ERROR;
1935 client_entry = (SilcClientEntry)id_cache->context;
1937 /* Notify application */
1938 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1939 } else if (id_type == SILC_ID_SERVER) {
1940 /* Received server's public key */
1941 server_id = silc_id_payload_get_id(idp);
1942 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1944 COMMAND_REPLY_ERROR;
1948 server_entry = (SilcServerEntry)id_cache->context;
1950 /* Notify application */
1951 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1955 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1956 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1958 silc_id_payload_free(idp);
1960 silc_pkcs_public_key_free(public_key);
1961 silc_free(client_id);
1962 silc_free(server_id);
1963 silc_client_command_reply_free(cmd);
1966 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1968 silc_client_command_reply_free(context);
1972 /******************************************************************************
1974 Internal command reply functions
1976 ******************************************************************************/
1978 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1980 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1981 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1982 SilcCommandStatus status;
1984 SILC_LOG_DEBUG(("Start"));
1986 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1987 if (status != SILC_STATUS_OK &&
1988 status != SILC_STATUS_LIST_START &&
1989 status != SILC_STATUS_LIST_ITEM &&
1990 status != SILC_STATUS_LIST_END)
1993 /* Save WHOIS info */
1994 silc_client_command_reply_whois_save(cmd, status, FALSE);
1996 /* Pending callbacks are not executed if this was an list entry */
1997 if (status != SILC_STATUS_OK &&
1998 status != SILC_STATUS_LIST_END) {
1999 silc_client_command_reply_free(cmd);
2004 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
2005 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
2007 /* If we received notify for invalid ID we'll remove the ID if we
2009 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2010 SilcClientEntry client_entry;
2012 unsigned char *tmp =
2013 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2016 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
2018 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2021 silc_client_del_client(cmd->client, conn, client_entry);
2022 silc_free(client_id);
2027 /* Unregister this command reply */
2028 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2029 NULL, silc_client_command_reply_whois_i,
2032 silc_client_command_reply_free(cmd);
2035 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2037 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2038 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2039 SilcCommandStatus status;
2041 SILC_LOG_DEBUG(("Start"));
2043 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
2044 if (status != SILC_STATUS_OK &&
2045 status != SILC_STATUS_LIST_START &&
2046 status != SILC_STATUS_LIST_ITEM &&
2047 status != SILC_STATUS_LIST_END)
2050 /* Save IDENTIFY info */
2051 silc_client_command_reply_identify_save(cmd, status, FALSE);
2053 /* Pending callbacks are not executed if this was an list entry */
2054 if (status != SILC_STATUS_OK &&
2055 status != SILC_STATUS_LIST_END) {
2056 silc_client_command_reply_free(cmd);
2061 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2062 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
2064 /* If we received notify for invalid ID we'll remove the ID if we
2066 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2067 SilcClientEntry client_entry;
2069 unsigned char *tmp =
2070 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2073 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
2075 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2078 silc_client_del_client(cmd->client, conn, client_entry);
2079 silc_free(client_id);
2084 /* Unregister this command reply */
2085 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2086 NULL, silc_client_command_reply_identify_i,
2089 silc_client_command_reply_free(cmd);
2092 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2094 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2095 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2096 SilcCommandStatus status;
2098 SilcIDCacheEntry id_cache;
2099 SilcServerEntry server;
2100 SilcServerID *server_id = NULL;
2101 char *server_name, *server_info;
2104 SILC_LOG_DEBUG(("Start"));
2106 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
2107 SILC_GET16_MSB(status, tmp);
2108 if (status != SILC_STATUS_OK)
2112 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2116 server_id = silc_id_payload_parse_id(tmp, len);
2120 /* Get server name */
2121 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2125 /* Get server info */
2126 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2130 /* See whether we have this server cached. If not create it. */
2131 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
2133 SILC_LOG_DEBUG(("New server entry"));
2134 server = silc_calloc(1, sizeof(*server));
2135 server->server_name = strdup(server_name);
2136 server->server_info = strdup(server_info);
2137 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
2139 /* Add it to the cache */
2140 silc_idcache_add(conn->server_cache, server->server_name,
2141 server->server_id, (void *)server, 0, NULL);
2145 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2146 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
2147 silc_free(server_id);
2148 silc_client_command_reply_free(cmd);