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, fingerprint));
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 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
602 COMMAND_REPLY((ARGS, conn->local_entry));
603 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
604 silc_client_command_reply_free(cmd);
608 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
609 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
610 silc_client_command_reply_free(cmd);
613 /* Received reply to the LIST command. */
615 SILC_CLIENT_CMD_REPLY_FUNC(list)
617 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
618 SilcCommandStatus status;
619 unsigned char *tmp, *name, *topic;
620 uint32 usercount = 0;
622 COMMAND_CHECK_STATUS_LIST;
624 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
625 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
626 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
628 SILC_GET32_MSB(usercount, tmp);
630 /* Notify application */
631 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
633 /* Pending callbacks are not executed if this was an list entry */
634 if (status != SILC_STATUS_OK &&
635 status != SILC_STATUS_LIST_END) {
636 silc_client_command_reply_free(cmd);
641 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
642 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
643 silc_client_command_reply_free(cmd);
646 /* Received reply to topic command. */
648 SILC_CLIENT_CMD_REPLY_FUNC(topic)
650 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
651 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
652 SilcCommandStatus status;
653 SilcChannelEntry channel;
654 SilcChannelID *channel_id = NULL;
655 SilcIDCacheEntry id_cache = NULL;
660 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
661 if (status != SILC_STATUS_OK) {
662 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
663 "%s", silc_client_command_status_message(status));
668 argc = silc_argument_get_arg_num(cmd->args);
669 if (argc < 1 || argc > 3) {
674 /* Take Channel ID */
675 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
680 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
684 channel_id = silc_id_payload_parse_id(tmp, len);
688 /* Get the channel entry */
689 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
691 silc_free(channel_id);
696 channel = (SilcChannelEntry)id_cache->context;
698 /* Notify application */
699 COMMAND_REPLY((ARGS, channel, topic));
702 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
703 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
704 silc_client_command_reply_free(cmd);
707 /* Received reply to invite command. */
709 SILC_CLIENT_CMD_REPLY_FUNC(invite)
711 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
712 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
713 SilcCommandStatus status;
714 SilcChannelEntry channel;
715 SilcChannelID *channel_id;
716 SilcIDCacheEntry id_cache;
720 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
721 SILC_GET16_MSB(status, tmp);
722 if (status != SILC_STATUS_OK) {
723 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
724 "%s", silc_client_command_status_message(status));
729 /* Take Channel ID */
730 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
734 channel_id = silc_id_payload_parse_id(tmp, len);
738 /* Get the channel entry */
739 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
741 silc_free(channel_id);
746 channel = (SilcChannelEntry)id_cache->context;
748 /* Get the invite list */
749 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
751 /* Notify application */
752 COMMAND_REPLY((ARGS, channel, tmp));
755 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
756 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
757 silc_client_command_reply_free(cmd);
760 /* Received reply to the KILL command. */
762 SILC_CLIENT_CMD_REPLY_FUNC(kill)
764 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
765 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
766 SilcCommandStatus status;
768 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
769 if (status != SILC_STATUS_OK) {
770 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
771 "%s", silc_client_command_status_message(status));
776 /* Notify application */
777 COMMAND_REPLY((ARGS));
780 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
781 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
782 silc_client_command_reply_free(cmd);
785 /* Received reply to INFO command. We receive the server ID and some
786 information about the server user requested. */
788 SILC_CLIENT_CMD_REPLY_FUNC(info)
790 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
791 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
792 SilcCommandStatus status;
794 SilcIDCacheEntry id_cache;
795 SilcServerEntry server;
796 SilcServerID *server_id = NULL;
797 char *server_name, *server_info;
800 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
801 SILC_GET16_MSB(status, tmp);
802 if (status != SILC_STATUS_OK) {
803 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
804 "%s", silc_client_command_status_message(status));
810 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
814 server_id = silc_id_payload_parse_id(tmp, len);
818 /* Get server name */
819 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
823 /* Get server info */
824 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
828 /* See whether we have this server cached. If not create it. */
829 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
831 SILC_LOG_DEBUG(("New server entry"));
833 server = silc_calloc(1, sizeof(*server));
834 server->server_name = strdup(server_name);
835 server->server_info = strdup(server_info);
836 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
838 /* Add it to the cache */
839 silc_idcache_add(conn->server_cache, server->server_name,
840 server->server_id, (void *)server, FALSE);
842 if (SILC_ID_SERVER_COMPARE(server_id, conn->remote_id))
845 server = (SilcServerEntry)id_cache->context;
848 /* Notify application */
849 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
852 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
853 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
854 silc_free(server_id);
855 silc_client_command_reply_free(cmd);
858 /* Received reply to PING command. The reply time is shown to user. */
860 SILC_CLIENT_CMD_REPLY_FUNC(ping)
862 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
863 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
864 SilcCommandStatus status;
867 time_t diff, curtime;
869 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
870 if (status != SILC_STATUS_OK) {
871 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
872 "%s", silc_client_command_status_message(status));
877 curtime = time(NULL);
878 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
879 cmd->packet->src_id_type);
880 if (!id || !conn->ping) {
885 for (i = 0; i < conn->ping_count; i++) {
886 if (!conn->ping[i].dest_id)
888 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
889 diff = curtime - conn->ping[i].start_time;
890 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
891 "Ping reply from %s: %d second%s",
892 conn->ping[i].dest_name, diff,
893 diff == 1 ? "" : "s");
895 conn->ping[i].start_time = 0;
896 silc_free(conn->ping[i].dest_id);
897 conn->ping[i].dest_id = NULL;
898 silc_free(conn->ping[i].dest_name);
899 conn->ping[i].dest_name = NULL;
906 /* Notify application */
907 COMMAND_REPLY((ARGS));
910 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
911 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
912 silc_client_command_reply_free(cmd);
915 /* Received reply for JOIN command. */
917 SILC_CLIENT_CMD_REPLY_FUNC(join)
919 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
920 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
921 SilcCommandStatus status;
922 SilcIDPayload idp = NULL;
923 SilcChannelEntry channel;
924 SilcIDCacheEntry id_cache = NULL;
926 uint32 argc, mode, len, list_count;
927 char *topic, *tmp, *channel_name = NULL, *hmac;
928 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
931 SILC_LOG_DEBUG(("Start"));
933 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
934 if (status != SILC_STATUS_OK) {
935 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
936 "%s", silc_client_command_status_message(status));
941 argc = silc_argument_get_arg_num(cmd->args);
942 if (argc < 7 || argc > 14) {
943 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
944 "Cannot join channel: Bad reply packet");
949 /* Get channel name */
950 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
952 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
953 "Cannot join channel: Bad reply packet");
957 channel_name = strdup(tmp);
960 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
962 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
963 "Cannot join channel: Bad reply packet");
965 silc_free(channel_name);
968 idp = silc_id_payload_parse_data(tmp, len);
971 silc_free(channel_name);
975 /* Get channel mode */
976 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
978 SILC_GET32_MSB(mode, tmp);
982 /* Get channel key */
983 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
985 keyp = silc_buffer_alloc(len);
986 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
987 silc_buffer_put(keyp, tmp, len);
991 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
993 /* If we have the channel entry, remove it and create a new one */
994 channel = silc_client_get_channel(cmd->client, conn, channel_name);
996 silc_client_del_channel(cmd->client, conn, channel);
998 /* Save received Channel ID. This actually creates the channel */
999 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
1001 silc_id_payload_free(idp);
1003 conn->current_channel = channel;
1006 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1008 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1009 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1010 "Cannot join channel: Unsupported HMAC `%s'",
1012 COMMAND_REPLY_ERROR;
1013 silc_free(channel_name);
1018 /* Get the list count */
1019 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1022 SILC_GET32_MSB(list_count, tmp);
1024 /* Get Client ID list */
1025 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1029 client_id_list = silc_buffer_alloc(len);
1030 silc_buffer_pull_tail(client_id_list, len);
1031 silc_buffer_put(client_id_list, tmp, len);
1033 /* Get client mode list */
1034 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1038 client_mode_list = silc_buffer_alloc(len);
1039 silc_buffer_pull_tail(client_mode_list, len);
1040 silc_buffer_put(client_mode_list, tmp, len);
1042 /* Add clients we received in the reply to the channel */
1043 for (i = 0; i < list_count; i++) {
1046 SilcClientID *client_id;
1047 SilcClientEntry client_entry;
1050 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1052 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1057 SILC_GET32_MSB(mode, client_mode_list->data);
1059 /* Check if we have this client cached already. */
1060 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1063 silc_hash_client_id_compare, NULL,
1065 /* No, we don't have it, add entry for it. */
1067 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1068 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1070 /* Yes, we have it already */
1071 client_entry = (SilcClientEntry)id_cache->context;
1074 /* Join the client to the channel */
1075 chu = silc_calloc(1, sizeof(*chu));
1076 chu->client = client_entry;
1078 silc_list_add(channel->clients, chu);
1079 silc_free(client_id);
1081 silc_buffer_pull(client_id_list, idp_len);
1082 silc_buffer_pull(client_mode_list, 4);
1084 silc_buffer_push(client_id_list, client_id_list->data -
1085 client_id_list->head);
1086 silc_buffer_push(client_mode_list, client_mode_list->data -
1087 client_mode_list->head);
1089 /* Save channel key */
1090 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1091 silc_client_save_channel_key(conn, keyp, channel);
1093 /* Client is now joined to the channel */
1094 channel->on_channel = TRUE;
1096 /* Notify application */
1097 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1098 keyp ? keyp->head : NULL, NULL,
1099 NULL, topic, hmac, list_count, client_id_list,
1103 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1104 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1105 silc_client_command_reply_free(cmd);
1108 silc_buffer_free(keyp);
1110 silc_buffer_free(client_id_list);
1111 if (client_mode_list)
1112 silc_buffer_free(client_mode_list);
1115 /* Received reply for MOTD command */
1117 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1119 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1120 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1121 SilcCommandStatus status;
1124 char *motd = NULL, *cp, line[256];
1126 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1127 SILC_GET16_MSB(status, tmp);
1128 if (status != SILC_STATUS_OK) {
1129 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1130 "%s", silc_client_command_status_message(status));
1131 COMMAND_REPLY_ERROR;
1135 argc = silc_argument_get_arg_num(cmd->args);
1137 COMMAND_REPLY_ERROR;
1142 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1144 COMMAND_REPLY_ERROR;
1151 if (cp[i++] == '\n') {
1152 memset(line, 0, sizeof(line));
1153 strncat(line, cp, i - 1);
1159 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1169 /* Notify application */
1170 COMMAND_REPLY((ARGS, motd));
1173 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1174 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1175 silc_client_command_reply_free(cmd);
1178 /* Received reply tot he UMODE command. Save the current user mode */
1180 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1182 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1183 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1184 SilcCommandStatus status;
1188 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1189 SILC_GET16_MSB(status, tmp);
1190 if (status != SILC_STATUS_OK) {
1191 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1192 "%s", silc_client_command_status_message(status));
1193 COMMAND_REPLY_ERROR;
1197 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1199 COMMAND_REPLY_ERROR;
1203 SILC_GET32_MSB(mode, tmp);
1204 conn->local_entry->mode = mode;
1206 /* Notify application */
1207 COMMAND_REPLY((ARGS, mode));
1210 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1211 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1212 silc_client_command_reply_free(cmd);
1215 /* Received reply for CMODE command. */
1217 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1219 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1220 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1221 SilcCommandStatus status;
1224 SilcIDCacheEntry id_cache;
1225 SilcChannelID *channel_id;
1226 SilcChannelEntry channel;
1229 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1230 if (status != SILC_STATUS_OK) {
1231 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1232 "%s", silc_client_command_status_message(status));
1233 COMMAND_REPLY_ERROR;
1237 /* Take Channel ID */
1238 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1241 channel_id = silc_id_payload_parse_id(tmp, len);
1245 /* Get the channel entry */
1246 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1248 silc_free(channel_id);
1249 COMMAND_REPLY_ERROR;
1253 channel = (SilcChannelEntry)id_cache->context;
1255 /* Get channel mode */
1256 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1258 silc_free(channel_id);
1259 COMMAND_REPLY_ERROR;
1264 SILC_GET32_MSB(mode, tmp);
1265 channel->mode = mode;
1267 /* Notify application */
1268 COMMAND_REPLY((ARGS, channel, mode));
1270 silc_free(channel_id);
1273 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1274 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1275 silc_client_command_reply_free(cmd);
1278 /* Received reply for CUMODE command */
1280 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1282 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1283 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1284 SilcCommandStatus status;
1285 SilcIDCacheEntry id_cache = NULL;
1286 SilcClientID *client_id;
1287 SilcChannelID *channel_id;
1288 SilcClientEntry client_entry;
1289 SilcChannelEntry channel;
1290 SilcChannelUser chu;
1291 unsigned char *modev, *tmp, *id;
1294 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1295 if (status != SILC_STATUS_OK) {
1296 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1297 "%s", silc_client_command_status_message(status));
1298 COMMAND_REPLY_ERROR;
1302 /* Get channel mode */
1303 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1305 COMMAND_REPLY_ERROR;
1309 /* Take Channel ID */
1310 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1313 channel_id = silc_id_payload_parse_id(tmp, len);
1317 /* Get the channel entry */
1318 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1320 silc_free(channel_id);
1321 COMMAND_REPLY_ERROR;
1325 channel = (SilcChannelEntry)id_cache->context;
1328 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1330 silc_free(channel_id);
1331 COMMAND_REPLY_ERROR;
1334 client_id = silc_id_payload_parse_id(id, len);
1336 silc_free(channel_id);
1337 COMMAND_REPLY_ERROR;
1341 /* Get client entry */
1342 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1344 silc_hash_client_id_compare, NULL,
1346 silc_free(channel_id);
1347 silc_free(client_id);
1348 COMMAND_REPLY_ERROR;
1352 client_entry = (SilcClientEntry)id_cache->context;
1355 SILC_GET32_MSB(mode, modev);
1356 silc_list_start(channel->clients);
1357 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1358 if (chu->client == client_entry) {
1364 /* Notify application */
1365 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1366 silc_free(client_id);
1367 silc_free(channel_id);
1370 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1371 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1372 silc_client_command_reply_free(cmd);
1375 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1377 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1378 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1379 SilcCommandStatus status;
1382 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1383 SILC_GET16_MSB(status, tmp);
1384 if (status != SILC_STATUS_OK) {
1385 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1386 "%s", silc_client_command_status_message(status));
1387 COMMAND_REPLY_ERROR;
1391 /* Notify application */
1392 COMMAND_REPLY((ARGS));
1395 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1396 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1397 silc_client_command_reply_free(cmd);
1400 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1402 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1403 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1404 SilcCommandStatus status;
1407 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1408 SILC_GET16_MSB(status, tmp);
1409 if (status != SILC_STATUS_OK) {
1410 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1411 "%s", silc_client_command_status_message(status));
1412 COMMAND_REPLY_ERROR;
1416 /* Notify application */
1417 COMMAND_REPLY((ARGS));
1420 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1421 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1422 silc_client_command_reply_free(cmd);
1425 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1427 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1428 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1429 SilcCommandStatus status;
1432 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1433 SILC_GET16_MSB(status, tmp);
1434 if (status != SILC_STATUS_OK) {
1435 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1436 "%s", silc_client_command_status_message(status));
1437 COMMAND_REPLY_ERROR;
1441 /* Notify application */
1442 COMMAND_REPLY((ARGS));
1445 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1446 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1447 silc_client_command_reply_free(cmd);
1450 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1452 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1453 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1454 SilcCommandStatus status;
1457 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1458 SILC_GET16_MSB(status, tmp);
1459 if (status != SILC_STATUS_OK) {
1460 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1461 "%s", silc_client_command_status_message(status));
1462 COMMAND_REPLY_ERROR;
1466 /* Notify application */
1467 COMMAND_REPLY((ARGS));
1470 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1471 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1472 silc_client_command_reply_free(cmd);
1475 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1477 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1478 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1479 SilcCommandStatus status;
1480 SilcIDCacheEntry id_cache = NULL;
1481 SilcChannelEntry channel;
1482 SilcChannelID *channel_id;
1486 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1487 SILC_GET16_MSB(status, tmp);
1488 if (status != SILC_STATUS_OK) {
1489 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1490 "%s", silc_client_command_status_message(status));
1491 COMMAND_REPLY_ERROR;
1495 /* Take Channel ID */
1496 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1500 channel_id = silc_id_payload_parse_id(tmp, len);
1504 /* Get the channel entry */
1505 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1507 silc_free(channel_id);
1508 COMMAND_REPLY_ERROR;
1512 channel = (SilcChannelEntry)id_cache->context;
1514 /* Get the ban list */
1515 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1517 /* Notify application */
1518 COMMAND_REPLY((ARGS, channel, tmp));
1521 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1522 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1523 silc_client_command_reply_free(cmd);
1526 SILC_CLIENT_CMD_REPLY_FUNC(close)
1528 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1529 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1530 SilcCommandStatus status;
1533 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1534 SILC_GET16_MSB(status, tmp);
1535 if (status != SILC_STATUS_OK) {
1536 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1537 "%s", silc_client_command_status_message(status));
1538 COMMAND_REPLY_ERROR;
1542 /* Notify application */
1543 COMMAND_REPLY((ARGS));
1546 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1547 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1548 silc_client_command_reply_free(cmd);
1551 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1553 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1554 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1555 SilcCommandStatus status;
1558 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1559 SILC_GET16_MSB(status, tmp);
1560 if (status != SILC_STATUS_OK) {
1561 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1562 "%s", silc_client_command_status_message(status));
1563 COMMAND_REPLY_ERROR;
1567 /* Notify application */
1568 COMMAND_REPLY((ARGS));
1571 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1572 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1573 silc_client_command_reply_free(cmd);
1576 /* Reply to LEAVE command. */
1578 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1580 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1581 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1582 SilcCommandStatus status;
1585 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1586 SILC_GET16_MSB(status, tmp);
1587 if (status != SILC_STATUS_OK) {
1588 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1589 "%s", silc_client_command_status_message(status));
1590 COMMAND_REPLY_ERROR;
1594 /* Notify application */
1595 COMMAND_REPLY((ARGS));
1598 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1599 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1600 silc_client_command_reply_free(cmd);
1603 /* Reply to USERS command. Received list of client ID's and theirs modes
1604 on the channel we requested. */
1606 SILC_CLIENT_CMD_REPLY_FUNC(users)
1608 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1609 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1610 SilcCommandStatus status;
1611 SilcIDCacheEntry id_cache = NULL;
1612 SilcChannelEntry channel;
1613 SilcChannelUser chu;
1614 SilcChannelID *channel_id = NULL;
1615 SilcBuffer client_id_list = NULL;
1616 SilcBuffer client_mode_list = NULL;
1618 uint32 tmp_len, list_count;
1620 unsigned char **res_argv = NULL;
1621 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1623 SILC_LOG_DEBUG(("Start"));
1625 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1626 SILC_GET16_MSB(status, tmp);
1627 if (status != SILC_STATUS_OK) {
1628 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1629 "%s", silc_client_command_status_message(status));
1630 COMMAND_REPLY_ERROR;
1634 /* Get channel ID */
1635 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1637 COMMAND_REPLY_ERROR;
1640 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1642 COMMAND_REPLY_ERROR;
1646 /* Get the list count */
1647 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1649 COMMAND_REPLY_ERROR;
1652 SILC_GET32_MSB(list_count, tmp);
1654 /* Get Client ID list */
1655 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1657 COMMAND_REPLY_ERROR;
1661 client_id_list = silc_buffer_alloc(tmp_len);
1662 silc_buffer_pull_tail(client_id_list, tmp_len);
1663 silc_buffer_put(client_id_list, tmp, tmp_len);
1665 /* Get client mode list */
1666 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1668 COMMAND_REPLY_ERROR;
1672 client_mode_list = silc_buffer_alloc(tmp_len);
1673 silc_buffer_pull_tail(client_mode_list, tmp_len);
1674 silc_buffer_put(client_mode_list, tmp, tmp_len);
1676 /* Get channel entry */
1677 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1679 /* Resolve the channel from server */
1680 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1682 /* Register pending command callback. After we've received the channel
1683 information we will reprocess this command reply by re-calling this
1684 USERS command reply callback. */
1685 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1686 NULL, silc_client_command_reply_users, cmd);
1689 channel = (SilcChannelEntry)id_cache->context;
1692 /* Remove old client list from channel. */
1693 silc_list_start(channel->clients);
1694 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1695 silc_list_del(channel->clients, chu);
1699 /* Cache the received Client ID's and modes. */
1700 for (i = 0; i < list_count; i++) {
1703 SilcClientID *client_id;
1704 SilcClientEntry client;
1707 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1709 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1714 SILC_GET32_MSB(mode, client_mode_list->data);
1716 /* Check if we have this client cached already. */
1718 silc_idcache_find_by_id_one_ext(conn->client_cache,
1721 silc_hash_client_id_compare, NULL,
1724 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1725 !((SilcClientEntry)id_cache->context)->realname) {
1727 if (id_cache && id_cache->context) {
1728 SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
1729 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1730 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
1731 silc_buffer_pull(client_id_list, idp_len);
1732 silc_buffer_pull(client_mode_list, 4);
1735 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1738 /* No we don't have it (or it is incomplete in information), query
1739 it from the server. Assemble argument table that will be sent
1740 for the WHOIS command later. */
1741 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1743 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1745 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1747 res_argv[res_argc] = client_id_list->data;
1748 res_argv_lens[res_argc] = idp_len;
1749 res_argv_types[res_argc] = res_argc + 3;
1752 /* Found the client, join it to the channel */
1753 client = (SilcClientEntry)id_cache->context;
1754 chu = silc_calloc(1, sizeof(*chu));
1755 chu->client = client;
1757 silc_list_add(channel->clients, chu);
1759 silc_free(client_id);
1763 silc_buffer_pull(client_id_list, idp_len);
1764 silc_buffer_pull(client_mode_list, 4);
1767 /* Query the client information from server if the list included clients
1768 that we don't know about. */
1772 /* Send the WHOIS command to server */
1773 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1774 res_argc, res_argv, res_argv_lens,
1775 res_argv_types, ++conn->cmd_ident);
1776 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1777 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1780 /* Register pending command callback. After we've received the WHOIS
1781 command reply we will reprocess this command reply by re-calling this
1782 USERS command reply callback. */
1783 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1784 NULL, silc_client_command_reply_users, cmd);
1786 silc_buffer_free(res_cmd);
1788 silc_free(channel_id);
1790 silc_free(res_argv);
1791 silc_free(res_argv_lens);
1792 silc_free(res_argv_types);
1796 /* Notify application */
1797 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1800 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1801 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1802 silc_client_command_reply_free(cmd);
1803 silc_free(channel_id);
1805 silc_buffer_free(client_id_list);
1806 if (client_mode_list)
1807 silc_buffer_free(client_mode_list);
1810 /* Received command reply to GETKEY command. WE've received the remote
1811 client's public key. */
1813 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1815 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1816 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1817 SilcCommandStatus status;
1818 SilcIDCacheEntry id_cache;
1819 SilcIDPayload idp = NULL;
1820 SilcClientID *client_id = NULL;
1821 SilcClientEntry client_entry;
1822 SilcServerID *server_id = NULL;
1823 SilcServerEntry server_entry;
1825 unsigned char *tmp, *pk;
1829 SilcPublicKey public_key = NULL;
1831 SILC_LOG_DEBUG(("Start"));
1833 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1834 SILC_GET16_MSB(status, tmp);
1835 if (status != SILC_STATUS_OK) {
1836 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1837 "%s", silc_client_command_status_message(status));
1838 COMMAND_REPLY_ERROR;
1842 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1844 COMMAND_REPLY_ERROR;
1847 idp = silc_id_payload_parse_data(tmp, len);
1849 COMMAND_REPLY_ERROR;
1853 /* Get the public key payload */
1854 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1856 /* Decode the public key */
1857 SILC_GET16_MSB(pk_len, tmp);
1858 SILC_GET16_MSB(type, tmp + 2);
1861 if (type != SILC_SKE_PK_TYPE_SILC) {
1862 COMMAND_REPLY_ERROR;
1866 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1867 COMMAND_REPLY_ERROR;
1872 id_type = silc_id_payload_get_type(idp);
1873 if (id_type == SILC_ID_CLIENT) {
1874 /* Received client's public key */
1875 client_id = silc_id_payload_get_id(idp);
1876 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1879 silc_hash_client_id_compare, NULL,
1881 COMMAND_REPLY_ERROR;
1885 client_entry = (SilcClientEntry)id_cache->context;
1887 /* Notify application */
1888 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1889 } else if (id_type == SILC_ID_SERVER) {
1890 /* Received server's public key */
1891 server_id = silc_id_payload_get_id(idp);
1892 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1894 COMMAND_REPLY_ERROR;
1898 server_entry = (SilcServerEntry)id_cache->context;
1900 /* Notify application */
1901 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1905 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1906 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1908 silc_id_payload_free(idp);
1910 silc_pkcs_public_key_free(public_key);
1911 silc_free(client_id);
1912 silc_free(server_id);
1913 silc_client_command_reply_free(cmd);