5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 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.
36 #include "clientlibincludes.h"
37 #include "client_internal.h"
39 /* Client command reply list. */
40 SilcClientCommandReply silc_command_reply_list[] =
42 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
43 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
44 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
45 SILC_CLIENT_CMD_REPLY(nick, NICK),
46 SILC_CLIENT_CMD_REPLY(list, LIST),
47 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
48 SILC_CLIENT_CMD_REPLY(invite, INVITE),
49 SILC_CLIENT_CMD_REPLY(kill, KILL),
50 SILC_CLIENT_CMD_REPLY(info, INFO),
51 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
52 SILC_CLIENT_CMD_REPLY(ping, PING),
53 SILC_CLIENT_CMD_REPLY(oper, OPER),
54 SILC_CLIENT_CMD_REPLY(join, JOIN),
55 SILC_CLIENT_CMD_REPLY(motd, MOTD),
56 SILC_CLIENT_CMD_REPLY(umode, UMODE),
57 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
58 SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
59 SILC_CLIENT_CMD_REPLY(kick, KICK),
60 SILC_CLIENT_CMD_REPLY(ban, BAN),
61 SILC_CLIENT_CMD_REPLY(close, CLOSE),
62 SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN),
63 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
64 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
65 SILC_CLIENT_CMD_REPLY(users, USERS),
66 SILC_CLIENT_CMD_REPLY(getkey, GETKEY),
71 const SilcCommandStatusMessage silc_command_status_messages[] = {
73 { STAT(NO_SUCH_NICK), "There was no such nickname" },
74 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
75 { STAT(NO_SUCH_SERVER), "No such server" },
76 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
77 { STAT(NO_RECIPIENT), "No recipient given" },
78 { STAT(UNKNOWN_COMMAND), "Unknown command" },
79 { STAT(WILDCARDS), "Unknown command" },
80 { STAT(NO_CLIENT_ID), "No Client ID given" },
81 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
82 { STAT(NO_SERVER_ID), "No Server ID given" },
83 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
84 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
85 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
86 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
87 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
88 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
89 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
90 { STAT(USER_ON_CHANNEL), "User already on the channel" },
91 { STAT(NOT_REGISTERED), "You have not registered" },
92 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
93 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
94 { STAT(PERM_DENIED), "Permission denied" },
95 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
96 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
97 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
98 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
99 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
100 { STAT(UNKNOWN_MODE), "Unknown mode" },
101 { STAT(NOT_YOU), "Cannot change mode for other users" },
102 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
103 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
104 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
105 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
106 { STAT(BAD_NICKNAME), "Bad nickname" },
107 { STAT(BAD_CHANNEL), "Bad channel name" },
108 { STAT(AUTH_FAILED), "Authentication failed" },
109 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
110 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
114 /* Command reply operation that is called at the end of all command replys.
115 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
116 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
117 #define ARGS cmd->client, cmd->sock->user_data, \
118 cmd->payload, TRUE, silc_command_get(cmd->payload), status
120 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
121 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
122 cmd->sock->user_data, cmd->payload, FALSE, \
123 silc_command_get(cmd->payload), status)
125 /* All functions that call the COMMAND_CHECK_STATUS or the
126 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
128 #define COMMAND_CHECK_STATUS \
130 SILC_LOG_DEBUG(("Start")); \
131 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
132 if (status != SILC_STATUS_OK) { \
133 COMMAND_REPLY_ERROR; \
138 #define COMMAND_CHECK_STATUS_LIST \
140 SILC_LOG_DEBUG(("Start")); \
141 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
142 if (status != SILC_STATUS_OK && \
143 status != SILC_STATUS_LIST_START && \
144 status != SILC_STATUS_LIST_ITEM && \
145 status != SILC_STATUS_LIST_END) { \
146 COMMAND_REPLY_ERROR; \
151 /* Process received command reply. */
153 void silc_client_command_reply_process(SilcClient client,
154 SilcSocketConnection sock,
155 SilcPacketContext *packet)
157 SilcBuffer buffer = packet->buffer;
158 SilcClientCommandReply *cmd;
159 SilcClientCommandReplyContext ctx;
160 SilcCommandPayload payload;
164 /* Get command reply payload from packet */
165 payload = silc_command_payload_parse(buffer);
167 /* Silently ignore bad reply packet */
168 SILC_LOG_DEBUG(("Bad command reply packet"));
172 /* Allocate command reply context. This must be free'd by the
173 command reply routine receiving it. */
174 ctx = silc_calloc(1, sizeof(*ctx));
175 ctx->client = client;
177 ctx->payload = payload;
178 ctx->args = silc_command_get_args(ctx->payload);
179 ctx->packet = packet;
180 ident = silc_command_get_ident(ctx->payload);
182 /* Check for pending commands and mark to be exeucted */
183 silc_client_command_pending_check(sock->user_data, ctx,
184 silc_command_get(ctx->payload), ident);
186 /* Execute command reply */
187 command = silc_command_get(ctx->payload);
188 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
189 if (cmd->cmd == command)
192 if (cmd == NULL || !cmd->cb) {
200 /* Returns status message string */
202 char *silc_client_command_status_message(SilcCommandStatus status)
206 for (i = 0; silc_command_status_messages[i].message; i++) {
207 if (silc_command_status_messages[i].status == status)
211 if (silc_command_status_messages[i].message == NULL)
214 return silc_command_status_messages[i].message;
217 /* Free command reply context and its internals. */
219 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
222 silc_command_payload_free(cmd->payload);
228 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
229 SilcCommandStatus status)
231 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
232 SilcClientID *client_id;
233 SilcIDCacheEntry id_cache = NULL;
234 SilcClientEntry client_entry = NULL;
237 unsigned char *id_data, *tmp;
238 char *nickname = NULL, *username = NULL;
239 char *realname = NULL;
240 uint32 idle = 0, mode = 0;
241 SilcBuffer channels = NULL;
242 unsigned char *fingerprint;
243 uint32 fingerprint_len;
245 argc = silc_argument_get_arg_num(cmd->args);
247 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
253 client_id = silc_id_payload_parse_id(id_data, len);
259 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
260 username = silc_argument_get_arg_type(cmd->args, 4, &len);
261 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
262 if (!nickname || !username || !realname) {
267 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
269 channels = silc_buffer_alloc(len);
270 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
271 silc_buffer_put(channels, tmp, len);
274 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
276 SILC_GET32_MSB(mode, tmp);
278 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
280 SILC_GET32_MSB(idle, tmp);
282 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
284 /* Check if we have this client cached already. */
285 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
287 silc_hash_client_id_compare, NULL,
289 SILC_LOG_DEBUG(("Adding new client entry"));
291 silc_client_add_client(cmd->client, conn, nickname, username, realname,
294 client_entry = (SilcClientEntry)id_cache->context;
295 silc_client_update_client(cmd->client, conn, client_entry,
296 nickname, username, realname, mode);
297 silc_free(client_id);
300 if (fingerprint && !client_entry->fingerprint) {
301 client_entry->fingerprint =
302 silc_calloc(fingerprint_len,
303 sizeof(*client_entry->fingerprint));
304 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
305 client_entry->fingerprint_len = fingerprint_len;
308 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
309 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
311 /* Notify application */
313 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
314 channels, mode, idle));
317 silc_buffer_free(channels);
320 /* Received reply for WHOIS command. This maybe called several times
321 for one WHOIS command as server may reply with list of results. */
323 SILC_CLIENT_CMD_REPLY_FUNC(whois)
325 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
326 SilcCommandStatus status;
328 COMMAND_CHECK_STATUS_LIST;
330 /* Save WHOIS info */
331 silc_client_command_reply_whois_save(cmd, status);
333 /* Pending callbacks are not executed if this was an list entry */
334 if (status != SILC_STATUS_OK &&
335 status != SILC_STATUS_LIST_END) {
336 silc_client_command_reply_free(cmd);
341 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
342 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
343 silc_client_command_reply_free(cmd);
346 /* Received reply for WHOWAS command. */
348 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
350 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
351 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
352 SilcCommandStatus status;
353 SilcClientID *client_id;
354 SilcIDCacheEntry id_cache = NULL;
355 SilcClientEntry client_entry = NULL;
357 unsigned char *id_data;
358 char *nickname, *username;
359 char *realname = NULL;
361 COMMAND_CHECK_STATUS_LIST;
363 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
369 client_id = silc_id_payload_parse_id(id_data, len);
375 /* Get the client entry, if exists */
376 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
378 silc_hash_client_id_compare, NULL,
380 client_entry = (SilcClientEntry)id_cache->context;
381 silc_free(client_id);
383 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
384 username = silc_argument_get_arg_type(cmd->args, 4, &len);
385 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
386 if (!nickname || !username) {
391 /* Notify application. We don't save any history information to any
392 cache. Just pass the data to the application for displaying on
394 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
396 /* Pending callbacks are not executed if this was an list entry */
397 if (status != SILC_STATUS_OK &&
398 status != SILC_STATUS_LIST_END) {
399 silc_client_command_reply_free(cmd);
404 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
405 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS);
406 silc_client_command_reply_free(cmd);
410 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
411 SilcCommandStatus status)
413 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
414 SilcClient client = cmd->client;
415 SilcClientID *client_id = NULL;
416 SilcServerID *server_id = NULL;
417 SilcChannelID *channel_id = NULL;
418 SilcIDCacheEntry id_cache = NULL;
419 SilcClientEntry client_entry;
420 SilcServerEntry server_entry;
421 SilcChannelEntry channel_entry;
424 unsigned char *id_data;
425 char *name = NULL, *info = NULL;
426 SilcIDPayload idp = NULL;
429 argc = silc_argument_get_arg_num(cmd->args);
431 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
436 idp = silc_id_payload_parse_data(id_data, len);
442 name = silc_argument_get_arg_type(cmd->args, 3, &len);
443 info = silc_argument_get_arg_type(cmd->args, 4, &len);
445 id_type = silc_id_payload_get_type(idp);
449 client_id = silc_id_payload_get_id(idp);
451 SILC_LOG_DEBUG(("Received client information"));
453 /* Check if we have this client cached already. */
454 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
457 silc_hash_client_id_compare, NULL,
459 SILC_LOG_DEBUG(("Adding new client entry"));
461 silc_client_add_client(cmd->client, conn, name, info, NULL,
462 silc_id_dup(client_id, id_type), 0);
464 client_entry = (SilcClientEntry)id_cache->context;
465 silc_client_update_client(cmd->client, conn, client_entry,
466 name, info, NULL, 0);
469 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
470 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
472 /* Notify application */
473 COMMAND_REPLY((ARGS, client_entry, name, info));
477 server_id = silc_id_payload_get_id(idp);
479 SILC_LOG_DEBUG(("Received server information"));
481 /* Check if we have this server cached already. */
482 if (!silc_idcache_find_by_id_one(conn->server_cache,
483 (void *)server_id, &id_cache)) {
484 SILC_LOG_DEBUG(("Adding new server entry"));
486 server_entry = silc_calloc(1, sizeof(*server_entry));
487 server_entry->server_id = silc_id_dup(server_id, id_type);
489 server_entry->server_name = strdup(name);
491 server_entry->server_info = strdup(info);
493 /* Add server to cache */
494 silc_idcache_add(conn->server_cache, server_entry->server_name,
495 server_entry->server_id, (void *)server_entry, FALSE);
497 server_entry = (SilcServerEntry)id_cache->context;
500 /* Notify application */
501 COMMAND_REPLY((ARGS, server_entry, name, info));
504 case SILC_ID_CHANNEL:
505 channel_id = silc_id_payload_get_id(idp);
507 SILC_LOG_DEBUG(("Received channel information"));
509 /* Check if we have this channel cached already. */
510 if (!silc_idcache_find_by_id_one(conn->channel_cache,
511 (void *)channel_id, &id_cache)) {
515 SILC_LOG_DEBUG(("Adding new channel entry"));
516 channel_entry = silc_client_new_channel_id(client, conn->sock,
517 strdup(name), 0, idp);
519 channel_entry = (SilcChannelEntry)id_cache->context;
522 /* Notify application */
523 COMMAND_REPLY((ARGS, channel_entry, name, info));
527 silc_id_payload_free(idp);
528 silc_free(client_id);
529 silc_free(server_id);
530 silc_free(channel_id);
533 /* Received reply for IDENTIFY command. This maybe called several times
534 for one IDENTIFY command as server may reply with list of results.
535 This is totally silent and does not print anything on screen. */
537 SILC_CLIENT_CMD_REPLY_FUNC(identify)
539 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
540 SilcCommandStatus status;
542 COMMAND_CHECK_STATUS_LIST;
544 /* Save IDENTIFY info */
545 silc_client_command_reply_identify_save(cmd, status);
547 /* Pending callbacks are not executed if this was an list entry */
548 if (status != SILC_STATUS_OK &&
549 status != SILC_STATUS_LIST_END) {
550 silc_client_command_reply_free(cmd);
555 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
556 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
557 silc_client_command_reply_free(cmd);
560 /* Received reply for command NICK. If everything went without errors
561 we just received our new Client ID. */
563 SILC_CLIENT_CMD_REPLY_FUNC(nick)
565 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
566 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
567 SilcCommandStatus status;
572 SILC_LOG_DEBUG(("Start"));
574 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
575 if (status != SILC_STATUS_OK) {
576 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
577 "Cannot set nickname: %s",
578 silc_client_command_status_message(status));
583 argc = silc_argument_get_arg_num(cmd->args);
584 if (argc < 2 || argc > 2) {
585 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
586 "Cannot set nickname: bad reply to command");
591 /* Take received Client ID */
592 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
593 idp = silc_id_payload_parse_data(tmp, len);
598 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
600 /* Notify application */
601 COMMAND_REPLY((ARGS, conn->local_entry));
604 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
605 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
606 silc_client_command_reply_free(cmd);
609 /* Received reply to the LIST command. */
611 SILC_CLIENT_CMD_REPLY_FUNC(list)
613 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
614 SilcCommandStatus status;
615 unsigned char *tmp, *name, *topic;
616 uint32 usercount = 0;
618 COMMAND_CHECK_STATUS_LIST;
620 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
621 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
622 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
624 SILC_GET32_MSB(usercount, tmp);
626 /* Notify application */
627 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
629 /* Pending callbacks are not executed if this was an list entry */
630 if (status != SILC_STATUS_OK &&
631 status != SILC_STATUS_LIST_END) {
632 silc_client_command_reply_free(cmd);
637 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
638 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
639 silc_client_command_reply_free(cmd);
642 /* Received reply to topic command. */
644 SILC_CLIENT_CMD_REPLY_FUNC(topic)
646 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
647 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
648 SilcCommandStatus status;
649 SilcChannelEntry channel;
650 SilcChannelID *channel_id = NULL;
651 SilcIDCacheEntry id_cache = NULL;
656 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
657 if (status != SILC_STATUS_OK) {
658 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
659 "%s", silc_client_command_status_message(status));
664 argc = silc_argument_get_arg_num(cmd->args);
665 if (argc < 1 || argc > 3) {
670 /* Take Channel ID */
671 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
676 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
680 channel_id = silc_id_payload_parse_id(tmp, len);
684 /* Get the channel entry */
685 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
687 silc_free(channel_id);
692 channel = (SilcChannelEntry)id_cache->context;
694 /* Notify application */
695 COMMAND_REPLY((ARGS, channel, topic));
698 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
699 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
700 silc_client_command_reply_free(cmd);
703 /* Received reply to invite command. */
705 SILC_CLIENT_CMD_REPLY_FUNC(invite)
707 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
708 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
709 SilcCommandStatus status;
710 SilcChannelEntry channel;
711 SilcChannelID *channel_id;
712 SilcIDCacheEntry id_cache;
716 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
717 SILC_GET16_MSB(status, tmp);
718 if (status != SILC_STATUS_OK) {
719 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
720 "%s", silc_client_command_status_message(status));
725 /* Take Channel ID */
726 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
730 channel_id = silc_id_payload_parse_id(tmp, len);
734 /* Get the channel entry */
735 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
737 silc_free(channel_id);
742 channel = (SilcChannelEntry)id_cache->context;
744 /* Get the invite list */
745 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
747 /* Notify application */
748 COMMAND_REPLY((ARGS, channel, tmp));
751 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
752 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
753 silc_client_command_reply_free(cmd);
756 /* Received reply to the KILL command. */
758 SILC_CLIENT_CMD_REPLY_FUNC(kill)
760 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
761 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
762 SilcCommandStatus status;
764 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
765 if (status != SILC_STATUS_OK) {
766 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
767 "%s", silc_client_command_status_message(status));
772 /* Notify application */
773 COMMAND_REPLY((ARGS));
776 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
777 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
778 silc_client_command_reply_free(cmd);
781 /* Received reply to INFO command. We receive the server ID and some
782 information about the server user requested. */
784 SILC_CLIENT_CMD_REPLY_FUNC(info)
786 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
787 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
788 SilcCommandStatus status;
790 SilcIDCacheEntry id_cache;
791 SilcServerEntry server;
792 SilcServerID *server_id = NULL;
793 char *server_name, *server_info;
796 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
797 SILC_GET16_MSB(status, tmp);
798 if (status != SILC_STATUS_OK) {
799 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
800 "%s", silc_client_command_status_message(status));
806 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
810 server_id = silc_id_payload_parse_id(tmp, len);
814 /* Get server name */
815 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
819 /* Get server info */
820 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
824 /* See whether we have this server cached. If not create it. */
825 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
827 SILC_LOG_DEBUG(("New server entry"));
829 server = silc_calloc(1, sizeof(*server));
830 server->server_name = strdup(server_name);
831 server->server_info = strdup(server_info);
832 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
834 /* Add it to the cache */
835 silc_idcache_add(conn->server_cache, server->server_name,
836 server->server_id, (void *)server, FALSE);
838 server = (SilcServerEntry)id_cache->context;
841 /* Notify application */
842 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
845 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
846 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
847 silc_free(server_id);
848 silc_client_command_reply_free(cmd);
851 /* Received reply to PING command. The reply time is shown to user. */
853 SILC_CLIENT_CMD_REPLY_FUNC(ping)
855 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
856 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
857 SilcCommandStatus status;
860 time_t diff, curtime;
862 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
863 if (status != SILC_STATUS_OK) {
864 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
865 "%s", silc_client_command_status_message(status));
870 curtime = time(NULL);
871 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
872 cmd->packet->src_id_type);
878 for (i = 0; i < conn->ping_count; i++) {
879 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
880 diff = curtime - conn->ping[i].start_time;
881 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
882 "Ping reply from %s: %d second%s",
883 conn->ping[i].dest_name, diff,
884 diff == 1 ? "" : "s");
886 conn->ping[i].start_time = 0;
887 silc_free(conn->ping[i].dest_id);
888 conn->ping[i].dest_id = NULL;
889 silc_free(conn->ping[i].dest_name);
890 conn->ping[i].dest_name = NULL;
897 /* Notify application */
898 COMMAND_REPLY((ARGS));
901 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
902 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
903 silc_client_command_reply_free(cmd);
906 /* Received reply for JOIN command. */
908 SILC_CLIENT_CMD_REPLY_FUNC(join)
910 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
911 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
912 SilcCommandStatus status;
913 SilcIDPayload idp = NULL;
914 SilcChannelEntry channel;
915 SilcIDCacheEntry id_cache = NULL;
917 uint32 argc, mode, len, list_count;
918 char *topic, *tmp, *channel_name = NULL, *hmac;
919 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
922 SILC_LOG_DEBUG(("Start"));
924 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
925 if (status != SILC_STATUS_OK) {
926 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
927 "%s", silc_client_command_status_message(status));
932 argc = silc_argument_get_arg_num(cmd->args);
933 if (argc < 7 || argc > 14) {
934 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
935 "Cannot join channel: Bad reply packet");
940 /* Get channel name */
941 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
943 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
944 "Cannot join channel: Bad reply packet");
948 channel_name = strdup(tmp);
951 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
953 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
954 "Cannot join channel: Bad reply packet");
956 silc_free(channel_name);
959 idp = silc_id_payload_parse_data(tmp, len);
962 silc_free(channel_name);
966 /* Get channel mode */
967 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
969 SILC_GET32_MSB(mode, tmp);
973 /* Get channel key */
974 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
976 keyp = silc_buffer_alloc(len);
977 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
978 silc_buffer_put(keyp, tmp, len);
982 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
984 /* If we have the channel entry, remove it and create a new one */
985 channel = silc_client_get_channel(cmd->client, conn, channel_name);
987 silc_client_del_channel(cmd->client, conn, channel);
989 /* Save received Channel ID. This actually creates the channel */
990 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
992 silc_id_payload_free(idp);
994 conn->current_channel = channel;
997 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
999 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1000 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1001 "Cannot join channel: Unsupported HMAC `%s'",
1003 COMMAND_REPLY_ERROR;
1004 silc_free(channel_name);
1009 /* Get the list count */
1010 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1013 SILC_GET32_MSB(list_count, tmp);
1015 /* Get Client ID list */
1016 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1020 client_id_list = silc_buffer_alloc(len);
1021 silc_buffer_pull_tail(client_id_list, len);
1022 silc_buffer_put(client_id_list, tmp, len);
1024 /* Get client mode list */
1025 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1029 client_mode_list = silc_buffer_alloc(len);
1030 silc_buffer_pull_tail(client_mode_list, len);
1031 silc_buffer_put(client_mode_list, tmp, len);
1033 /* Add clients we received in the reply to the channel */
1034 for (i = 0; i < list_count; i++) {
1037 SilcClientID *client_id;
1038 SilcClientEntry client_entry;
1041 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1043 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1048 SILC_GET32_MSB(mode, client_mode_list->data);
1050 /* Check if we have this client cached already. */
1051 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1054 silc_hash_client_id_compare, NULL,
1056 /* No, we don't have it, add entry for it. */
1058 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1059 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1061 /* Yes, we have it already */
1062 client_entry = (SilcClientEntry)id_cache->context;
1065 /* Join the client to the channel */
1066 chu = silc_calloc(1, sizeof(*chu));
1067 chu->client = client_entry;
1069 silc_list_add(channel->clients, chu);
1070 silc_free(client_id);
1072 silc_buffer_pull(client_id_list, idp_len);
1073 silc_buffer_pull(client_mode_list, 4);
1075 silc_buffer_push(client_id_list, client_id_list->data -
1076 client_id_list->head);
1077 silc_buffer_push(client_mode_list, client_mode_list->data -
1078 client_mode_list->head);
1080 /* Save channel key */
1081 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1082 silc_client_save_channel_key(conn, keyp, channel);
1084 /* Client is now joined to the channel */
1085 channel->on_channel = TRUE;
1087 /* Notify application */
1088 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1089 keyp ? keyp->head : NULL, NULL,
1090 NULL, topic, hmac, list_count, client_id_list,
1094 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1095 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1096 silc_client_command_reply_free(cmd);
1099 silc_buffer_free(keyp);
1101 silc_buffer_free(client_id_list);
1102 if (client_mode_list)
1103 silc_buffer_free(client_mode_list);
1106 /* Received reply for MOTD command */
1108 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1110 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1111 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1112 SilcCommandStatus status;
1115 char *motd = NULL, *cp, line[256];
1117 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1118 SILC_GET16_MSB(status, tmp);
1119 if (status != SILC_STATUS_OK) {
1120 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1121 "%s", silc_client_command_status_message(status));
1122 COMMAND_REPLY_ERROR;
1126 argc = silc_argument_get_arg_num(cmd->args);
1128 COMMAND_REPLY_ERROR;
1133 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1135 COMMAND_REPLY_ERROR;
1142 if (cp[i++] == '\n') {
1143 memset(line, 0, sizeof(line));
1144 strncat(line, cp, i - 1);
1150 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1160 /* Notify application */
1161 COMMAND_REPLY((ARGS, motd));
1164 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1165 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1166 silc_client_command_reply_free(cmd);
1169 /* Received reply tot he UMODE command. Save the current user mode */
1171 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1173 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1174 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1175 SilcCommandStatus status;
1179 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1180 SILC_GET16_MSB(status, tmp);
1181 if (status != SILC_STATUS_OK) {
1182 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1183 "%s", silc_client_command_status_message(status));
1184 COMMAND_REPLY_ERROR;
1188 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1190 COMMAND_REPLY_ERROR;
1194 SILC_GET32_MSB(mode, tmp);
1195 conn->local_entry->mode = mode;
1197 /* Notify application */
1198 COMMAND_REPLY((ARGS, mode));
1201 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1202 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1203 silc_client_command_reply_free(cmd);
1206 /* Received reply for CMODE command. */
1208 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1210 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1211 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1212 SilcCommandStatus status;
1215 SilcIDCacheEntry id_cache;
1216 SilcChannelID *channel_id;
1217 SilcChannelEntry channel;
1220 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1221 if (status != SILC_STATUS_OK) {
1222 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1223 "%s", silc_client_command_status_message(status));
1224 COMMAND_REPLY_ERROR;
1228 /* Take Channel ID */
1229 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1232 channel_id = silc_id_payload_parse_id(tmp, len);
1236 /* Get the channel entry */
1237 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1239 silc_free(channel_id);
1240 COMMAND_REPLY_ERROR;
1244 channel = (SilcChannelEntry)id_cache->context;
1246 /* Get channel mode */
1247 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1249 silc_free(channel_id);
1250 COMMAND_REPLY_ERROR;
1255 SILC_GET32_MSB(mode, tmp);
1256 channel->mode = mode;
1258 /* Notify application */
1259 COMMAND_REPLY((ARGS, channel, mode));
1261 silc_free(channel_id);
1264 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1265 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1266 silc_client_command_reply_free(cmd);
1269 /* Received reply for CUMODE command */
1271 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1273 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1274 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1275 SilcCommandStatus status;
1276 SilcIDCacheEntry id_cache = NULL;
1277 SilcClientID *client_id;
1278 SilcChannelID *channel_id;
1279 SilcClientEntry client_entry;
1280 SilcChannelEntry channel;
1281 SilcChannelUser chu;
1282 unsigned char *modev, *tmp, *id;
1285 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1286 if (status != SILC_STATUS_OK) {
1287 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1288 "%s", silc_client_command_status_message(status));
1289 COMMAND_REPLY_ERROR;
1293 /* Get channel mode */
1294 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1296 COMMAND_REPLY_ERROR;
1300 /* Take Channel ID */
1301 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1304 channel_id = silc_id_payload_parse_id(tmp, len);
1308 /* Get the channel entry */
1309 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1311 silc_free(channel_id);
1312 COMMAND_REPLY_ERROR;
1316 channel = (SilcChannelEntry)id_cache->context;
1319 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1321 silc_free(channel_id);
1322 COMMAND_REPLY_ERROR;
1325 client_id = silc_id_payload_parse_id(id, len);
1327 silc_free(channel_id);
1328 COMMAND_REPLY_ERROR;
1332 /* Get client entry */
1333 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1335 silc_hash_client_id_compare, NULL,
1337 silc_free(channel_id);
1338 silc_free(client_id);
1339 COMMAND_REPLY_ERROR;
1343 client_entry = (SilcClientEntry)id_cache->context;
1346 SILC_GET32_MSB(mode, modev);
1347 silc_list_start(channel->clients);
1348 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1349 if (chu->client == client_entry) {
1355 /* Notify application */
1356 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1357 silc_free(client_id);
1358 silc_free(channel_id);
1361 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1362 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1363 silc_client_command_reply_free(cmd);
1366 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1368 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1369 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1370 SilcCommandStatus status;
1373 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1374 SILC_GET16_MSB(status, tmp);
1375 if (status != SILC_STATUS_OK) {
1376 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1377 "%s", silc_client_command_status_message(status));
1378 COMMAND_REPLY_ERROR;
1382 /* Notify application */
1383 COMMAND_REPLY((ARGS));
1386 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1387 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1388 silc_client_command_reply_free(cmd);
1391 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1393 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1394 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1395 SilcCommandStatus status;
1398 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1399 SILC_GET16_MSB(status, tmp);
1400 if (status != SILC_STATUS_OK) {
1401 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1402 "%s", silc_client_command_status_message(status));
1403 COMMAND_REPLY_ERROR;
1407 /* Notify application */
1408 COMMAND_REPLY((ARGS));
1411 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1412 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1413 silc_client_command_reply_free(cmd);
1416 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1418 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1419 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1420 SilcCommandStatus status;
1423 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1424 SILC_GET16_MSB(status, tmp);
1425 if (status != SILC_STATUS_OK) {
1426 cmd->client->ops->say(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_OPER);
1437 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1438 silc_client_command_reply_free(cmd);
1441 SILC_CLIENT_CMD_REPLY_FUNC(connect)
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->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1452 "%s", silc_client_command_status_message(status));
1453 COMMAND_REPLY_ERROR;
1457 /* Notify application */
1458 COMMAND_REPLY((ARGS));
1461 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1462 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1463 silc_client_command_reply_free(cmd);
1466 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1468 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1469 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1470 SilcCommandStatus status;
1471 SilcIDCacheEntry id_cache = NULL;
1472 SilcChannelEntry channel;
1473 SilcChannelID *channel_id;
1477 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1478 SILC_GET16_MSB(status, tmp);
1479 if (status != SILC_STATUS_OK) {
1480 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1481 "%s", silc_client_command_status_message(status));
1482 COMMAND_REPLY_ERROR;
1486 /* Take Channel ID */
1487 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1491 channel_id = silc_id_payload_parse_id(tmp, len);
1495 /* Get the channel entry */
1496 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1498 silc_free(channel_id);
1499 COMMAND_REPLY_ERROR;
1503 channel = (SilcChannelEntry)id_cache->context;
1505 /* Get the ban list */
1506 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1508 /* Notify application */
1509 COMMAND_REPLY((ARGS, channel, tmp));
1512 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1513 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1514 silc_client_command_reply_free(cmd);
1517 SILC_CLIENT_CMD_REPLY_FUNC(close)
1519 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1520 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1521 SilcCommandStatus status;
1524 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1525 SILC_GET16_MSB(status, tmp);
1526 if (status != SILC_STATUS_OK) {
1527 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1528 "%s", silc_client_command_status_message(status));
1529 COMMAND_REPLY_ERROR;
1533 /* Notify application */
1534 COMMAND_REPLY((ARGS));
1537 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1538 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1539 silc_client_command_reply_free(cmd);
1542 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1544 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1545 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1546 SilcCommandStatus status;
1549 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1550 SILC_GET16_MSB(status, tmp);
1551 if (status != SILC_STATUS_OK) {
1552 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1553 "%s", silc_client_command_status_message(status));
1554 COMMAND_REPLY_ERROR;
1558 /* Notify application */
1559 COMMAND_REPLY((ARGS));
1562 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1563 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1564 silc_client_command_reply_free(cmd);
1567 /* Reply to LEAVE command. */
1569 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1571 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1572 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1573 SilcCommandStatus status;
1576 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1577 SILC_GET16_MSB(status, tmp);
1578 if (status != SILC_STATUS_OK) {
1579 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1580 "%s", silc_client_command_status_message(status));
1581 COMMAND_REPLY_ERROR;
1585 /* Notify application */
1586 COMMAND_REPLY((ARGS));
1589 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1590 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1591 silc_client_command_reply_free(cmd);
1594 /* Reply to USERS command. Received list of client ID's and theirs modes
1595 on the channel we requested. */
1597 SILC_CLIENT_CMD_REPLY_FUNC(users)
1599 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1600 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1601 SilcCommandStatus status;
1602 SilcIDCacheEntry id_cache = NULL;
1603 SilcChannelEntry channel;
1604 SilcChannelUser chu;
1605 SilcChannelID *channel_id = NULL;
1606 SilcBuffer client_id_list = NULL;
1607 SilcBuffer client_mode_list = NULL;
1609 uint32 tmp_len, list_count;
1611 unsigned char **res_argv = NULL;
1612 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1614 SILC_LOG_DEBUG(("Start"));
1616 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1617 SILC_GET16_MSB(status, tmp);
1618 if (status != SILC_STATUS_OK) {
1619 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1620 "%s", silc_client_command_status_message(status));
1621 COMMAND_REPLY_ERROR;
1625 /* Get channel ID */
1626 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1628 COMMAND_REPLY_ERROR;
1631 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1633 COMMAND_REPLY_ERROR;
1637 /* Get the list count */
1638 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1640 COMMAND_REPLY_ERROR;
1643 SILC_GET32_MSB(list_count, tmp);
1645 /* Get Client ID list */
1646 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1648 COMMAND_REPLY_ERROR;
1652 client_id_list = silc_buffer_alloc(tmp_len);
1653 silc_buffer_pull_tail(client_id_list, tmp_len);
1654 silc_buffer_put(client_id_list, tmp, tmp_len);
1656 /* Get client mode list */
1657 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1659 COMMAND_REPLY_ERROR;
1663 client_mode_list = silc_buffer_alloc(tmp_len);
1664 silc_buffer_pull_tail(client_mode_list, tmp_len);
1665 silc_buffer_put(client_mode_list, tmp, tmp_len);
1667 /* Get channel entry */
1668 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1670 /* Resolve the channel from server */
1671 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1673 /* Register pending command callback. After we've received the channel
1674 information we will reprocess this command reply by re-calling this
1675 USERS command reply callback. */
1676 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1677 NULL, silc_client_command_reply_users, cmd);
1680 channel = (SilcChannelEntry)id_cache->context;
1683 /* Remove old client list from channel. */
1684 silc_list_start(channel->clients);
1685 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1686 silc_list_del(channel->clients, chu);
1690 /* Cache the received Client ID's and modes. */
1691 for (i = 0; i < list_count; i++) {
1694 SilcClientID *client_id;
1695 SilcClientEntry client;
1698 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1700 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1705 SILC_GET32_MSB(mode, client_mode_list->data);
1707 /* Check if we have this client cached already. */
1709 silc_idcache_find_by_id_one_ext(conn->client_cache,
1712 silc_hash_client_id_compare, NULL,
1715 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1716 !((SilcClientEntry)id_cache->context)->realname) {
1718 if (id_cache && id_cache->context) {
1719 SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
1720 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1721 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
1722 silc_buffer_pull(client_id_list, idp_len);
1723 silc_buffer_pull(client_mode_list, 4);
1726 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1729 /* No we don't have it (or it is incomplete in information), query
1730 it from the server. Assemble argument table that will be sent
1731 for the WHOIS command later. */
1732 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1734 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1736 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1738 res_argv[res_argc] = client_id_list->data;
1739 res_argv_lens[res_argc] = idp_len;
1740 res_argv_types[res_argc] = res_argc + 3;
1743 /* Found the client, join it to the channel */
1744 client = (SilcClientEntry)id_cache->context;
1745 chu = silc_calloc(1, sizeof(*chu));
1746 chu->client = client;
1748 silc_list_add(channel->clients, chu);
1750 silc_free(client_id);
1754 silc_buffer_pull(client_id_list, idp_len);
1755 silc_buffer_pull(client_mode_list, 4);
1758 /* Query the client information from server if the list included clients
1759 that we don't know about. */
1763 /* Send the WHOIS command to server */
1764 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1765 res_argc, res_argv, res_argv_lens,
1766 res_argv_types, ++conn->cmd_ident);
1767 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1768 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1771 /* Register pending command callback. After we've received the WHOIS
1772 command reply we will reprocess this command reply by re-calling this
1773 USERS command reply callback. */
1774 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1775 NULL, silc_client_command_reply_users, cmd);
1777 silc_buffer_free(res_cmd);
1779 silc_free(channel_id);
1781 silc_free(res_argv);
1782 silc_free(res_argv_lens);
1783 silc_free(res_argv_types);
1787 /* Notify application */
1788 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1791 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1792 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1793 silc_client_command_reply_free(cmd);
1794 silc_free(channel_id);
1796 silc_buffer_free(client_id_list);
1797 if (client_mode_list)
1798 silc_buffer_free(client_mode_list);
1801 /* Received command reply to GETKEY command. WE've received the remote
1802 client's public key. */
1804 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1806 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1807 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1808 SilcCommandStatus status;
1809 SilcIDCacheEntry id_cache;
1810 SilcIDPayload idp = NULL;
1811 SilcClientID *client_id = NULL;
1812 SilcClientEntry client_entry;
1813 SilcServerID *server_id = NULL;
1814 SilcServerEntry server_entry;
1816 unsigned char *tmp, *pk;
1820 SilcPublicKey public_key = NULL;
1822 SILC_LOG_DEBUG(("Start"));
1824 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1825 SILC_GET16_MSB(status, tmp);
1826 if (status != SILC_STATUS_OK) {
1827 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1828 "%s", silc_client_command_status_message(status));
1829 COMMAND_REPLY_ERROR;
1833 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1835 COMMAND_REPLY_ERROR;
1838 idp = silc_id_payload_parse_data(tmp, len);
1840 COMMAND_REPLY_ERROR;
1844 /* Get the public key payload */
1845 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1847 /* Decode the public key */
1848 SILC_GET16_MSB(pk_len, tmp);
1849 SILC_GET16_MSB(type, tmp + 2);
1852 if (type != SILC_SKE_PK_TYPE_SILC) {
1853 COMMAND_REPLY_ERROR;
1857 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1858 COMMAND_REPLY_ERROR;
1863 id_type = silc_id_payload_get_type(idp);
1864 if (id_type == SILC_ID_CLIENT) {
1865 /* Received client's public key */
1866 client_id = silc_id_payload_get_id(idp);
1867 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1870 silc_hash_client_id_compare, NULL,
1872 COMMAND_REPLY_ERROR;
1876 client_entry = (SilcClientEntry)id_cache->context;
1878 /* Notify application */
1879 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1880 } else if (id_type == SILC_ID_SERVER) {
1881 /* Received server's public key */
1882 server_id = silc_id_payload_get_id(idp);
1883 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1885 COMMAND_REPLY_ERROR;
1889 server_entry = (SilcServerEntry)id_cache->context;
1891 /* Notify application */
1892 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1896 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1897 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1899 silc_id_payload_free(idp);
1901 silc_pkcs_public_key_free(public_key);
1902 silc_free(client_id);
1903 silc_free(server_id);
1904 silc_client_command_reply_free(cmd);