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 server = (SilcServerEntry)id_cache->context;
845 /* Notify application */
846 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
849 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
850 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
851 silc_free(server_id);
852 silc_client_command_reply_free(cmd);
855 /* Received reply to PING command. The reply time is shown to user. */
857 SILC_CLIENT_CMD_REPLY_FUNC(ping)
859 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
860 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
861 SilcCommandStatus status;
864 time_t diff, curtime;
866 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
867 if (status != SILC_STATUS_OK) {
868 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
869 "%s", silc_client_command_status_message(status));
874 curtime = time(NULL);
875 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
876 cmd->packet->src_id_type);
877 if (!id || !conn->ping) {
882 for (i = 0; i < conn->ping_count; i++) {
883 if (!conn->ping[i].dest_id)
885 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
886 diff = curtime - conn->ping[i].start_time;
887 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
888 "Ping reply from %s: %d second%s",
889 conn->ping[i].dest_name, diff,
890 diff == 1 ? "" : "s");
892 conn->ping[i].start_time = 0;
893 silc_free(conn->ping[i].dest_id);
894 conn->ping[i].dest_id = NULL;
895 silc_free(conn->ping[i].dest_name);
896 conn->ping[i].dest_name = NULL;
903 /* Notify application */
904 COMMAND_REPLY((ARGS));
907 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
908 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
909 silc_client_command_reply_free(cmd);
912 /* Received reply for JOIN command. */
914 SILC_CLIENT_CMD_REPLY_FUNC(join)
916 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
917 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
918 SilcCommandStatus status;
919 SilcIDPayload idp = NULL;
920 SilcChannelEntry channel;
921 SilcIDCacheEntry id_cache = NULL;
923 uint32 argc, mode, len, list_count;
924 char *topic, *tmp, *channel_name = NULL, *hmac;
925 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
928 SILC_LOG_DEBUG(("Start"));
930 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
931 if (status != SILC_STATUS_OK) {
932 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
933 "%s", silc_client_command_status_message(status));
938 argc = silc_argument_get_arg_num(cmd->args);
939 if (argc < 7 || argc > 14) {
940 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
941 "Cannot join channel: Bad reply packet");
946 /* Get channel name */
947 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
949 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
950 "Cannot join channel: Bad reply packet");
954 channel_name = strdup(tmp);
957 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
959 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
960 "Cannot join channel: Bad reply packet");
962 silc_free(channel_name);
965 idp = silc_id_payload_parse_data(tmp, len);
968 silc_free(channel_name);
972 /* Get channel mode */
973 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
975 SILC_GET32_MSB(mode, tmp);
979 /* Get channel key */
980 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
982 keyp = silc_buffer_alloc(len);
983 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
984 silc_buffer_put(keyp, tmp, len);
988 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
990 /* If we have the channel entry, remove it and create a new one */
991 channel = silc_client_get_channel(cmd->client, conn, channel_name);
993 silc_client_del_channel(cmd->client, conn, channel);
995 /* Save received Channel ID. This actually creates the channel */
996 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
998 silc_id_payload_free(idp);
1000 conn->current_channel = channel;
1003 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1005 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1006 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1007 "Cannot join channel: Unsupported HMAC `%s'",
1009 COMMAND_REPLY_ERROR;
1010 silc_free(channel_name);
1015 /* Get the list count */
1016 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1019 SILC_GET32_MSB(list_count, tmp);
1021 /* Get Client ID list */
1022 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1026 client_id_list = silc_buffer_alloc(len);
1027 silc_buffer_pull_tail(client_id_list, len);
1028 silc_buffer_put(client_id_list, tmp, len);
1030 /* Get client mode list */
1031 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1035 client_mode_list = silc_buffer_alloc(len);
1036 silc_buffer_pull_tail(client_mode_list, len);
1037 silc_buffer_put(client_mode_list, tmp, len);
1039 /* Add clients we received in the reply to the channel */
1040 for (i = 0; i < list_count; i++) {
1043 SilcClientID *client_id;
1044 SilcClientEntry client_entry;
1047 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1049 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1054 SILC_GET32_MSB(mode, client_mode_list->data);
1056 /* Check if we have this client cached already. */
1057 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1060 silc_hash_client_id_compare, NULL,
1062 /* No, we don't have it, add entry for it. */
1064 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1065 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1067 /* Yes, we have it already */
1068 client_entry = (SilcClientEntry)id_cache->context;
1071 /* Join the client to the channel */
1072 chu = silc_calloc(1, sizeof(*chu));
1073 chu->client = client_entry;
1075 silc_list_add(channel->clients, chu);
1076 silc_free(client_id);
1078 silc_buffer_pull(client_id_list, idp_len);
1079 silc_buffer_pull(client_mode_list, 4);
1081 silc_buffer_push(client_id_list, client_id_list->data -
1082 client_id_list->head);
1083 silc_buffer_push(client_mode_list, client_mode_list->data -
1084 client_mode_list->head);
1086 /* Save channel key */
1087 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1088 silc_client_save_channel_key(conn, keyp, channel);
1090 /* Client is now joined to the channel */
1091 channel->on_channel = TRUE;
1093 /* Notify application */
1094 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1095 keyp ? keyp->head : NULL, NULL,
1096 NULL, topic, hmac, list_count, client_id_list,
1100 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1101 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1102 silc_client_command_reply_free(cmd);
1105 silc_buffer_free(keyp);
1107 silc_buffer_free(client_id_list);
1108 if (client_mode_list)
1109 silc_buffer_free(client_mode_list);
1112 /* Received reply for MOTD command */
1114 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1116 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1117 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1118 SilcCommandStatus status;
1121 char *motd = NULL, *cp, line[256];
1123 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1124 SILC_GET16_MSB(status, tmp);
1125 if (status != SILC_STATUS_OK) {
1126 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1127 "%s", silc_client_command_status_message(status));
1128 COMMAND_REPLY_ERROR;
1132 argc = silc_argument_get_arg_num(cmd->args);
1134 COMMAND_REPLY_ERROR;
1139 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1141 COMMAND_REPLY_ERROR;
1148 if (cp[i++] == '\n') {
1149 memset(line, 0, sizeof(line));
1150 strncat(line, cp, i - 1);
1156 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1166 /* Notify application */
1167 COMMAND_REPLY((ARGS, motd));
1170 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1171 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1172 silc_client_command_reply_free(cmd);
1175 /* Received reply tot he UMODE command. Save the current user mode */
1177 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1179 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1180 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1181 SilcCommandStatus status;
1185 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1186 SILC_GET16_MSB(status, tmp);
1187 if (status != SILC_STATUS_OK) {
1188 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1189 "%s", silc_client_command_status_message(status));
1190 COMMAND_REPLY_ERROR;
1194 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1196 COMMAND_REPLY_ERROR;
1200 SILC_GET32_MSB(mode, tmp);
1201 conn->local_entry->mode = mode;
1203 /* Notify application */
1204 COMMAND_REPLY((ARGS, mode));
1207 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1208 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1209 silc_client_command_reply_free(cmd);
1212 /* Received reply for CMODE command. */
1214 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1216 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1217 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1218 SilcCommandStatus status;
1221 SilcIDCacheEntry id_cache;
1222 SilcChannelID *channel_id;
1223 SilcChannelEntry channel;
1226 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1227 if (status != SILC_STATUS_OK) {
1228 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1229 "%s", silc_client_command_status_message(status));
1230 COMMAND_REPLY_ERROR;
1234 /* Take Channel ID */
1235 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1238 channel_id = silc_id_payload_parse_id(tmp, len);
1242 /* Get the channel entry */
1243 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1245 silc_free(channel_id);
1246 COMMAND_REPLY_ERROR;
1250 channel = (SilcChannelEntry)id_cache->context;
1252 /* Get channel mode */
1253 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1255 silc_free(channel_id);
1256 COMMAND_REPLY_ERROR;
1261 SILC_GET32_MSB(mode, tmp);
1262 channel->mode = mode;
1264 /* Notify application */
1265 COMMAND_REPLY((ARGS, channel, mode));
1267 silc_free(channel_id);
1270 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1271 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1272 silc_client_command_reply_free(cmd);
1275 /* Received reply for CUMODE command */
1277 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1279 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1280 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1281 SilcCommandStatus status;
1282 SilcIDCacheEntry id_cache = NULL;
1283 SilcClientID *client_id;
1284 SilcChannelID *channel_id;
1285 SilcClientEntry client_entry;
1286 SilcChannelEntry channel;
1287 SilcChannelUser chu;
1288 unsigned char *modev, *tmp, *id;
1291 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1292 if (status != SILC_STATUS_OK) {
1293 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1294 "%s", silc_client_command_status_message(status));
1295 COMMAND_REPLY_ERROR;
1299 /* Get channel mode */
1300 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1302 COMMAND_REPLY_ERROR;
1306 /* Take Channel ID */
1307 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1310 channel_id = silc_id_payload_parse_id(tmp, len);
1314 /* Get the channel entry */
1315 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1317 silc_free(channel_id);
1318 COMMAND_REPLY_ERROR;
1322 channel = (SilcChannelEntry)id_cache->context;
1325 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1327 silc_free(channel_id);
1328 COMMAND_REPLY_ERROR;
1331 client_id = silc_id_payload_parse_id(id, len);
1333 silc_free(channel_id);
1334 COMMAND_REPLY_ERROR;
1338 /* Get client entry */
1339 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1341 silc_hash_client_id_compare, NULL,
1343 silc_free(channel_id);
1344 silc_free(client_id);
1345 COMMAND_REPLY_ERROR;
1349 client_entry = (SilcClientEntry)id_cache->context;
1352 SILC_GET32_MSB(mode, modev);
1353 silc_list_start(channel->clients);
1354 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1355 if (chu->client == client_entry) {
1361 /* Notify application */
1362 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1363 silc_free(client_id);
1364 silc_free(channel_id);
1367 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1368 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1369 silc_client_command_reply_free(cmd);
1372 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1374 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1375 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1376 SilcCommandStatus status;
1379 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1380 SILC_GET16_MSB(status, tmp);
1381 if (status != SILC_STATUS_OK) {
1382 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1383 "%s", silc_client_command_status_message(status));
1384 COMMAND_REPLY_ERROR;
1388 /* Notify application */
1389 COMMAND_REPLY((ARGS));
1392 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1393 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1394 silc_client_command_reply_free(cmd);
1397 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1399 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1400 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1401 SilcCommandStatus status;
1404 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1405 SILC_GET16_MSB(status, tmp);
1406 if (status != SILC_STATUS_OK) {
1407 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1408 "%s", silc_client_command_status_message(status));
1409 COMMAND_REPLY_ERROR;
1413 /* Notify application */
1414 COMMAND_REPLY((ARGS));
1417 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1418 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1419 silc_client_command_reply_free(cmd);
1422 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1424 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1425 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1426 SilcCommandStatus status;
1429 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1430 SILC_GET16_MSB(status, tmp);
1431 if (status != SILC_STATUS_OK) {
1432 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1433 "%s", silc_client_command_status_message(status));
1434 COMMAND_REPLY_ERROR;
1438 /* Notify application */
1439 COMMAND_REPLY((ARGS));
1442 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1443 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1444 silc_client_command_reply_free(cmd);
1447 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1449 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1450 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1451 SilcCommandStatus status;
1454 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1455 SILC_GET16_MSB(status, tmp);
1456 if (status != SILC_STATUS_OK) {
1457 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1458 "%s", silc_client_command_status_message(status));
1459 COMMAND_REPLY_ERROR;
1463 /* Notify application */
1464 COMMAND_REPLY((ARGS));
1467 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1468 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1469 silc_client_command_reply_free(cmd);
1472 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1474 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1475 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1476 SilcCommandStatus status;
1477 SilcIDCacheEntry id_cache = NULL;
1478 SilcChannelEntry channel;
1479 SilcChannelID *channel_id;
1483 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1484 SILC_GET16_MSB(status, tmp);
1485 if (status != SILC_STATUS_OK) {
1486 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1487 "%s", silc_client_command_status_message(status));
1488 COMMAND_REPLY_ERROR;
1492 /* Take Channel ID */
1493 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1497 channel_id = silc_id_payload_parse_id(tmp, len);
1501 /* Get the channel entry */
1502 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1504 silc_free(channel_id);
1505 COMMAND_REPLY_ERROR;
1509 channel = (SilcChannelEntry)id_cache->context;
1511 /* Get the ban list */
1512 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1514 /* Notify application */
1515 COMMAND_REPLY((ARGS, channel, tmp));
1518 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1519 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1520 silc_client_command_reply_free(cmd);
1523 SILC_CLIENT_CMD_REPLY_FUNC(close)
1525 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1526 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1527 SilcCommandStatus status;
1530 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1531 SILC_GET16_MSB(status, tmp);
1532 if (status != SILC_STATUS_OK) {
1533 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1534 "%s", silc_client_command_status_message(status));
1535 COMMAND_REPLY_ERROR;
1539 /* Notify application */
1540 COMMAND_REPLY((ARGS));
1543 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1544 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1545 silc_client_command_reply_free(cmd);
1548 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1550 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1551 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1552 SilcCommandStatus status;
1555 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1556 SILC_GET16_MSB(status, tmp);
1557 if (status != SILC_STATUS_OK) {
1558 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1559 "%s", silc_client_command_status_message(status));
1560 COMMAND_REPLY_ERROR;
1564 /* Notify application */
1565 COMMAND_REPLY((ARGS));
1568 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1569 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1570 silc_client_command_reply_free(cmd);
1573 /* Reply to LEAVE command. */
1575 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1577 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1578 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1579 SilcCommandStatus status;
1582 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1583 SILC_GET16_MSB(status, tmp);
1584 if (status != SILC_STATUS_OK) {
1585 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1586 "%s", silc_client_command_status_message(status));
1587 COMMAND_REPLY_ERROR;
1591 /* Notify application */
1592 COMMAND_REPLY((ARGS));
1595 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1596 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1597 silc_client_command_reply_free(cmd);
1600 /* Reply to USERS command. Received list of client ID's and theirs modes
1601 on the channel we requested. */
1603 SILC_CLIENT_CMD_REPLY_FUNC(users)
1605 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1606 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1607 SilcCommandStatus status;
1608 SilcIDCacheEntry id_cache = NULL;
1609 SilcChannelEntry channel;
1610 SilcChannelUser chu;
1611 SilcChannelID *channel_id = NULL;
1612 SilcBuffer client_id_list = NULL;
1613 SilcBuffer client_mode_list = NULL;
1615 uint32 tmp_len, list_count;
1617 unsigned char **res_argv = NULL;
1618 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1620 SILC_LOG_DEBUG(("Start"));
1622 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1623 SILC_GET16_MSB(status, tmp);
1624 if (status != SILC_STATUS_OK) {
1625 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1626 "%s", silc_client_command_status_message(status));
1627 COMMAND_REPLY_ERROR;
1631 /* Get channel ID */
1632 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1634 COMMAND_REPLY_ERROR;
1637 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1639 COMMAND_REPLY_ERROR;
1643 /* Get the list count */
1644 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1646 COMMAND_REPLY_ERROR;
1649 SILC_GET32_MSB(list_count, tmp);
1651 /* Get Client ID list */
1652 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1654 COMMAND_REPLY_ERROR;
1658 client_id_list = silc_buffer_alloc(tmp_len);
1659 silc_buffer_pull_tail(client_id_list, tmp_len);
1660 silc_buffer_put(client_id_list, tmp, tmp_len);
1662 /* Get client mode list */
1663 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1665 COMMAND_REPLY_ERROR;
1669 client_mode_list = silc_buffer_alloc(tmp_len);
1670 silc_buffer_pull_tail(client_mode_list, tmp_len);
1671 silc_buffer_put(client_mode_list, tmp, tmp_len);
1673 /* Get channel entry */
1674 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1676 /* Resolve the channel from server */
1677 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1679 /* Register pending command callback. After we've received the channel
1680 information we will reprocess this command reply by re-calling this
1681 USERS command reply callback. */
1682 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1683 NULL, silc_client_command_reply_users, cmd);
1686 channel = (SilcChannelEntry)id_cache->context;
1689 /* Remove old client list from channel. */
1690 silc_list_start(channel->clients);
1691 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1692 silc_list_del(channel->clients, chu);
1696 /* Cache the received Client ID's and modes. */
1697 for (i = 0; i < list_count; i++) {
1700 SilcClientID *client_id;
1701 SilcClientEntry client;
1704 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1706 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1711 SILC_GET32_MSB(mode, client_mode_list->data);
1713 /* Check if we have this client cached already. */
1715 silc_idcache_find_by_id_one_ext(conn->client_cache,
1718 silc_hash_client_id_compare, NULL,
1721 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1722 !((SilcClientEntry)id_cache->context)->realname) {
1724 if (id_cache && id_cache->context) {
1725 SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
1726 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1727 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
1728 silc_buffer_pull(client_id_list, idp_len);
1729 silc_buffer_pull(client_mode_list, 4);
1732 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1735 /* No we don't have it (or it is incomplete in information), query
1736 it from the server. Assemble argument table that will be sent
1737 for the WHOIS command later. */
1738 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1740 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1742 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1744 res_argv[res_argc] = client_id_list->data;
1745 res_argv_lens[res_argc] = idp_len;
1746 res_argv_types[res_argc] = res_argc + 3;
1749 /* Found the client, join it to the channel */
1750 client = (SilcClientEntry)id_cache->context;
1751 chu = silc_calloc(1, sizeof(*chu));
1752 chu->client = client;
1754 silc_list_add(channel->clients, chu);
1756 silc_free(client_id);
1760 silc_buffer_pull(client_id_list, idp_len);
1761 silc_buffer_pull(client_mode_list, 4);
1764 /* Query the client information from server if the list included clients
1765 that we don't know about. */
1769 /* Send the WHOIS command to server */
1770 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1771 res_argc, res_argv, res_argv_lens,
1772 res_argv_types, ++conn->cmd_ident);
1773 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1774 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1777 /* Register pending command callback. After we've received the WHOIS
1778 command reply we will reprocess this command reply by re-calling this
1779 USERS command reply callback. */
1780 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1781 NULL, silc_client_command_reply_users, cmd);
1783 silc_buffer_free(res_cmd);
1785 silc_free(channel_id);
1787 silc_free(res_argv);
1788 silc_free(res_argv_lens);
1789 silc_free(res_argv_types);
1793 /* Notify application */
1794 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1797 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1798 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1799 silc_client_command_reply_free(cmd);
1800 silc_free(channel_id);
1802 silc_buffer_free(client_id_list);
1803 if (client_mode_list)
1804 silc_buffer_free(client_mode_list);
1807 /* Received command reply to GETKEY command. WE've received the remote
1808 client's public key. */
1810 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1812 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1813 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1814 SilcCommandStatus status;
1815 SilcIDCacheEntry id_cache;
1816 SilcIDPayload idp = NULL;
1817 SilcClientID *client_id = NULL;
1818 SilcClientEntry client_entry;
1819 SilcServerID *server_id = NULL;
1820 SilcServerEntry server_entry;
1822 unsigned char *tmp, *pk;
1826 SilcPublicKey public_key = NULL;
1828 SILC_LOG_DEBUG(("Start"));
1830 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1831 SILC_GET16_MSB(status, tmp);
1832 if (status != SILC_STATUS_OK) {
1833 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1834 "%s", silc_client_command_status_message(status));
1835 COMMAND_REPLY_ERROR;
1839 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1841 COMMAND_REPLY_ERROR;
1844 idp = silc_id_payload_parse_data(tmp, len);
1846 COMMAND_REPLY_ERROR;
1850 /* Get the public key payload */
1851 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1853 /* Decode the public key */
1854 SILC_GET16_MSB(pk_len, tmp);
1855 SILC_GET16_MSB(type, tmp + 2);
1858 if (type != SILC_SKE_PK_TYPE_SILC) {
1859 COMMAND_REPLY_ERROR;
1863 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1864 COMMAND_REPLY_ERROR;
1869 id_type = silc_id_payload_get_type(idp);
1870 if (id_type == SILC_ID_CLIENT) {
1871 /* Received client's public key */
1872 client_id = silc_id_payload_get_id(idp);
1873 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1876 silc_hash_client_id_compare, NULL,
1878 COMMAND_REPLY_ERROR;
1882 client_entry = (SilcClientEntry)id_cache->context;
1884 /* Notify application */
1885 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1886 } else if (id_type == SILC_ID_SERVER) {
1887 /* Received server's public key */
1888 server_id = silc_id_payload_get_id(idp);
1889 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1891 COMMAND_REPLY_ERROR;
1895 server_entry = (SilcServerEntry)id_cache->context;
1897 /* Notify application */
1898 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1902 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1903 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1905 silc_id_payload_free(idp);
1907 silc_pkcs_public_key_free(public_key);
1908 silc_free(client_id);
1909 silc_free(server_id);
1910 silc_client_command_reply_free(cmd);