5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 * Command reply functions are "the otherside" of the command functions.
22 * Reply to a command sent by server is handled by these functions.
24 * The arguments received from server are also passed to the calling
25 * application through command_reply client operation. The arguments are
26 * exactly same and in same order as the server sent it. However, ID's are
27 * not sent to the application. Instead, corresponding ID entry is sent
28 * to the application. For example, instead of sending Client ID the
29 * corresponding SilcClientEntry is sent to the application. The case is
30 * same with for example Channel ID's. This way application has all the
31 * necessary data already in hand without redundant searching. If ID is
32 * received but ID entry does not exist, NULL is sent.
36 #include "clientlibincludes.h"
37 #include "client_internal.h"
39 /* Client command reply list. */
40 SilcClientCommandReply silc_command_reply_list[] =
42 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
43 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
44 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
45 SILC_CLIENT_CMD_REPLY(nick, NICK),
46 SILC_CLIENT_CMD_REPLY(list, LIST),
47 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
48 SILC_CLIENT_CMD_REPLY(invite, INVITE),
49 SILC_CLIENT_CMD_REPLY(kill, KILL),
50 SILC_CLIENT_CMD_REPLY(info, INFO),
51 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
52 SILC_CLIENT_CMD_REPLY(ping, PING),
53 SILC_CLIENT_CMD_REPLY(oper, OPER),
54 SILC_CLIENT_CMD_REPLY(join, JOIN),
55 SILC_CLIENT_CMD_REPLY(motd, MOTD),
56 SILC_CLIENT_CMD_REPLY(umode, UMODE),
57 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
58 SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
59 SILC_CLIENT_CMD_REPLY(kick, KICK),
60 SILC_CLIENT_CMD_REPLY(ban, BAN),
61 SILC_CLIENT_CMD_REPLY(close, CLOSE),
62 SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN),
63 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
64 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
65 SILC_CLIENT_CMD_REPLY(users, USERS),
66 SILC_CLIENT_CMD_REPLY(getkey, GETKEY),
71 const SilcCommandStatusMessage silc_command_status_messages[] = {
73 { STAT(NO_SUCH_NICK), "There was no such nickname" },
74 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
75 { STAT(NO_SUCH_SERVER), "No such server" },
76 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
77 { STAT(NO_RECIPIENT), "No recipient given" },
78 { STAT(UNKNOWN_COMMAND), "Unknown command" },
79 { STAT(WILDCARDS), "Unknown command" },
80 { STAT(NO_CLIENT_ID), "No Client ID given" },
81 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
82 { STAT(NO_SERVER_ID), "No Server ID given" },
83 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
84 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
85 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
86 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
87 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
88 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
89 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
90 { STAT(USER_ON_CHANNEL), "User already on the channel" },
91 { STAT(NOT_REGISTERED), "You have not registered" },
92 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
93 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
94 { STAT(PERM_DENIED), "Permission denied" },
95 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
96 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
97 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
98 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
99 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
100 { STAT(UNKNOWN_MODE), "Unknown mode" },
101 { STAT(NOT_YOU), "Cannot change mode for other users" },
102 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
103 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
104 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
105 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
106 { STAT(BAD_NICKNAME), "Bad nickname" },
107 { STAT(BAD_CHANNEL), "Bad channel name" },
108 { STAT(AUTH_FAILED), "Authentication failed" },
109 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
110 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
114 /* Command reply operation that is called at the end of all command replys.
115 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
116 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
117 #define ARGS cmd->client, cmd->sock->user_data, \
118 cmd->payload, TRUE, silc_command_get(cmd->payload), status
120 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
121 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
122 cmd->sock->user_data, cmd->payload, FALSE, \
123 silc_command_get(cmd->payload), status)
125 /* All functions that call the COMMAND_CHECK_STATUS or the
126 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
128 #define COMMAND_CHECK_STATUS \
130 SILC_LOG_DEBUG(("Start")); \
131 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
132 if (status != SILC_STATUS_OK) { \
133 COMMAND_REPLY_ERROR; \
138 #define COMMAND_CHECK_STATUS_LIST \
140 SILC_LOG_DEBUG(("Start")); \
141 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
142 if (status != SILC_STATUS_OK && \
143 status != SILC_STATUS_LIST_START && \
144 status != SILC_STATUS_LIST_ITEM && \
145 status != SILC_STATUS_LIST_END) { \
146 COMMAND_REPLY_ERROR; \
151 /* Process received command reply. */
153 void silc_client_command_reply_process(SilcClient client,
154 SilcSocketConnection sock,
155 SilcPacketContext *packet)
157 SilcBuffer buffer = packet->buffer;
158 SilcClientCommandReply *cmd;
159 SilcClientCommandReplyContext ctx;
160 SilcCommandPayload payload;
164 /* Get command reply payload from packet */
165 payload = silc_command_payload_parse(buffer);
167 /* Silently ignore bad reply packet */
168 SILC_LOG_DEBUG(("Bad command reply packet"));
172 /* Allocate command reply context. This must be free'd by the
173 command reply routine receiving it. */
174 ctx = silc_calloc(1, sizeof(*ctx));
175 ctx->client = client;
177 ctx->payload = payload;
178 ctx->args = silc_command_get_args(ctx->payload);
179 ctx->packet = packet;
180 ident = silc_command_get_ident(ctx->payload);
182 /* Check for pending commands and mark to be exeucted */
183 silc_client_command_pending_check(sock->user_data, ctx,
184 silc_command_get(ctx->payload), ident);
186 /* Execute command reply */
187 command = silc_command_get(ctx->payload);
188 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
189 if (cmd->cmd == command)
192 if (cmd == NULL || !cmd->cb) {
200 /* Returns status message string */
202 char *silc_client_command_status_message(SilcCommandStatus status)
206 for (i = 0; silc_command_status_messages[i].message; i++) {
207 if (silc_command_status_messages[i].status == status)
211 if (silc_command_status_messages[i].message == NULL)
214 return silc_command_status_messages[i].message;
217 /* Free command reply context and its internals. */
219 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
222 silc_command_payload_free(cmd->payload);
228 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
229 SilcCommandStatus status)
231 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
232 SilcClientID *client_id;
233 SilcIDCacheEntry id_cache = NULL;
234 SilcClientEntry client_entry = NULL;
237 unsigned char *id_data, *tmp;
238 char *nickname = NULL, *username = NULL;
239 char *realname = NULL;
240 uint32 idle = 0, mode = 0;
241 SilcBuffer channels = NULL;
242 unsigned char *fingerprint;
243 uint32 fingerprint_len;
245 argc = silc_argument_get_arg_num(cmd->args);
247 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
253 client_id = silc_id_payload_parse_id(id_data, len);
259 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
260 username = silc_argument_get_arg_type(cmd->args, 4, &len);
261 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
262 if (!nickname || !username || !realname) {
267 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
269 channels = silc_buffer_alloc(len);
270 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
271 silc_buffer_put(channels, tmp, len);
274 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
276 SILC_GET32_MSB(mode, tmp);
278 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
280 SILC_GET32_MSB(idle, tmp);
282 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
284 /* Check if we have this client cached already. */
285 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
287 silc_hash_client_id_compare, NULL,
289 SILC_LOG_DEBUG(("Adding new client entry"));
291 silc_client_add_client(cmd->client, conn, nickname, username, realname,
294 client_entry = (SilcClientEntry)id_cache->context;
295 silc_client_update_client(cmd->client, conn, client_entry,
296 nickname, username, realname, mode);
297 silc_free(client_id);
300 if (fingerprint && !client_entry->fingerprint) {
301 client_entry->fingerprint =
302 silc_calloc(fingerprint_len,
303 sizeof(*client_entry->fingerprint));
304 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
305 client_entry->fingerprint_len = fingerprint_len;
308 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
309 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
311 /* Notify application */
313 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
314 channels, mode, idle));
317 silc_buffer_free(channels);
320 /* Received reply for WHOIS command. This maybe called several times
321 for one WHOIS command as server may reply with list of results. */
323 SILC_CLIENT_CMD_REPLY_FUNC(whois)
325 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
326 SilcCommandStatus status;
328 COMMAND_CHECK_STATUS_LIST;
330 /* Save WHOIS info */
331 silc_client_command_reply_whois_save(cmd, status);
333 /* Pending callbacks are not executed if this was an list entry */
334 if (status != SILC_STATUS_OK &&
335 status != SILC_STATUS_LIST_END) {
336 silc_client_command_reply_free(cmd);
341 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
342 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
343 silc_client_command_reply_free(cmd);
346 /* Received reply for WHOWAS command. */
348 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
350 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
351 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
352 SilcCommandStatus status;
353 SilcClientID *client_id;
354 SilcIDCacheEntry id_cache = NULL;
355 SilcClientEntry client_entry = NULL;
357 unsigned char *id_data;
358 char *nickname, *username;
359 char *realname = NULL;
361 COMMAND_CHECK_STATUS_LIST;
363 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
369 client_id = silc_id_payload_parse_id(id_data, len);
375 /* Get the client entry, if exists */
376 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
378 silc_hash_client_id_compare, NULL,
380 client_entry = (SilcClientEntry)id_cache->context;
381 silc_free(client_id);
383 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
384 username = silc_argument_get_arg_type(cmd->args, 4, &len);
385 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
386 if (!nickname || !username) {
391 /* Notify application. We don't save any history information to any
392 cache. Just pass the data to the application for displaying on
394 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
396 /* Pending callbacks are not executed if this was an list entry */
397 if (status != SILC_STATUS_OK &&
398 status != SILC_STATUS_LIST_END) {
399 silc_client_command_reply_free(cmd);
404 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
405 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS);
406 silc_client_command_reply_free(cmd);
410 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
411 SilcCommandStatus status)
413 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
414 SilcClient client = cmd->client;
415 SilcClientID *client_id = NULL;
416 SilcServerID *server_id = NULL;
417 SilcChannelID *channel_id = NULL;
418 SilcIDCacheEntry id_cache = NULL;
419 SilcClientEntry client_entry;
420 SilcServerEntry server_entry;
421 SilcChannelEntry channel_entry;
424 unsigned char *id_data;
425 char *name = NULL, *info = NULL;
426 SilcIDPayload idp = NULL;
429 argc = silc_argument_get_arg_num(cmd->args);
431 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
436 idp = silc_id_payload_parse_data(id_data, len);
442 name = silc_argument_get_arg_type(cmd->args, 3, &len);
443 info = silc_argument_get_arg_type(cmd->args, 4, &len);
445 id_type = silc_id_payload_get_type(idp);
449 client_id = silc_id_payload_get_id(idp);
451 SILC_LOG_DEBUG(("Received client information"));
453 /* Check if we have this client cached already. */
454 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
457 silc_hash_client_id_compare, NULL,
459 SILC_LOG_DEBUG(("Adding new client entry"));
461 silc_client_add_client(cmd->client, conn, name, info, NULL,
462 silc_id_dup(client_id, id_type), 0);
464 client_entry = (SilcClientEntry)id_cache->context;
465 silc_client_update_client(cmd->client, conn, client_entry,
466 name, info, NULL, 0);
469 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
470 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
472 /* Notify application */
473 COMMAND_REPLY((ARGS, client_entry, name, info));
477 server_id = silc_id_payload_get_id(idp);
479 SILC_LOG_DEBUG(("Received server information"));
481 /* Check if we have this server cached already. */
482 if (!silc_idcache_find_by_id_one(conn->server_cache,
483 (void *)server_id, &id_cache)) {
484 SILC_LOG_DEBUG(("Adding new server entry"));
486 server_entry = silc_calloc(1, sizeof(*server_entry));
487 server_entry->server_id = silc_id_dup(server_id, id_type);
489 server_entry->server_name = strdup(name);
491 server_entry->server_info = strdup(info);
493 /* Add server to cache */
494 silc_idcache_add(conn->server_cache, server_entry->server_name,
495 server_entry->server_id, (void *)server_entry, FALSE);
497 server_entry = (SilcServerEntry)id_cache->context;
500 /* Notify application */
501 COMMAND_REPLY((ARGS, server_entry, name, info));
504 case SILC_ID_CHANNEL:
505 channel_id = silc_id_payload_get_id(idp);
507 SILC_LOG_DEBUG(("Received channel information"));
509 /* Check if we have this channel cached already. */
510 if (!silc_idcache_find_by_id_one(conn->channel_cache,
511 (void *)channel_id, &id_cache)) {
515 SILC_LOG_DEBUG(("Adding new channel entry"));
516 channel_entry = silc_client_new_channel_id(client, conn->sock,
517 strdup(name), 0, idp);
519 channel_entry = (SilcChannelEntry)id_cache->context;
522 /* Notify application */
523 COMMAND_REPLY((ARGS, channel_entry, name, info));
527 silc_id_payload_free(idp);
528 silc_free(client_id);
529 silc_free(server_id);
530 silc_free(channel_id);
533 /* Received reply for IDENTIFY command. This maybe called several times
534 for one IDENTIFY command as server may reply with list of results.
535 This is totally silent and does not print anything on screen. */
537 SILC_CLIENT_CMD_REPLY_FUNC(identify)
539 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
540 SilcCommandStatus status;
542 COMMAND_CHECK_STATUS_LIST;
544 /* Save IDENTIFY info */
545 silc_client_command_reply_identify_save(cmd, status);
547 /* Pending callbacks are not executed if this was an list entry */
548 if (status != SILC_STATUS_OK &&
549 status != SILC_STATUS_LIST_END) {
550 silc_client_command_reply_free(cmd);
555 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
556 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
557 silc_client_command_reply_free(cmd);
560 /* Received reply for command NICK. If everything went without errors
561 we just received our new Client ID. */
563 SILC_CLIENT_CMD_REPLY_FUNC(nick)
565 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
566 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
567 SilcCommandStatus status;
572 SILC_LOG_DEBUG(("Start"));
574 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
575 if (status != SILC_STATUS_OK) {
576 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
577 "Cannot set nickname: %s",
578 silc_client_command_status_message(status));
583 argc = silc_argument_get_arg_num(cmd->args);
584 if (argc < 2 || argc > 2) {
585 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
586 "Cannot set nickname: bad reply to command");
591 /* Take received Client ID */
592 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
593 idp = silc_id_payload_parse_data(tmp, len);
598 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
600 /* Notify application */
601 COMMAND_REPLY((ARGS, conn->local_entry));
604 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
605 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
606 silc_client_command_reply_free(cmd);
609 /* Received reply to the LIST command. */
611 SILC_CLIENT_CMD_REPLY_FUNC(list)
613 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
614 SilcCommandStatus status;
615 unsigned char *tmp, *name, *topic;
616 uint32 usercount = 0;
618 COMMAND_CHECK_STATUS_LIST;
620 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
621 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
622 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
624 SILC_GET32_MSB(usercount, tmp);
626 /* Notify application */
627 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
629 /* Pending callbacks are not executed if this was an list entry */
630 if (status != SILC_STATUS_OK &&
631 status != SILC_STATUS_LIST_END) {
632 silc_client_command_reply_free(cmd);
637 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
638 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
639 silc_client_command_reply_free(cmd);
642 /* Received reply to topic command. */
644 SILC_CLIENT_CMD_REPLY_FUNC(topic)
646 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
647 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
648 SilcCommandStatus status;
649 SilcChannelEntry channel;
650 SilcChannelID *channel_id = NULL;
651 SilcIDCacheEntry id_cache = NULL;
656 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
657 if (status != SILC_STATUS_OK) {
658 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
659 "%s", silc_client_command_status_message(status));
664 argc = silc_argument_get_arg_num(cmd->args);
665 if (argc < 1 || argc > 3) {
670 /* Take Channel ID */
671 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
676 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
680 channel_id = silc_id_payload_parse_id(tmp, len);
684 /* Get the channel entry */
685 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
687 silc_free(channel_id);
692 channel = (SilcChannelEntry)id_cache->context;
694 /* Notify application */
695 COMMAND_REPLY((ARGS, channel, topic));
698 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
699 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
700 silc_client_command_reply_free(cmd);
703 /* Received reply to invite command. */
705 SILC_CLIENT_CMD_REPLY_FUNC(invite)
707 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
708 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
709 SilcCommandStatus status;
710 SilcChannelEntry channel;
711 SilcChannelID *channel_id;
712 SilcIDCacheEntry id_cache;
716 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
717 SILC_GET16_MSB(status, tmp);
718 if (status != SILC_STATUS_OK) {
719 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
720 "%s", silc_client_command_status_message(status));
725 /* Take Channel ID */
726 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
730 channel_id = silc_id_payload_parse_id(tmp, len);
734 /* Get the channel entry */
735 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
737 silc_free(channel_id);
742 channel = (SilcChannelEntry)id_cache->context;
744 /* Get the invite list */
745 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
747 /* Notify application */
748 COMMAND_REPLY((ARGS, channel, tmp));
751 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
752 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
753 silc_client_command_reply_free(cmd);
756 /* Received reply to the KILL command. */
758 SILC_CLIENT_CMD_REPLY_FUNC(kill)
760 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
761 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
762 SilcCommandStatus status;
764 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
765 if (status != SILC_STATUS_OK) {
766 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
767 "%s", silc_client_command_status_message(status));
772 /* Notify application */
773 COMMAND_REPLY((ARGS));
776 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
777 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
778 silc_client_command_reply_free(cmd);
781 /* Received reply to INFO command. We receive the server ID and some
782 information about the server user requested. */
784 SILC_CLIENT_CMD_REPLY_FUNC(info)
786 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
787 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
788 SilcCommandStatus status;
790 SilcIDCacheEntry id_cache;
791 SilcServerEntry server;
792 SilcServerID *server_id = NULL;
793 char *server_name, *server_info;
796 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
797 SILC_GET16_MSB(status, tmp);
798 if (status != SILC_STATUS_OK) {
799 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
800 "%s", silc_client_command_status_message(status));
806 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
810 server_id = silc_id_payload_parse_id(tmp, len);
814 /* Get server name */
815 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
819 /* Get server info */
820 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
824 /* See whether we have this server cached. If not create it. */
825 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
827 SILC_LOG_DEBUG(("New server entry"));
829 server = silc_calloc(1, sizeof(*server));
830 server->server_name = strdup(server_name);
831 server->server_info = strdup(server_info);
832 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
834 /* Add it to the cache */
835 silc_idcache_add(conn->server_cache, server->server_name,
836 server->server_id, (void *)server, FALSE);
838 server = (SilcServerEntry)id_cache->context;
841 /* Notify application */
842 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
845 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
846 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
847 silc_free(server_id);
848 silc_client_command_reply_free(cmd);
851 /* Received reply to PING command. The reply time is shown to user. */
853 SILC_CLIENT_CMD_REPLY_FUNC(ping)
855 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
856 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
857 SilcCommandStatus status;
860 time_t diff, curtime;
862 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
863 if (status != SILC_STATUS_OK) {
864 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
865 "%s", silc_client_command_status_message(status));
870 curtime = time(NULL);
871 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
872 cmd->packet->src_id_type);
873 if (!id || !conn->ping) {
878 for (i = 0; i < conn->ping_count; i++) {
879 if (!conn->ping[i].dest_id)
881 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
882 diff = curtime - conn->ping[i].start_time;
883 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
884 "Ping reply from %s: %d second%s",
885 conn->ping[i].dest_name, diff,
886 diff == 1 ? "" : "s");
888 conn->ping[i].start_time = 0;
889 silc_free(conn->ping[i].dest_id);
890 conn->ping[i].dest_id = NULL;
891 silc_free(conn->ping[i].dest_name);
892 conn->ping[i].dest_name = NULL;
899 /* Notify application */
900 COMMAND_REPLY((ARGS));
903 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
904 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
905 silc_client_command_reply_free(cmd);
908 /* Received reply for JOIN command. */
910 SILC_CLIENT_CMD_REPLY_FUNC(join)
912 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
913 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
914 SilcCommandStatus status;
915 SilcIDPayload idp = NULL;
916 SilcChannelEntry channel;
917 SilcIDCacheEntry id_cache = NULL;
919 uint32 argc, mode, len, list_count;
920 char *topic, *tmp, *channel_name = NULL, *hmac;
921 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
924 SILC_LOG_DEBUG(("Start"));
926 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
927 if (status != SILC_STATUS_OK) {
928 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
929 "%s", silc_client_command_status_message(status));
934 argc = silc_argument_get_arg_num(cmd->args);
935 if (argc < 7 || argc > 14) {
936 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
937 "Cannot join channel: Bad reply packet");
942 /* Get channel name */
943 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
945 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
946 "Cannot join channel: Bad reply packet");
950 channel_name = strdup(tmp);
953 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
955 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
956 "Cannot join channel: Bad reply packet");
958 silc_free(channel_name);
961 idp = silc_id_payload_parse_data(tmp, len);
964 silc_free(channel_name);
968 /* Get channel mode */
969 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
971 SILC_GET32_MSB(mode, tmp);
975 /* Get channel key */
976 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
978 keyp = silc_buffer_alloc(len);
979 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
980 silc_buffer_put(keyp, tmp, len);
984 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
986 /* If we have the channel entry, remove it and create a new one */
987 channel = silc_client_get_channel(cmd->client, conn, channel_name);
989 silc_client_del_channel(cmd->client, conn, channel);
991 /* Save received Channel ID. This actually creates the channel */
992 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
994 silc_id_payload_free(idp);
996 conn->current_channel = channel;
999 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1001 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1002 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1003 "Cannot join channel: Unsupported HMAC `%s'",
1005 COMMAND_REPLY_ERROR;
1006 silc_free(channel_name);
1011 /* Get the list count */
1012 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1015 SILC_GET32_MSB(list_count, tmp);
1017 /* Get Client ID list */
1018 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1022 client_id_list = silc_buffer_alloc(len);
1023 silc_buffer_pull_tail(client_id_list, len);
1024 silc_buffer_put(client_id_list, tmp, len);
1026 /* Get client mode list */
1027 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1031 client_mode_list = silc_buffer_alloc(len);
1032 silc_buffer_pull_tail(client_mode_list, len);
1033 silc_buffer_put(client_mode_list, tmp, len);
1035 /* Add clients we received in the reply to the channel */
1036 for (i = 0; i < list_count; i++) {
1039 SilcClientID *client_id;
1040 SilcClientEntry client_entry;
1043 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1045 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1050 SILC_GET32_MSB(mode, client_mode_list->data);
1052 /* Check if we have this client cached already. */
1053 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1056 silc_hash_client_id_compare, NULL,
1058 /* No, we don't have it, add entry for it. */
1060 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1061 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1063 /* Yes, we have it already */
1064 client_entry = (SilcClientEntry)id_cache->context;
1067 /* Join the client to the channel */
1068 chu = silc_calloc(1, sizeof(*chu));
1069 chu->client = client_entry;
1071 silc_list_add(channel->clients, chu);
1072 silc_free(client_id);
1074 silc_buffer_pull(client_id_list, idp_len);
1075 silc_buffer_pull(client_mode_list, 4);
1077 silc_buffer_push(client_id_list, client_id_list->data -
1078 client_id_list->head);
1079 silc_buffer_push(client_mode_list, client_mode_list->data -
1080 client_mode_list->head);
1082 /* Save channel key */
1083 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1084 silc_client_save_channel_key(conn, keyp, channel);
1086 /* Client is now joined to the channel */
1087 channel->on_channel = TRUE;
1089 /* Notify application */
1090 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1091 keyp ? keyp->head : NULL, NULL,
1092 NULL, topic, hmac, list_count, client_id_list,
1096 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1097 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1098 silc_client_command_reply_free(cmd);
1101 silc_buffer_free(keyp);
1103 silc_buffer_free(client_id_list);
1104 if (client_mode_list)
1105 silc_buffer_free(client_mode_list);
1108 /* Received reply for MOTD command */
1110 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1112 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1113 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1114 SilcCommandStatus status;
1117 char *motd = NULL, *cp, line[256];
1119 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1120 SILC_GET16_MSB(status, tmp);
1121 if (status != SILC_STATUS_OK) {
1122 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1123 "%s", silc_client_command_status_message(status));
1124 COMMAND_REPLY_ERROR;
1128 argc = silc_argument_get_arg_num(cmd->args);
1130 COMMAND_REPLY_ERROR;
1135 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1137 COMMAND_REPLY_ERROR;
1144 if (cp[i++] == '\n') {
1145 memset(line, 0, sizeof(line));
1146 strncat(line, cp, i - 1);
1152 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1162 /* Notify application */
1163 COMMAND_REPLY((ARGS, motd));
1166 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1167 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1168 silc_client_command_reply_free(cmd);
1171 /* Received reply tot he UMODE command. Save the current user mode */
1173 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1175 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1176 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1177 SilcCommandStatus status;
1181 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1182 SILC_GET16_MSB(status, tmp);
1183 if (status != SILC_STATUS_OK) {
1184 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1185 "%s", silc_client_command_status_message(status));
1186 COMMAND_REPLY_ERROR;
1190 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1192 COMMAND_REPLY_ERROR;
1196 SILC_GET32_MSB(mode, tmp);
1197 conn->local_entry->mode = mode;
1199 /* Notify application */
1200 COMMAND_REPLY((ARGS, mode));
1203 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1204 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1205 silc_client_command_reply_free(cmd);
1208 /* Received reply for CMODE command. */
1210 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1212 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1213 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1214 SilcCommandStatus status;
1217 SilcIDCacheEntry id_cache;
1218 SilcChannelID *channel_id;
1219 SilcChannelEntry channel;
1222 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1223 if (status != SILC_STATUS_OK) {
1224 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1225 "%s", silc_client_command_status_message(status));
1226 COMMAND_REPLY_ERROR;
1230 /* Take Channel ID */
1231 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1234 channel_id = silc_id_payload_parse_id(tmp, len);
1238 /* Get the channel entry */
1239 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1241 silc_free(channel_id);
1242 COMMAND_REPLY_ERROR;
1246 channel = (SilcChannelEntry)id_cache->context;
1248 /* Get channel mode */
1249 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1251 silc_free(channel_id);
1252 COMMAND_REPLY_ERROR;
1257 SILC_GET32_MSB(mode, tmp);
1258 channel->mode = mode;
1260 /* Notify application */
1261 COMMAND_REPLY((ARGS, channel, mode));
1263 silc_free(channel_id);
1266 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1267 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1268 silc_client_command_reply_free(cmd);
1271 /* Received reply for CUMODE command */
1273 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1275 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1276 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1277 SilcCommandStatus status;
1278 SilcIDCacheEntry id_cache = NULL;
1279 SilcClientID *client_id;
1280 SilcChannelID *channel_id;
1281 SilcClientEntry client_entry;
1282 SilcChannelEntry channel;
1283 SilcChannelUser chu;
1284 unsigned char *modev, *tmp, *id;
1287 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1288 if (status != SILC_STATUS_OK) {
1289 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1290 "%s", silc_client_command_status_message(status));
1291 COMMAND_REPLY_ERROR;
1295 /* Get channel mode */
1296 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1298 COMMAND_REPLY_ERROR;
1302 /* Take Channel ID */
1303 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1306 channel_id = silc_id_payload_parse_id(tmp, len);
1310 /* Get the channel entry */
1311 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1313 silc_free(channel_id);
1314 COMMAND_REPLY_ERROR;
1318 channel = (SilcChannelEntry)id_cache->context;
1321 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1323 silc_free(channel_id);
1324 COMMAND_REPLY_ERROR;
1327 client_id = silc_id_payload_parse_id(id, len);
1329 silc_free(channel_id);
1330 COMMAND_REPLY_ERROR;
1334 /* Get client entry */
1335 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1337 silc_hash_client_id_compare, NULL,
1339 silc_free(channel_id);
1340 silc_free(client_id);
1341 COMMAND_REPLY_ERROR;
1345 client_entry = (SilcClientEntry)id_cache->context;
1348 SILC_GET32_MSB(mode, modev);
1349 silc_list_start(channel->clients);
1350 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1351 if (chu->client == client_entry) {
1357 /* Notify application */
1358 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1359 silc_free(client_id);
1360 silc_free(channel_id);
1363 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1364 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1365 silc_client_command_reply_free(cmd);
1368 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1370 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1371 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1372 SilcCommandStatus status;
1375 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1376 SILC_GET16_MSB(status, tmp);
1377 if (status != SILC_STATUS_OK) {
1378 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1379 "%s", silc_client_command_status_message(status));
1380 COMMAND_REPLY_ERROR;
1384 /* Notify application */
1385 COMMAND_REPLY((ARGS));
1388 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1389 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1390 silc_client_command_reply_free(cmd);
1393 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1395 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1396 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1397 SilcCommandStatus status;
1400 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1401 SILC_GET16_MSB(status, tmp);
1402 if (status != SILC_STATUS_OK) {
1403 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1404 "%s", silc_client_command_status_message(status));
1405 COMMAND_REPLY_ERROR;
1409 /* Notify application */
1410 COMMAND_REPLY((ARGS));
1413 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1414 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1415 silc_client_command_reply_free(cmd);
1418 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1420 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1421 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1422 SilcCommandStatus status;
1425 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1426 SILC_GET16_MSB(status, tmp);
1427 if (status != SILC_STATUS_OK) {
1428 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1429 "%s", silc_client_command_status_message(status));
1430 COMMAND_REPLY_ERROR;
1434 /* Notify application */
1435 COMMAND_REPLY((ARGS));
1438 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1439 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1440 silc_client_command_reply_free(cmd);
1443 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1445 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1446 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1447 SilcCommandStatus status;
1450 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1451 SILC_GET16_MSB(status, tmp);
1452 if (status != SILC_STATUS_OK) {
1453 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1454 "%s", silc_client_command_status_message(status));
1455 COMMAND_REPLY_ERROR;
1459 /* Notify application */
1460 COMMAND_REPLY((ARGS));
1463 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1464 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1465 silc_client_command_reply_free(cmd);
1468 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1470 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1471 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1472 SilcCommandStatus status;
1473 SilcIDCacheEntry id_cache = NULL;
1474 SilcChannelEntry channel;
1475 SilcChannelID *channel_id;
1479 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1480 SILC_GET16_MSB(status, tmp);
1481 if (status != SILC_STATUS_OK) {
1482 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1483 "%s", silc_client_command_status_message(status));
1484 COMMAND_REPLY_ERROR;
1488 /* Take Channel ID */
1489 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1493 channel_id = silc_id_payload_parse_id(tmp, len);
1497 /* Get the channel entry */
1498 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1500 silc_free(channel_id);
1501 COMMAND_REPLY_ERROR;
1505 channel = (SilcChannelEntry)id_cache->context;
1507 /* Get the ban list */
1508 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1510 /* Notify application */
1511 COMMAND_REPLY((ARGS, channel, tmp));
1514 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1515 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1516 silc_client_command_reply_free(cmd);
1519 SILC_CLIENT_CMD_REPLY_FUNC(close)
1521 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1522 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1523 SilcCommandStatus status;
1526 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1527 SILC_GET16_MSB(status, tmp);
1528 if (status != SILC_STATUS_OK) {
1529 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1530 "%s", silc_client_command_status_message(status));
1531 COMMAND_REPLY_ERROR;
1535 /* Notify application */
1536 COMMAND_REPLY((ARGS));
1539 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1540 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1541 silc_client_command_reply_free(cmd);
1544 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1546 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1547 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1548 SilcCommandStatus status;
1551 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1552 SILC_GET16_MSB(status, tmp);
1553 if (status != SILC_STATUS_OK) {
1554 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1555 "%s", silc_client_command_status_message(status));
1556 COMMAND_REPLY_ERROR;
1560 /* Notify application */
1561 COMMAND_REPLY((ARGS));
1564 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1565 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1566 silc_client_command_reply_free(cmd);
1569 /* Reply to LEAVE command. */
1571 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1573 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1574 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1575 SilcCommandStatus status;
1578 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1579 SILC_GET16_MSB(status, tmp);
1580 if (status != SILC_STATUS_OK) {
1581 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1582 "%s", silc_client_command_status_message(status));
1583 COMMAND_REPLY_ERROR;
1587 /* Notify application */
1588 COMMAND_REPLY((ARGS));
1591 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1592 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1593 silc_client_command_reply_free(cmd);
1596 /* Reply to USERS command. Received list of client ID's and theirs modes
1597 on the channel we requested. */
1599 SILC_CLIENT_CMD_REPLY_FUNC(users)
1601 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1602 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1603 SilcCommandStatus status;
1604 SilcIDCacheEntry id_cache = NULL;
1605 SilcChannelEntry channel;
1606 SilcChannelUser chu;
1607 SilcChannelID *channel_id = NULL;
1608 SilcBuffer client_id_list = NULL;
1609 SilcBuffer client_mode_list = NULL;
1611 uint32 tmp_len, list_count;
1613 unsigned char **res_argv = NULL;
1614 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1616 SILC_LOG_DEBUG(("Start"));
1618 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1619 SILC_GET16_MSB(status, tmp);
1620 if (status != SILC_STATUS_OK) {
1621 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1622 "%s", silc_client_command_status_message(status));
1623 COMMAND_REPLY_ERROR;
1627 /* Get channel ID */
1628 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1630 COMMAND_REPLY_ERROR;
1633 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1635 COMMAND_REPLY_ERROR;
1639 /* Get the list count */
1640 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1642 COMMAND_REPLY_ERROR;
1645 SILC_GET32_MSB(list_count, tmp);
1647 /* Get Client ID list */
1648 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1650 COMMAND_REPLY_ERROR;
1654 client_id_list = silc_buffer_alloc(tmp_len);
1655 silc_buffer_pull_tail(client_id_list, tmp_len);
1656 silc_buffer_put(client_id_list, tmp, tmp_len);
1658 /* Get client mode list */
1659 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1661 COMMAND_REPLY_ERROR;
1665 client_mode_list = silc_buffer_alloc(tmp_len);
1666 silc_buffer_pull_tail(client_mode_list, tmp_len);
1667 silc_buffer_put(client_mode_list, tmp, tmp_len);
1669 /* Get channel entry */
1670 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1672 /* Resolve the channel from server */
1673 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1675 /* Register pending command callback. After we've received the channel
1676 information we will reprocess this command reply by re-calling this
1677 USERS command reply callback. */
1678 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1679 NULL, silc_client_command_reply_users, cmd);
1682 channel = (SilcChannelEntry)id_cache->context;
1685 /* Remove old client list from channel. */
1686 silc_list_start(channel->clients);
1687 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1688 silc_list_del(channel->clients, chu);
1692 /* Cache the received Client ID's and modes. */
1693 for (i = 0; i < list_count; i++) {
1696 SilcClientID *client_id;
1697 SilcClientEntry client;
1700 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1702 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1707 SILC_GET32_MSB(mode, client_mode_list->data);
1709 /* Check if we have this client cached already. */
1711 silc_idcache_find_by_id_one_ext(conn->client_cache,
1714 silc_hash_client_id_compare, NULL,
1717 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1718 !((SilcClientEntry)id_cache->context)->realname) {
1720 if (id_cache && id_cache->context) {
1721 SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
1722 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1723 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
1724 silc_buffer_pull(client_id_list, idp_len);
1725 silc_buffer_pull(client_mode_list, 4);
1728 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1731 /* No we don't have it (or it is incomplete in information), query
1732 it from the server. Assemble argument table that will be sent
1733 for the WHOIS command later. */
1734 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1736 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1738 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1740 res_argv[res_argc] = client_id_list->data;
1741 res_argv_lens[res_argc] = idp_len;
1742 res_argv_types[res_argc] = res_argc + 3;
1745 /* Found the client, join it to the channel */
1746 client = (SilcClientEntry)id_cache->context;
1747 chu = silc_calloc(1, sizeof(*chu));
1748 chu->client = client;
1750 silc_list_add(channel->clients, chu);
1752 silc_free(client_id);
1756 silc_buffer_pull(client_id_list, idp_len);
1757 silc_buffer_pull(client_mode_list, 4);
1760 /* Query the client information from server if the list included clients
1761 that we don't know about. */
1765 /* Send the WHOIS command to server */
1766 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1767 res_argc, res_argv, res_argv_lens,
1768 res_argv_types, ++conn->cmd_ident);
1769 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1770 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1773 /* Register pending command callback. After we've received the WHOIS
1774 command reply we will reprocess this command reply by re-calling this
1775 USERS command reply callback. */
1776 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1777 NULL, silc_client_command_reply_users, cmd);
1779 silc_buffer_free(res_cmd);
1781 silc_free(channel_id);
1783 silc_free(res_argv);
1784 silc_free(res_argv_lens);
1785 silc_free(res_argv_types);
1789 /* Notify application */
1790 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1793 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1794 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1795 silc_client_command_reply_free(cmd);
1796 silc_free(channel_id);
1798 silc_buffer_free(client_id_list);
1799 if (client_mode_list)
1800 silc_buffer_free(client_mode_list);
1803 /* Received command reply to GETKEY command. WE've received the remote
1804 client's public key. */
1806 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1808 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1809 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1810 SilcCommandStatus status;
1811 SilcIDCacheEntry id_cache;
1812 SilcIDPayload idp = NULL;
1813 SilcClientID *client_id = NULL;
1814 SilcClientEntry client_entry;
1815 SilcServerID *server_id = NULL;
1816 SilcServerEntry server_entry;
1818 unsigned char *tmp, *pk;
1822 SilcPublicKey public_key = NULL;
1824 SILC_LOG_DEBUG(("Start"));
1826 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1827 SILC_GET16_MSB(status, tmp);
1828 if (status != SILC_STATUS_OK) {
1829 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1830 "%s", silc_client_command_status_message(status));
1831 COMMAND_REPLY_ERROR;
1835 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1837 COMMAND_REPLY_ERROR;
1840 idp = silc_id_payload_parse_data(tmp, len);
1842 COMMAND_REPLY_ERROR;
1846 /* Get the public key payload */
1847 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1849 /* Decode the public key */
1850 SILC_GET16_MSB(pk_len, tmp);
1851 SILC_GET16_MSB(type, tmp + 2);
1854 if (type != SILC_SKE_PK_TYPE_SILC) {
1855 COMMAND_REPLY_ERROR;
1859 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1860 COMMAND_REPLY_ERROR;
1865 id_type = silc_id_payload_get_type(idp);
1866 if (id_type == SILC_ID_CLIENT) {
1867 /* Received client's public key */
1868 client_id = silc_id_payload_get_id(idp);
1869 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1872 silc_hash_client_id_compare, NULL,
1874 COMMAND_REPLY_ERROR;
1878 client_entry = (SilcClientEntry)id_cache->context;
1880 /* Notify application */
1881 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1882 } else if (id_type == SILC_ID_SERVER) {
1883 /* Received server's public key */
1884 server_id = silc_id_payload_get_id(idp);
1885 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1887 COMMAND_REPLY_ERROR;
1891 server_entry = (SilcServerEntry)id_cache->context;
1893 /* Notify application */
1894 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1898 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1899 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1901 silc_id_payload_free(idp);
1903 silc_pkcs_public_key_free(public_key);
1904 silc_free(client_id);
1905 silc_free(server_id);
1906 silc_client_command_reply_free(cmd);