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->data, buffer->len);
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(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(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 if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
936 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
937 "%s", silc_client_command_status_message(status));
942 argc = silc_argument_get_arg_num(cmd->args);
943 if (argc < 7 || argc > 14) {
944 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
945 "Cannot join channel: Bad reply packet");
950 /* Get channel name */
951 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
953 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
954 "Cannot join channel: Bad reply packet");
958 channel_name = strdup(tmp);
961 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
963 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
964 "Cannot join channel: Bad reply packet");
966 silc_free(channel_name);
969 idp = silc_id_payload_parse(tmp, len);
972 silc_free(channel_name);
976 /* Get channel mode */
977 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
979 SILC_GET32_MSB(mode, tmp);
983 /* Get channel key */
984 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
986 keyp = silc_buffer_alloc(len);
987 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
988 silc_buffer_put(keyp, tmp, len);
992 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
994 /* If we have the channel entry, remove it and create a new one */
995 channel = silc_client_get_channel(cmd->client, conn, channel_name);
997 silc_client_del_channel(cmd->client, conn, channel);
999 /* Save received Channel ID. This actually creates the channel */
1000 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
1002 silc_id_payload_free(idp);
1004 conn->current_channel = channel;
1007 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1009 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1010 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1011 "Cannot join channel: Unsupported HMAC `%s'",
1013 COMMAND_REPLY_ERROR;
1014 silc_free(channel_name);
1019 /* Get the list count */
1020 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1023 SILC_GET32_MSB(list_count, tmp);
1025 /* Get Client ID list */
1026 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1030 client_id_list = silc_buffer_alloc(len);
1031 silc_buffer_pull_tail(client_id_list, len);
1032 silc_buffer_put(client_id_list, tmp, len);
1034 /* Get client mode list */
1035 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1039 client_mode_list = silc_buffer_alloc(len);
1040 silc_buffer_pull_tail(client_mode_list, len);
1041 silc_buffer_put(client_mode_list, tmp, len);
1043 /* Add clients we received in the reply to the channel */
1044 for (i = 0; i < list_count; i++) {
1047 SilcClientID *client_id;
1048 SilcClientEntry client_entry;
1051 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1053 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1058 SILC_GET32_MSB(mode, client_mode_list->data);
1060 /* Check if we have this client cached already. */
1061 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1064 silc_hash_client_id_compare, NULL,
1066 /* No, we don't have it, add entry for it. */
1068 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1069 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1071 /* Yes, we have it already */
1072 client_entry = (SilcClientEntry)id_cache->context;
1075 /* Join the client to the channel */
1076 chu = silc_calloc(1, sizeof(*chu));
1077 chu->client = client_entry;
1079 silc_list_add(channel->clients, chu);
1080 silc_free(client_id);
1082 silc_buffer_pull(client_id_list, idp_len);
1083 silc_buffer_pull(client_mode_list, 4);
1085 silc_buffer_push(client_id_list, client_id_list->data -
1086 client_id_list->head);
1087 silc_buffer_push(client_mode_list, client_mode_list->data -
1088 client_mode_list->head);
1090 /* Save channel key */
1091 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1092 silc_client_save_channel_key(conn, keyp, channel);
1094 /* Client is now joined to the channel */
1095 channel->on_channel = TRUE;
1097 /* Notify application */
1098 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1099 keyp ? keyp->head : NULL, NULL,
1100 NULL, topic, hmac, list_count, client_id_list,
1104 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1105 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1106 silc_client_command_reply_free(cmd);
1109 silc_buffer_free(keyp);
1111 silc_buffer_free(client_id_list);
1112 if (client_mode_list)
1113 silc_buffer_free(client_mode_list);
1116 /* Received reply for MOTD command */
1118 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1120 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1121 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1122 SilcCommandStatus status;
1125 char *motd = NULL, *cp, line[256];
1127 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1128 SILC_GET16_MSB(status, tmp);
1129 if (status != SILC_STATUS_OK) {
1130 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1131 "%s", silc_client_command_status_message(status));
1132 COMMAND_REPLY_ERROR;
1136 argc = silc_argument_get_arg_num(cmd->args);
1138 COMMAND_REPLY_ERROR;
1143 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1145 COMMAND_REPLY_ERROR;
1152 if (cp[i++] == '\n') {
1153 memset(line, 0, sizeof(line));
1154 strncat(line, cp, i - 1);
1160 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1170 /* Notify application */
1171 COMMAND_REPLY((ARGS, motd));
1174 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1175 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1176 silc_client_command_reply_free(cmd);
1179 /* Received reply tot he UMODE command. Save the current user mode */
1181 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1183 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1184 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1185 SilcCommandStatus status;
1189 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1190 SILC_GET16_MSB(status, tmp);
1191 if (status != SILC_STATUS_OK) {
1192 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1193 "%s", silc_client_command_status_message(status));
1194 COMMAND_REPLY_ERROR;
1198 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1200 COMMAND_REPLY_ERROR;
1204 SILC_GET32_MSB(mode, tmp);
1205 conn->local_entry->mode = mode;
1207 /* Notify application */
1208 COMMAND_REPLY((ARGS, mode));
1211 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1212 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1213 silc_client_command_reply_free(cmd);
1216 /* Received reply for CMODE command. */
1218 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1220 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1221 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1222 SilcCommandStatus status;
1225 SilcIDCacheEntry id_cache;
1226 SilcChannelID *channel_id;
1227 SilcChannelEntry channel;
1230 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1231 if (status != SILC_STATUS_OK) {
1232 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1233 "%s", silc_client_command_status_message(status));
1234 COMMAND_REPLY_ERROR;
1238 /* Take Channel ID */
1239 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1242 channel_id = silc_id_payload_parse_id(tmp, len);
1246 /* Get the channel entry */
1247 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1249 silc_free(channel_id);
1250 COMMAND_REPLY_ERROR;
1254 channel = (SilcChannelEntry)id_cache->context;
1256 /* Get channel mode */
1257 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1259 silc_free(channel_id);
1260 COMMAND_REPLY_ERROR;
1265 SILC_GET32_MSB(mode, tmp);
1266 channel->mode = mode;
1268 /* Notify application */
1269 COMMAND_REPLY((ARGS, channel, mode));
1271 silc_free(channel_id);
1274 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1275 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1276 silc_client_command_reply_free(cmd);
1279 /* Received reply for CUMODE command */
1281 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1283 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1284 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1285 SilcCommandStatus status;
1286 SilcIDCacheEntry id_cache = NULL;
1287 SilcClientID *client_id;
1288 SilcChannelID *channel_id;
1289 SilcClientEntry client_entry;
1290 SilcChannelEntry channel;
1291 SilcChannelUser chu;
1292 unsigned char *modev, *tmp, *id;
1295 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1296 if (status != SILC_STATUS_OK) {
1297 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1298 "%s", silc_client_command_status_message(status));
1299 COMMAND_REPLY_ERROR;
1303 /* Get channel mode */
1304 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1306 COMMAND_REPLY_ERROR;
1310 /* Take Channel ID */
1311 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1314 channel_id = silc_id_payload_parse_id(tmp, len);
1318 /* Get the channel entry */
1319 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1321 silc_free(channel_id);
1322 COMMAND_REPLY_ERROR;
1326 channel = (SilcChannelEntry)id_cache->context;
1329 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1331 silc_free(channel_id);
1332 COMMAND_REPLY_ERROR;
1335 client_id = silc_id_payload_parse_id(id, len);
1337 silc_free(channel_id);
1338 COMMAND_REPLY_ERROR;
1342 /* Get client entry */
1343 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1345 silc_hash_client_id_compare, NULL,
1347 silc_free(channel_id);
1348 silc_free(client_id);
1349 COMMAND_REPLY_ERROR;
1353 client_entry = (SilcClientEntry)id_cache->context;
1356 SILC_GET32_MSB(mode, modev);
1357 silc_list_start(channel->clients);
1358 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1359 if (chu->client == client_entry) {
1365 /* Notify application */
1366 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1367 silc_free(client_id);
1368 silc_free(channel_id);
1371 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1372 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1373 silc_client_command_reply_free(cmd);
1376 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1378 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1379 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1380 SilcCommandStatus status;
1383 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1384 SILC_GET16_MSB(status, tmp);
1385 if (status != SILC_STATUS_OK) {
1386 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1387 "%s", silc_client_command_status_message(status));
1388 COMMAND_REPLY_ERROR;
1392 /* Notify application */
1393 COMMAND_REPLY((ARGS));
1396 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1397 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1398 silc_client_command_reply_free(cmd);
1401 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1403 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1404 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1405 SilcCommandStatus status;
1408 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1409 SILC_GET16_MSB(status, tmp);
1410 if (status != SILC_STATUS_OK) {
1411 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1412 "%s", silc_client_command_status_message(status));
1413 COMMAND_REPLY_ERROR;
1417 /* Notify application */
1418 COMMAND_REPLY((ARGS));
1421 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1422 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1423 silc_client_command_reply_free(cmd);
1426 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1428 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1429 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1430 SilcCommandStatus status;
1433 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1434 SILC_GET16_MSB(status, tmp);
1435 if (status != SILC_STATUS_OK) {
1436 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1437 "%s", silc_client_command_status_message(status));
1438 COMMAND_REPLY_ERROR;
1442 /* Notify application */
1443 COMMAND_REPLY((ARGS));
1446 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1447 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1448 silc_client_command_reply_free(cmd);
1451 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1453 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1454 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1455 SilcCommandStatus status;
1458 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1459 SILC_GET16_MSB(status, tmp);
1460 if (status != SILC_STATUS_OK) {
1461 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1462 "%s", silc_client_command_status_message(status));
1463 COMMAND_REPLY_ERROR;
1467 /* Notify application */
1468 COMMAND_REPLY((ARGS));
1471 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1472 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1473 silc_client_command_reply_free(cmd);
1476 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1478 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1479 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1480 SilcCommandStatus status;
1481 SilcIDCacheEntry id_cache = NULL;
1482 SilcChannelEntry channel;
1483 SilcChannelID *channel_id;
1487 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1488 SILC_GET16_MSB(status, tmp);
1489 if (status != SILC_STATUS_OK) {
1490 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1491 "%s", silc_client_command_status_message(status));
1492 COMMAND_REPLY_ERROR;
1496 /* Take Channel ID */
1497 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1501 channel_id = silc_id_payload_parse_id(tmp, len);
1505 /* Get the channel entry */
1506 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1508 silc_free(channel_id);
1509 COMMAND_REPLY_ERROR;
1513 channel = (SilcChannelEntry)id_cache->context;
1515 /* Get the ban list */
1516 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1518 /* Notify application */
1519 COMMAND_REPLY((ARGS, channel, tmp));
1522 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1523 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1524 silc_client_command_reply_free(cmd);
1527 SILC_CLIENT_CMD_REPLY_FUNC(close)
1529 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1530 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1531 SilcCommandStatus status;
1534 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1535 SILC_GET16_MSB(status, tmp);
1536 if (status != SILC_STATUS_OK) {
1537 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1538 "%s", silc_client_command_status_message(status));
1539 COMMAND_REPLY_ERROR;
1543 /* Notify application */
1544 COMMAND_REPLY((ARGS));
1547 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1548 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1549 silc_client_command_reply_free(cmd);
1552 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1554 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1555 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1556 SilcCommandStatus status;
1559 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1560 SILC_GET16_MSB(status, tmp);
1561 if (status != SILC_STATUS_OK) {
1562 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1563 "%s", silc_client_command_status_message(status));
1564 COMMAND_REPLY_ERROR;
1568 /* Notify application */
1569 COMMAND_REPLY((ARGS));
1572 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1573 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1574 silc_client_command_reply_free(cmd);
1577 /* Reply to LEAVE command. */
1579 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1581 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1582 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1583 SilcCommandStatus status;
1586 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1587 SILC_GET16_MSB(status, tmp);
1588 if (status != SILC_STATUS_OK) {
1589 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1590 "%s", silc_client_command_status_message(status));
1591 COMMAND_REPLY_ERROR;
1595 /* Notify application */
1596 COMMAND_REPLY((ARGS));
1599 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1600 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1601 silc_client_command_reply_free(cmd);
1604 /* Reply to USERS command. Received list of client ID's and theirs modes
1605 on the channel we requested. */
1607 SILC_CLIENT_CMD_REPLY_FUNC(users)
1609 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1610 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1611 SilcCommandStatus status;
1612 SilcIDCacheEntry id_cache = NULL;
1613 SilcChannelEntry channel;
1614 SilcChannelUser chu;
1615 SilcChannelID *channel_id = NULL;
1616 SilcBuffer client_id_list = NULL;
1617 SilcBuffer client_mode_list = NULL;
1619 uint32 tmp_len, list_count;
1621 unsigned char **res_argv = NULL;
1622 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1624 SILC_LOG_DEBUG(("Start"));
1626 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1627 SILC_GET16_MSB(status, tmp);
1628 if (status != SILC_STATUS_OK) {
1629 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1630 "%s", silc_client_command_status_message(status));
1631 COMMAND_REPLY_ERROR;
1635 /* Get channel ID */
1636 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1638 COMMAND_REPLY_ERROR;
1641 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1643 COMMAND_REPLY_ERROR;
1647 /* Get the list count */
1648 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1650 COMMAND_REPLY_ERROR;
1653 SILC_GET32_MSB(list_count, tmp);
1655 /* Get Client ID list */
1656 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1658 COMMAND_REPLY_ERROR;
1662 client_id_list = silc_buffer_alloc(tmp_len);
1663 silc_buffer_pull_tail(client_id_list, tmp_len);
1664 silc_buffer_put(client_id_list, tmp, tmp_len);
1666 /* Get client mode list */
1667 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1669 COMMAND_REPLY_ERROR;
1673 client_mode_list = silc_buffer_alloc(tmp_len);
1674 silc_buffer_pull_tail(client_mode_list, tmp_len);
1675 silc_buffer_put(client_mode_list, tmp, tmp_len);
1677 /* Get channel entry */
1678 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1680 /* Resolve the channel from server */
1681 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1683 /* Register pending command callback. After we've received the channel
1684 information we will reprocess this command reply by re-calling this
1685 USERS command reply callback. */
1686 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1687 NULL, silc_client_command_reply_users, cmd);
1690 channel = (SilcChannelEntry)id_cache->context;
1693 /* Remove old client list from channel. */
1694 silc_list_start(channel->clients);
1695 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1696 silc_list_del(channel->clients, chu);
1700 /* Cache the received Client ID's and modes. */
1701 for (i = 0; i < list_count; i++) {
1704 SilcClientID *client_id;
1705 SilcClientEntry client;
1708 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1710 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1715 SILC_GET32_MSB(mode, client_mode_list->data);
1717 /* Check if we have this client cached already. */
1719 silc_idcache_find_by_id_one_ext(conn->client_cache,
1722 silc_hash_client_id_compare, NULL,
1725 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1726 !((SilcClientEntry)id_cache->context)->realname) {
1728 if (id_cache && id_cache->context) {
1729 SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
1730 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1731 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
1732 silc_buffer_pull(client_id_list, idp_len);
1733 silc_buffer_pull(client_mode_list, 4);
1736 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1739 /* No we don't have it (or it is incomplete in information), query
1740 it from the server. Assemble argument table that will be sent
1741 for the WHOIS command later. */
1742 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1744 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1746 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1748 res_argv[res_argc] = client_id_list->data;
1749 res_argv_lens[res_argc] = idp_len;
1750 res_argv_types[res_argc] = res_argc + 3;
1753 /* Found the client, join it to the channel */
1754 client = (SilcClientEntry)id_cache->context;
1755 chu = silc_calloc(1, sizeof(*chu));
1756 chu->client = client;
1758 silc_list_add(channel->clients, chu);
1760 silc_free(client_id);
1764 silc_buffer_pull(client_id_list, idp_len);
1765 silc_buffer_pull(client_mode_list, 4);
1768 /* Query the client information from server if the list included clients
1769 that we don't know about. */
1773 /* Send the WHOIS command to server */
1774 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1775 res_argc, res_argv, res_argv_lens,
1776 res_argv_types, ++conn->cmd_ident);
1777 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1778 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1781 /* Register pending command callback. After we've received the WHOIS
1782 command reply we will reprocess this command reply by re-calling this
1783 USERS command reply callback. */
1784 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1785 NULL, silc_client_command_reply_users, cmd);
1787 silc_buffer_free(res_cmd);
1789 silc_free(channel_id);
1791 silc_free(res_argv);
1792 silc_free(res_argv_lens);
1793 silc_free(res_argv_types);
1797 /* Notify application */
1798 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1801 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1802 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1803 silc_client_command_reply_free(cmd);
1804 silc_free(channel_id);
1806 silc_buffer_free(client_id_list);
1807 if (client_mode_list)
1808 silc_buffer_free(client_mode_list);
1811 /* Received command reply to GETKEY command. WE've received the remote
1812 client's public key. */
1814 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1816 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1817 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1818 SilcCommandStatus status;
1819 SilcIDCacheEntry id_cache;
1820 SilcIDPayload idp = NULL;
1821 SilcClientID *client_id = NULL;
1822 SilcClientEntry client_entry;
1823 SilcServerID *server_id = NULL;
1824 SilcServerEntry server_entry;
1826 unsigned char *tmp, *pk;
1830 SilcPublicKey public_key = NULL;
1832 SILC_LOG_DEBUG(("Start"));
1834 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1835 SILC_GET16_MSB(status, tmp);
1836 if (status != SILC_STATUS_OK) {
1837 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1838 "%s", silc_client_command_status_message(status));
1839 COMMAND_REPLY_ERROR;
1843 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1845 COMMAND_REPLY_ERROR;
1848 idp = silc_id_payload_parse(tmp, len);
1850 COMMAND_REPLY_ERROR;
1854 /* Get the public key payload */
1855 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1857 /* Decode the public key */
1858 SILC_GET16_MSB(pk_len, tmp);
1859 SILC_GET16_MSB(type, tmp + 2);
1862 if (type != SILC_SKE_PK_TYPE_SILC) {
1863 COMMAND_REPLY_ERROR;
1867 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1868 COMMAND_REPLY_ERROR;
1873 id_type = silc_id_payload_get_type(idp);
1874 if (id_type == SILC_ID_CLIENT) {
1875 /* Received client's public key */
1876 client_id = silc_id_payload_get_id(idp);
1877 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1880 silc_hash_client_id_compare, NULL,
1882 COMMAND_REPLY_ERROR;
1886 client_entry = (SilcClientEntry)id_cache->context;
1888 /* Notify application */
1889 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1890 } else if (id_type == SILC_ID_SERVER) {
1891 /* Received server's public key */
1892 server_id = silc_id_payload_get_id(idp);
1893 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1895 COMMAND_REPLY_ERROR;
1899 server_entry = (SilcServerEntry)id_cache->context;
1901 /* Notify application */
1902 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1906 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1907 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1909 silc_id_payload_free(idp);
1911 silc_pkcs_public_key_free(public_key);
1912 silc_free(client_id);
1913 silc_free(server_id);
1914 silc_client_command_reply_free(cmd);