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(
622 conn, SILC_CLIENT_MESSAGE_ERROR,
623 "Cannot set nickname: bad reply to command");
628 /* Take received Client ID */
629 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
630 idp = silc_id_payload_parse(tmp, len);
635 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
637 /* Notify application */
638 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
639 COMMAND_REPLY((ARGS, conn->local_entry));
640 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
641 silc_client_command_reply_free(cmd);
645 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
646 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
647 silc_client_command_reply_free(cmd);
650 /* Received reply to the LIST command. */
652 SILC_CLIENT_CMD_REPLY_FUNC(list)
654 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
655 SilcCommandStatus status;
656 unsigned char *tmp, *name, *topic;
657 uint32 usercount = 0;
659 COMMAND_CHECK_STATUS_LIST;
661 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
662 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
663 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
665 SILC_GET32_MSB(usercount, tmp);
667 /* Notify application */
668 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
670 /* Pending callbacks are not executed if this was an list entry */
671 if (status != SILC_STATUS_OK &&
672 status != SILC_STATUS_LIST_END) {
673 silc_client_command_reply_free(cmd);
678 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
679 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
680 silc_client_command_reply_free(cmd);
683 /* Received reply to topic command. */
685 SILC_CLIENT_CMD_REPLY_FUNC(topic)
687 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
688 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
689 SilcCommandStatus status;
690 SilcChannelEntry channel;
691 SilcChannelID *channel_id = NULL;
692 SilcIDCacheEntry id_cache = NULL;
697 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
698 if (status != SILC_STATUS_OK) {
699 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
700 "%s", silc_client_command_status_message(status));
705 argc = silc_argument_get_arg_num(cmd->args);
706 if (argc < 1 || argc > 3) {
711 /* Take Channel ID */
712 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
717 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
721 channel_id = silc_id_payload_parse_id(tmp, len);
725 /* Get the channel entry */
726 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
728 silc_free(channel_id);
733 channel = (SilcChannelEntry)id_cache->context;
735 /* Notify application */
736 COMMAND_REPLY((ARGS, channel, topic));
739 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
740 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
741 silc_client_command_reply_free(cmd);
744 /* Received reply to invite command. */
746 SILC_CLIENT_CMD_REPLY_FUNC(invite)
748 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
749 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
750 SilcCommandStatus status;
751 SilcChannelEntry channel;
752 SilcChannelID *channel_id;
753 SilcIDCacheEntry id_cache;
757 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
758 SILC_GET16_MSB(status, tmp);
759 if (status != SILC_STATUS_OK) {
760 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
761 "%s", silc_client_command_status_message(status));
766 /* Take Channel ID */
767 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
771 channel_id = silc_id_payload_parse_id(tmp, len);
775 /* Get the channel entry */
776 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
778 silc_free(channel_id);
783 channel = (SilcChannelEntry)id_cache->context;
785 /* Get the invite list */
786 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
788 /* Notify application */
789 COMMAND_REPLY((ARGS, channel, tmp));
792 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
793 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
794 silc_client_command_reply_free(cmd);
797 /* Received reply to the KILL command. */
799 SILC_CLIENT_CMD_REPLY_FUNC(kill)
801 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
802 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
803 SilcCommandStatus status;
805 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
806 if (status != SILC_STATUS_OK) {
807 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
808 "%s", silc_client_command_status_message(status));
813 /* Notify application */
814 COMMAND_REPLY((ARGS));
817 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
818 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
819 silc_client_command_reply_free(cmd);
822 /* Received reply to INFO command. We receive the server ID and some
823 information about the server user requested. */
825 SILC_CLIENT_CMD_REPLY_FUNC(info)
827 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
828 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
829 SilcCommandStatus status;
831 SilcIDCacheEntry id_cache;
832 SilcServerEntry server;
833 SilcServerID *server_id = NULL;
834 char *server_name, *server_info;
837 SILC_LOG_DEBUG(("Start"));
839 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
840 SILC_GET16_MSB(status, tmp);
841 if (status != SILC_STATUS_OK) {
842 cmd->client->internal->ops->say(
844 SILC_CLIENT_MESSAGE_ERROR,
846 silc_client_command_status_message(status));
852 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
856 server_id = silc_id_payload_parse_id(tmp, len);
860 /* Get server name */
861 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
865 /* Get server info */
866 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
870 /* See whether we have this server cached. If not create it. */
871 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
873 SILC_LOG_DEBUG(("New server entry"));
875 server = silc_calloc(1, sizeof(*server));
876 server->server_name = strdup(server_name);
877 server->server_info = strdup(server_info);
878 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
880 /* Add it to the cache */
881 silc_idcache_add(conn->server_cache, server->server_name,
882 server->server_id, (void *)server, 0, NULL);
884 server = (SilcServerEntry)id_cache->context;
887 /* Notify application */
888 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
891 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
892 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
893 silc_free(server_id);
894 silc_client_command_reply_free(cmd);
897 /* Received reply to PING command. The reply time is shown to user. */
899 SILC_CLIENT_CMD_REPLY_FUNC(ping)
901 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
902 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
903 SilcCommandStatus status;
906 time_t diff, curtime;
908 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
909 if (status != SILC_STATUS_OK) {
910 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
911 "%s", silc_client_command_status_message(status));
916 curtime = time(NULL);
917 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
918 cmd->packet->src_id_type);
919 if (!id || !conn->ping) {
924 for (i = 0; i < conn->ping_count; i++) {
925 if (!conn->ping[i].dest_id)
927 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
928 diff = curtime - conn->ping[i].start_time;
929 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
930 "Ping reply from %s: %d second%s",
931 conn->ping[i].dest_name, diff,
932 diff == 1 ? "" : "s");
934 conn->ping[i].start_time = 0;
935 silc_free(conn->ping[i].dest_id);
936 conn->ping[i].dest_id = NULL;
937 silc_free(conn->ping[i].dest_name);
938 conn->ping[i].dest_name = NULL;
945 /* Notify application */
946 COMMAND_REPLY((ARGS));
949 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
950 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
951 silc_client_command_reply_free(cmd);
954 /* Received reply for JOIN command. */
956 SILC_CLIENT_CMD_REPLY_FUNC(join)
958 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
959 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
960 SilcCommandStatus status;
961 SilcIDPayload idp = NULL;
962 SilcChannelEntry channel;
963 SilcIDCacheEntry id_cache = NULL;
965 uint32 argc, mode, len, list_count;
966 char *topic, *tmp, *channel_name = NULL, *hmac;
967 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
970 SILC_LOG_DEBUG(("Start"));
972 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
973 if (status != SILC_STATUS_OK) {
974 if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
975 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
976 "%s", silc_client_command_status_message(status));
981 argc = silc_argument_get_arg_num(cmd->args);
982 if (argc < 7 || argc > 14) {
983 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
984 "Cannot join channel: Bad reply packet");
989 /* Get channel name */
990 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
992 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
993 "Cannot join channel: Bad reply packet");
997 channel_name = strdup(tmp);
1000 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1002 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1003 "Cannot join channel: Bad reply packet");
1004 COMMAND_REPLY_ERROR;
1005 silc_free(channel_name);
1008 idp = silc_id_payload_parse(tmp, len);
1010 COMMAND_REPLY_ERROR;
1011 silc_free(channel_name);
1015 /* Get channel mode */
1016 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1018 SILC_GET32_MSB(mode, tmp);
1022 /* Get channel key */
1023 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1025 keyp = silc_buffer_alloc(len);
1026 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1027 silc_buffer_put(keyp, tmp, len);
1031 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1033 /* If we have the channel entry, remove it and create a new one */
1034 channel = silc_client_get_channel(cmd->client, conn, channel_name);
1036 silc_client_del_channel(cmd->client, conn, channel);
1038 /* Save received Channel ID. This actually creates the channel */
1039 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
1041 silc_id_payload_free(idp);
1043 conn->current_channel = channel;
1046 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1048 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1049 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1050 "Cannot join channel: Unsupported HMAC `%s'",
1052 COMMAND_REPLY_ERROR;
1053 silc_free(channel_name);
1058 /* Get the list count */
1059 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1062 SILC_GET32_MSB(list_count, tmp);
1064 /* Get Client ID list */
1065 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1069 client_id_list = silc_buffer_alloc(len);
1070 silc_buffer_pull_tail(client_id_list, len);
1071 silc_buffer_put(client_id_list, tmp, len);
1073 /* Get client mode list */
1074 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1078 client_mode_list = silc_buffer_alloc(len);
1079 silc_buffer_pull_tail(client_mode_list, len);
1080 silc_buffer_put(client_mode_list, tmp, len);
1082 /* Add clients we received in the reply to the channel */
1083 for (i = 0; i < list_count; i++) {
1086 SilcClientID *client_id;
1087 SilcClientEntry client_entry;
1090 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1092 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1097 SILC_GET32_MSB(mode, client_mode_list->data);
1099 /* Check if we have this client cached already. */
1100 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1103 silc_hash_client_id_compare, NULL,
1105 /* No, we don't have it, add entry for it. */
1107 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1108 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1110 /* Yes, we have it already */
1111 client_entry = (SilcClientEntry)id_cache->context;
1114 /* Join the client to the channel */
1115 chu = silc_calloc(1, sizeof(*chu));
1116 chu->client = client_entry;
1118 silc_list_add(channel->clients, chu);
1119 silc_free(client_id);
1121 silc_buffer_pull(client_id_list, idp_len);
1122 silc_buffer_pull(client_mode_list, 4);
1124 silc_buffer_push(client_id_list, client_id_list->data -
1125 client_id_list->head);
1126 silc_buffer_push(client_mode_list, client_mode_list->data -
1127 client_mode_list->head);
1129 /* Save channel key */
1130 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1131 silc_client_save_channel_key(conn, keyp, channel);
1133 /* Client is now joined to the channel */
1134 channel->on_channel = TRUE;
1136 /* Notify application */
1137 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1138 keyp ? keyp->head : NULL, NULL,
1139 NULL, topic, hmac, list_count, client_id_list,
1143 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1144 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1145 silc_client_command_reply_free(cmd);
1148 silc_buffer_free(keyp);
1150 silc_buffer_free(client_id_list);
1151 if (client_mode_list)
1152 silc_buffer_free(client_mode_list);
1155 /* Received reply for MOTD command */
1157 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1159 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1160 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1161 SilcCommandStatus status;
1164 char *motd = NULL, *cp, line[256];
1166 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1167 SILC_GET16_MSB(status, tmp);
1168 if (status != SILC_STATUS_OK) {
1169 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1170 "%s", silc_client_command_status_message(status));
1171 COMMAND_REPLY_ERROR;
1175 argc = silc_argument_get_arg_num(cmd->args);
1177 COMMAND_REPLY_ERROR;
1182 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1184 COMMAND_REPLY_ERROR;
1191 if (cp[i++] == '\n') {
1192 memset(line, 0, sizeof(line));
1193 strncat(line, cp, i - 1);
1199 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1209 /* Notify application */
1210 COMMAND_REPLY((ARGS, motd));
1213 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1214 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1215 silc_client_command_reply_free(cmd);
1218 /* Received reply tot he UMODE command. Save the current user mode */
1220 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1222 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1223 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1224 SilcCommandStatus status;
1228 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1229 SILC_GET16_MSB(status, tmp);
1230 if (status != SILC_STATUS_OK) {
1231 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1232 "%s", silc_client_command_status_message(status));
1233 COMMAND_REPLY_ERROR;
1237 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1239 COMMAND_REPLY_ERROR;
1243 SILC_GET32_MSB(mode, tmp);
1244 conn->local_entry->mode = mode;
1246 /* Notify application */
1247 COMMAND_REPLY((ARGS, mode));
1250 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1251 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1252 silc_client_command_reply_free(cmd);
1255 /* Received reply for CMODE command. */
1257 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1259 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1260 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1261 SilcCommandStatus status;
1264 SilcIDCacheEntry id_cache;
1265 SilcChannelID *channel_id;
1266 SilcChannelEntry channel;
1269 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1270 if (status != SILC_STATUS_OK) {
1271 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1272 "%s", silc_client_command_status_message(status));
1273 COMMAND_REPLY_ERROR;
1277 /* Take Channel ID */
1278 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1281 channel_id = silc_id_payload_parse_id(tmp, len);
1285 /* Get the channel entry */
1286 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1288 silc_free(channel_id);
1289 COMMAND_REPLY_ERROR;
1293 channel = (SilcChannelEntry)id_cache->context;
1295 /* Get channel mode */
1296 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1298 silc_free(channel_id);
1299 COMMAND_REPLY_ERROR;
1304 SILC_GET32_MSB(mode, tmp);
1305 channel->mode = mode;
1307 /* Notify application */
1308 COMMAND_REPLY((ARGS, channel, mode));
1310 silc_free(channel_id);
1313 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1314 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1315 silc_client_command_reply_free(cmd);
1318 /* Received reply for CUMODE command */
1320 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1322 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1323 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1324 SilcCommandStatus status;
1325 SilcIDCacheEntry id_cache = NULL;
1326 SilcClientID *client_id;
1327 SilcChannelID *channel_id;
1328 SilcClientEntry client_entry;
1329 SilcChannelEntry channel;
1330 SilcChannelUser chu;
1331 unsigned char *modev, *tmp, *id;
1334 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1335 if (status != SILC_STATUS_OK) {
1336 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1337 "%s", silc_client_command_status_message(status));
1338 COMMAND_REPLY_ERROR;
1342 /* Get channel mode */
1343 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1345 COMMAND_REPLY_ERROR;
1349 /* Take Channel ID */
1350 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1353 channel_id = silc_id_payload_parse_id(tmp, len);
1357 /* Get the channel entry */
1358 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1360 silc_free(channel_id);
1361 COMMAND_REPLY_ERROR;
1365 channel = (SilcChannelEntry)id_cache->context;
1368 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1370 silc_free(channel_id);
1371 COMMAND_REPLY_ERROR;
1374 client_id = silc_id_payload_parse_id(id, len);
1376 silc_free(channel_id);
1377 COMMAND_REPLY_ERROR;
1381 /* Get client entry */
1382 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1384 silc_hash_client_id_compare, NULL,
1386 silc_free(channel_id);
1387 silc_free(client_id);
1388 COMMAND_REPLY_ERROR;
1392 client_entry = (SilcClientEntry)id_cache->context;
1395 SILC_GET32_MSB(mode, modev);
1396 silc_list_start(channel->clients);
1397 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1398 if (chu->client == client_entry) {
1404 /* Notify application */
1405 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1406 silc_free(client_id);
1407 silc_free(channel_id);
1410 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1411 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1412 silc_client_command_reply_free(cmd);
1415 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1417 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1418 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1419 SilcCommandStatus status;
1422 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1423 SILC_GET16_MSB(status, tmp);
1424 if (status != SILC_STATUS_OK) {
1425 cmd->client->internal->ops->say(
1426 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1427 "%s", silc_client_command_status_message(status));
1428 COMMAND_REPLY_ERROR;
1432 /* Notify application */
1433 COMMAND_REPLY((ARGS));
1436 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1437 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1438 silc_client_command_reply_free(cmd);
1441 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1443 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1444 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1445 SilcCommandStatus status;
1448 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1449 SILC_GET16_MSB(status, tmp);
1450 if (status != SILC_STATUS_OK) {
1451 cmd->client->internal->ops->say(
1452 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1453 "%s", silc_client_command_status_message(status));
1454 COMMAND_REPLY_ERROR;
1458 /* Notify application */
1459 COMMAND_REPLY((ARGS));
1462 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1463 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1464 silc_client_command_reply_free(cmd);
1467 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1469 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1470 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1471 SilcCommandStatus status;
1474 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1475 SILC_GET16_MSB(status, tmp);
1476 if (status != SILC_STATUS_OK) {
1477 cmd->client->internal->ops->say(
1479 SILC_CLIENT_MESSAGE_ERROR,
1480 "%s", silc_client_command_status_message(status));
1481 COMMAND_REPLY_ERROR;
1485 /* Notify application */
1486 COMMAND_REPLY((ARGS));
1489 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1490 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1491 silc_client_command_reply_free(cmd);
1494 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1496 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1497 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1498 SilcCommandStatus status;
1501 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1502 SILC_GET16_MSB(status, tmp);
1503 if (status != SILC_STATUS_OK) {
1504 cmd->client->internal->ops->say(
1505 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1506 "%s", silc_client_command_status_message(status));
1507 COMMAND_REPLY_ERROR;
1511 /* Notify application */
1512 COMMAND_REPLY((ARGS));
1515 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1516 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1517 silc_client_command_reply_free(cmd);
1520 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1522 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1523 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1524 SilcCommandStatus status;
1525 SilcIDCacheEntry id_cache = NULL;
1526 SilcChannelEntry channel;
1527 SilcChannelID *channel_id;
1531 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1532 SILC_GET16_MSB(status, tmp);
1533 if (status != SILC_STATUS_OK) {
1534 cmd->client->internal->ops->say(
1535 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1536 "%s", silc_client_command_status_message(status));
1537 COMMAND_REPLY_ERROR;
1541 /* Take Channel ID */
1542 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1546 channel_id = silc_id_payload_parse_id(tmp, len);
1550 /* Get the channel entry */
1551 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1553 silc_free(channel_id);
1554 COMMAND_REPLY_ERROR;
1558 channel = (SilcChannelEntry)id_cache->context;
1560 /* Get the ban list */
1561 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1563 /* Notify application */
1564 COMMAND_REPLY((ARGS, channel, tmp));
1567 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1568 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1569 silc_client_command_reply_free(cmd);
1572 SILC_CLIENT_CMD_REPLY_FUNC(close)
1574 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1575 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1576 SilcCommandStatus status;
1579 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1580 SILC_GET16_MSB(status, tmp);
1581 if (status != SILC_STATUS_OK) {
1582 cmd->client->internal->ops->say(
1583 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1584 "%s", silc_client_command_status_message(status));
1585 COMMAND_REPLY_ERROR;
1589 /* Notify application */
1590 COMMAND_REPLY((ARGS));
1593 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1594 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1595 silc_client_command_reply_free(cmd);
1598 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1600 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1601 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1602 SilcCommandStatus status;
1605 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1606 SILC_GET16_MSB(status, tmp);
1607 if (status != SILC_STATUS_OK) {
1608 cmd->client->internal->ops->say(
1609 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1610 "%s", silc_client_command_status_message(status));
1611 COMMAND_REPLY_ERROR;
1615 /* Notify application */
1616 COMMAND_REPLY((ARGS));
1619 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1620 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1621 silc_client_command_reply_free(cmd);
1624 /* Reply to LEAVE command. */
1626 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1628 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1629 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1630 SilcCommandStatus status;
1633 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1634 SILC_GET16_MSB(status, tmp);
1635 if (status != SILC_STATUS_OK) {
1636 cmd->client->internal->ops->say(
1637 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1638 "%s", silc_client_command_status_message(status));
1639 COMMAND_REPLY_ERROR;
1643 /* Notify application */
1644 COMMAND_REPLY((ARGS));
1647 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1648 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1649 silc_client_command_reply_free(cmd);
1652 /* Reply to USERS command. Received list of client ID's and theirs modes
1653 on the channel we requested. */
1655 SILC_CLIENT_CMD_REPLY_FUNC(users)
1657 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1658 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1659 SilcCommandStatus status;
1660 SilcIDCacheEntry id_cache = NULL;
1661 SilcChannelEntry channel;
1662 SilcChannelUser chu;
1663 SilcChannelID *channel_id = NULL;
1664 SilcBuffer client_id_list = NULL;
1665 SilcBuffer client_mode_list = NULL;
1667 uint32 tmp_len, list_count;
1669 unsigned char **res_argv = NULL;
1670 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1672 SILC_LOG_DEBUG(("Start"));
1674 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1675 SILC_GET16_MSB(status, tmp);
1676 if (status != SILC_STATUS_OK) {
1677 cmd->client->internal->ops->say(
1678 cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1679 "%s", silc_client_command_status_message(status));
1680 COMMAND_REPLY_ERROR;
1684 /* Get channel ID */
1685 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1687 COMMAND_REPLY_ERROR;
1690 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1692 COMMAND_REPLY_ERROR;
1696 /* Get the list count */
1697 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1699 COMMAND_REPLY_ERROR;
1702 SILC_GET32_MSB(list_count, tmp);
1704 /* Get Client ID list */
1705 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1707 COMMAND_REPLY_ERROR;
1711 client_id_list = silc_buffer_alloc(tmp_len);
1712 silc_buffer_pull_tail(client_id_list, tmp_len);
1713 silc_buffer_put(client_id_list, tmp, tmp_len);
1715 /* Get client mode list */
1716 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1718 COMMAND_REPLY_ERROR;
1722 client_mode_list = silc_buffer_alloc(tmp_len);
1723 silc_buffer_pull_tail(client_mode_list, tmp_len);
1724 silc_buffer_put(client_mode_list, tmp, tmp_len);
1726 /* Get channel entry */
1727 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1729 /* Resolve the channel from server */
1730 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1732 /* Register pending command callback. After we've received the channel
1733 information we will reprocess this command reply by re-calling this
1734 USERS command reply callback. */
1735 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1736 NULL, silc_client_command_reply_users, cmd);
1739 channel = (SilcChannelEntry)id_cache->context;
1742 /* Remove old client list from channel. */
1743 silc_list_start(channel->clients);
1744 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1745 silc_list_del(channel->clients, chu);
1749 /* Cache the received Client ID's and modes. */
1750 for (i = 0; i < list_count; i++) {
1753 SilcClientID *client_id;
1754 SilcClientEntry client;
1757 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1759 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1764 SILC_GET32_MSB(mode, client_mode_list->data);
1766 /* Check if we have this client cached already. */
1768 silc_idcache_find_by_id_one_ext(conn->client_cache,
1771 silc_hash_client_id_compare, NULL,
1774 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1775 !((SilcClientEntry)id_cache->context)->realname) {
1777 if (id_cache && id_cache->context) {
1778 SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
1779 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1780 silc_buffer_pull(client_id_list, idp_len);
1781 silc_buffer_pull(client_mode_list, 4);
1784 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1787 /* No we don't have it (or it is incomplete in information), query
1788 it from the server. Assemble argument table that will be sent
1789 for the WHOIS command later. */
1790 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1792 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1794 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1796 res_argv[res_argc] = client_id_list->data;
1797 res_argv_lens[res_argc] = idp_len;
1798 res_argv_types[res_argc] = res_argc + 3;
1801 /* Found the client, join it to the channel */
1802 client = (SilcClientEntry)id_cache->context;
1803 chu = silc_calloc(1, sizeof(*chu));
1804 chu->client = client;
1806 silc_list_add(channel->clients, chu);
1808 silc_free(client_id);
1812 silc_buffer_pull(client_id_list, idp_len);
1813 silc_buffer_pull(client_mode_list, 4);
1816 /* Query the client information from server if the list included clients
1817 that we don't know about. */
1821 /* Send the WHOIS command to server */
1822 silc_client_command_register(cmd->client, SILC_COMMAND_WHOIS, NULL, NULL,
1823 silc_client_command_reply_whois_i, 0,
1825 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1826 res_argc, res_argv, res_argv_lens,
1827 res_argv_types, conn->cmd_ident);
1828 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1829 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1832 /* Register pending command callback. After we've received the WHOIS
1833 command reply we will reprocess this command reply by re-calling this
1834 USERS command reply callback. */
1835 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1836 NULL, silc_client_command_reply_users, cmd);
1838 silc_buffer_free(res_cmd);
1840 silc_free(channel_id);
1842 silc_free(res_argv);
1843 silc_free(res_argv_lens);
1844 silc_free(res_argv_types);
1848 /* Notify application */
1849 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1852 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1853 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1854 silc_client_command_reply_free(cmd);
1855 silc_free(channel_id);
1857 silc_buffer_free(client_id_list);
1858 if (client_mode_list)
1859 silc_buffer_free(client_mode_list);
1862 /* Received command reply to GETKEY command. WE've received the remote
1863 client's public key. */
1865 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1867 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1868 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1869 SilcCommandStatus status;
1870 SilcIDCacheEntry id_cache;
1871 SilcIDPayload idp = NULL;
1872 SilcClientID *client_id = NULL;
1873 SilcClientEntry client_entry;
1874 SilcServerID *server_id = NULL;
1875 SilcServerEntry server_entry;
1877 unsigned char *tmp, *pk;
1881 SilcPublicKey public_key = NULL;
1883 SILC_LOG_DEBUG(("Start"));
1885 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1886 SILC_GET16_MSB(status, tmp);
1887 if (status != SILC_STATUS_OK) {
1888 cmd->client->internal->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1889 "%s", silc_client_command_status_message(status));
1890 COMMAND_REPLY_ERROR;
1894 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1896 COMMAND_REPLY_ERROR;
1899 idp = silc_id_payload_parse(tmp, len);
1901 COMMAND_REPLY_ERROR;
1905 /* Get the public key payload */
1906 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1908 /* Decode the public key */
1909 SILC_GET16_MSB(pk_len, tmp);
1910 SILC_GET16_MSB(type, tmp + 2);
1913 if (type != SILC_SKE_PK_TYPE_SILC) {
1914 COMMAND_REPLY_ERROR;
1918 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1919 COMMAND_REPLY_ERROR;
1924 id_type = silc_id_payload_get_type(idp);
1925 if (id_type == SILC_ID_CLIENT) {
1926 /* Received client's public key */
1927 client_id = silc_id_payload_get_id(idp);
1928 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1931 silc_hash_client_id_compare, NULL,
1933 COMMAND_REPLY_ERROR;
1937 client_entry = (SilcClientEntry)id_cache->context;
1939 /* Notify application */
1940 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1941 } else if (id_type == SILC_ID_SERVER) {
1942 /* Received server's public key */
1943 server_id = silc_id_payload_get_id(idp);
1944 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1946 COMMAND_REPLY_ERROR;
1950 server_entry = (SilcServerEntry)id_cache->context;
1952 /* Notify application */
1953 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1957 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1958 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1960 silc_id_payload_free(idp);
1962 silc_pkcs_public_key_free(public_key);
1963 silc_free(client_id);
1964 silc_free(server_id);
1965 silc_client_command_reply_free(cmd);
1968 SILC_CLIENT_CMD_REPLY_FUNC(quit)
1970 silc_client_command_reply_free(context);
1974 /******************************************************************************
1976 Internal command reply functions
1978 ******************************************************************************/
1980 SILC_CLIENT_CMD_REPLY_FUNC(whois_i)
1982 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1983 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1984 SilcCommandStatus status;
1986 SILC_LOG_DEBUG(("Start"));
1988 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1989 if (status != SILC_STATUS_OK &&
1990 status != SILC_STATUS_LIST_START &&
1991 status != SILC_STATUS_LIST_ITEM &&
1992 status != SILC_STATUS_LIST_END)
1995 /* Save WHOIS info */
1996 silc_client_command_reply_whois_save(cmd, status, FALSE);
1998 /* Pending callbacks are not executed if this was an list entry */
1999 if (status != SILC_STATUS_OK &&
2000 status != SILC_STATUS_LIST_END) {
2001 silc_client_command_reply_free(cmd);
2006 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
2007 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
2009 /* If we received notify for invalid ID we'll remove the ID if we
2011 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2012 SilcClientEntry client_entry;
2014 unsigned char *tmp =
2015 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2018 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
2020 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2023 silc_client_del_client(cmd->client, conn, client_entry);
2024 silc_free(client_id);
2029 /* Unregister this command reply */
2030 silc_client_command_unregister(cmd->client, SILC_COMMAND_WHOIS,
2031 NULL, silc_client_command_reply_whois_i,
2034 silc_client_command_reply_free(cmd);
2037 SILC_CLIENT_CMD_REPLY_FUNC(identify_i)
2039 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2040 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2041 SilcCommandStatus status;
2043 SILC_LOG_DEBUG(("Start"));
2045 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
2046 if (status != SILC_STATUS_OK &&
2047 status != SILC_STATUS_LIST_START &&
2048 status != SILC_STATUS_LIST_ITEM &&
2049 status != SILC_STATUS_LIST_END)
2052 /* Save IDENTIFY info */
2053 silc_client_command_reply_identify_save(cmd, status, FALSE);
2055 /* Pending callbacks are not executed if this was an list entry */
2056 if (status != SILC_STATUS_OK &&
2057 status != SILC_STATUS_LIST_END) {
2058 silc_client_command_reply_free(cmd);
2063 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
2064 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
2066 /* If we received notify for invalid ID we'll remove the ID if we
2068 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
2069 SilcClientEntry client_entry;
2071 unsigned char *tmp =
2072 silc_argument_get_arg_type(silc_command_get_args(cmd->payload),
2075 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
2077 client_entry = silc_client_get_client_by_id(cmd->client, conn,
2080 silc_client_del_client(cmd->client, conn, client_entry);
2081 silc_free(client_id);
2086 /* Unregister this command reply */
2087 silc_client_command_unregister(cmd->client, SILC_COMMAND_IDENTIFY,
2088 NULL, silc_client_command_reply_identify_i,
2091 silc_client_command_reply_free(cmd);
2094 SILC_CLIENT_CMD_REPLY_FUNC(info_i)
2096 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
2097 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
2098 SilcCommandStatus status;
2100 SilcIDCacheEntry id_cache;
2101 SilcServerEntry server;
2102 SilcServerID *server_id = NULL;
2103 char *server_name, *server_info;
2106 SILC_LOG_DEBUG(("Start"));
2108 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
2109 SILC_GET16_MSB(status, tmp);
2110 if (status != SILC_STATUS_OK)
2114 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
2118 server_id = silc_id_payload_parse_id(tmp, len);
2122 /* Get server name */
2123 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
2127 /* Get server info */
2128 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
2132 /* See whether we have this server cached. If not create it. */
2133 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
2135 SILC_LOG_DEBUG(("New server entry"));
2136 server = silc_calloc(1, sizeof(*server));
2137 server->server_name = strdup(server_name);
2138 server->server_info = strdup(server_info);
2139 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
2141 /* Add it to the cache */
2142 silc_idcache_add(conn->server_cache, server->server_name,
2143 server->server_id, (void *)server, 0, NULL);
2147 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
2148 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
2149 silc_free(server_id);
2150 silc_client_command_reply_free(cmd);