5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 * Command reply functions are "the otherside" of the command functions.
22 * Reply to a command sent by server is handled by these functions.
24 * The arguments received from server are also passed to the calling
25 * application through command_reply client operation. The arguments are
26 * exactly same and in same order as the server sent it. However, ID's are
27 * not sent to the application. Instead, corresponding ID entry is sent
28 * to the application. For example, instead of sending Client ID the
29 * corresponding SilcClientEntry is sent to the application. The case is
30 * same with for example Channel ID's. This way application has all the
31 * necessary data already in hand without redundant searching. If ID is
32 * received but ID entry does not exist, NULL is sent.
36 #include "clientlibincludes.h"
37 #include "client_internal.h"
39 /* Client command reply list. */
40 SilcClientCommandReply silc_command_reply_list[] =
42 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
43 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
44 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
45 SILC_CLIENT_CMD_REPLY(nick, NICK),
46 SILC_CLIENT_CMD_REPLY(list, LIST),
47 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
48 SILC_CLIENT_CMD_REPLY(invite, INVITE),
49 SILC_CLIENT_CMD_REPLY(kill, KILL),
50 SILC_CLIENT_CMD_REPLY(info, INFO),
51 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
52 SILC_CLIENT_CMD_REPLY(ping, PING),
53 SILC_CLIENT_CMD_REPLY(oper, OPER),
54 SILC_CLIENT_CMD_REPLY(join, JOIN),
55 SILC_CLIENT_CMD_REPLY(motd, MOTD),
56 SILC_CLIENT_CMD_REPLY(umode, UMODE),
57 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
58 SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
59 SILC_CLIENT_CMD_REPLY(kick, KICK),
60 SILC_CLIENT_CMD_REPLY(ban, BAN),
61 SILC_CLIENT_CMD_REPLY(close, CLOSE),
62 SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN),
63 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
64 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
65 SILC_CLIENT_CMD_REPLY(users, USERS),
66 SILC_CLIENT_CMD_REPLY(getkey, GETKEY),
71 const SilcCommandStatusMessage silc_command_status_messages[] = {
73 { STAT(NO_SUCH_NICK), "There was no such nickname" },
74 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
75 { STAT(NO_SUCH_SERVER), "No such server" },
76 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
77 { STAT(NO_RECIPIENT), "No recipient given" },
78 { STAT(UNKNOWN_COMMAND), "Unknown command" },
79 { STAT(WILDCARDS), "Unknown command" },
80 { STAT(NO_CLIENT_ID), "No Client ID given" },
81 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
82 { STAT(NO_SERVER_ID), "No Server ID given" },
83 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
84 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
85 { STAT(NO_SUCH_CLIENT_ID), "There is no such client" },
86 { STAT(NO_SUCH_CHANNEL_ID),"There is no such channel" },
87 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
88 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
89 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
90 { STAT(USER_ON_CHANNEL), "User already on the channel" },
91 { STAT(NOT_REGISTERED), "You have not registered" },
92 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
93 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
94 { STAT(PERM_DENIED), "Permission denied" },
95 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
96 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
97 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
98 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
99 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
100 { STAT(UNKNOWN_MODE), "Unknown mode" },
101 { STAT(NOT_YOU), "Cannot change mode for other users" },
102 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
103 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
104 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
105 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
106 { STAT(BAD_NICKNAME), "Bad nickname" },
107 { STAT(BAD_CHANNEL), "Bad channel name" },
108 { STAT(AUTH_FAILED), "Authentication failed" },
109 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
110 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
114 /* Command reply operation that is called at the end of all command replys.
115 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
116 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
117 #define ARGS cmd->client, cmd->sock->user_data, \
118 cmd->payload, TRUE, silc_command_get(cmd->payload), status
120 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
121 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
122 cmd->sock->user_data, cmd->payload, FALSE, \
123 silc_command_get(cmd->payload), status)
125 /* All functions that call the COMMAND_CHECK_STATUS or the
126 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
128 #define COMMAND_CHECK_STATUS \
130 SILC_LOG_DEBUG(("Start")); \
131 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
132 if (status != SILC_STATUS_OK) { \
133 COMMAND_REPLY_ERROR; \
138 #define COMMAND_CHECK_STATUS_LIST \
140 SILC_LOG_DEBUG(("Start")); \
141 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
142 if (status != SILC_STATUS_OK && \
143 status != SILC_STATUS_LIST_START && \
144 status != SILC_STATUS_LIST_ITEM && \
145 status != SILC_STATUS_LIST_END) { \
146 COMMAND_REPLY_ERROR; \
151 /* Process received command reply. */
153 void silc_client_command_reply_process(SilcClient client,
154 SilcSocketConnection sock,
155 SilcPacketContext *packet)
157 SilcBuffer buffer = packet->buffer;
158 SilcClientCommandReply *cmd;
159 SilcClientCommandReplyContext ctx;
160 SilcCommandPayload payload;
164 /* Get command reply payload from packet */
165 payload = silc_command_payload_parse(buffer->data, buffer->len);
167 /* Silently ignore bad reply packet */
168 SILC_LOG_DEBUG(("Bad command reply packet"));
172 /* Allocate command reply context. This must be free'd by the
173 command reply routine receiving it. */
174 ctx = silc_calloc(1, sizeof(*ctx));
175 ctx->client = client;
177 ctx->payload = payload;
178 ctx->args = silc_command_get_args(ctx->payload);
179 ctx->packet = packet;
180 ident = silc_command_get_ident(ctx->payload);
182 /* Check for pending commands and mark to be exeucted */
183 silc_client_command_pending_check(sock->user_data, ctx,
184 silc_command_get(ctx->payload), ident);
186 /* Execute command reply */
187 command = silc_command_get(ctx->payload);
188 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
189 if (cmd->cmd == command)
192 if (cmd == NULL || !cmd->cb) {
200 /* Returns status message string */
202 char *silc_client_command_status_message(SilcCommandStatus status)
206 for (i = 0; silc_command_status_messages[i].message; i++) {
207 if (silc_command_status_messages[i].status == status)
211 if (silc_command_status_messages[i].message == NULL)
214 return silc_command_status_messages[i].message;
217 /* Free command reply context and its internals. */
219 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
222 silc_command_payload_free(cmd->payload);
228 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
229 SilcCommandStatus status)
231 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
232 SilcClientID *client_id;
233 SilcIDCacheEntry id_cache = NULL;
234 SilcClientEntry client_entry = NULL;
237 unsigned char *id_data, *tmp;
238 char *nickname = NULL, *username = NULL;
239 char *realname = NULL;
240 uint32 idle = 0, mode = 0;
241 SilcBuffer channels = NULL;
242 unsigned char *fingerprint;
243 uint32 fingerprint_len;
245 argc = silc_argument_get_arg_num(cmd->args);
247 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
253 client_id = silc_id_payload_parse_id(id_data, len);
259 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
260 username = silc_argument_get_arg_type(cmd->args, 4, &len);
261 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
262 if (!nickname || !username || !realname) {
267 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
269 channels = silc_buffer_alloc(len);
270 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
271 silc_buffer_put(channels, tmp, len);
274 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
276 SILC_GET32_MSB(mode, tmp);
278 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
280 SILC_GET32_MSB(idle, tmp);
282 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
284 /* Check if we have this client cached already. */
285 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
287 silc_hash_client_id_compare, NULL,
289 SILC_LOG_DEBUG(("Adding new client entry"));
291 silc_client_add_client(cmd->client, conn, nickname, username, realname,
294 client_entry = (SilcClientEntry)id_cache->context;
295 silc_client_update_client(cmd->client, conn, client_entry,
296 nickname, username, realname, mode);
297 silc_free(client_id);
300 if (fingerprint && !client_entry->fingerprint) {
301 client_entry->fingerprint =
302 silc_calloc(fingerprint_len,
303 sizeof(*client_entry->fingerprint));
304 memcpy(client_entry->fingerprint, fingerprint, fingerprint_len);
305 client_entry->fingerprint_len = fingerprint_len;
308 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
309 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
311 /* Notify application */
313 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
314 channels, mode, idle, fingerprint));
317 silc_buffer_free(channels);
320 /* Received reply for WHOIS command. This maybe called several times
321 for one WHOIS command as server may reply with list of results. */
323 SILC_CLIENT_CMD_REPLY_FUNC(whois)
325 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
326 SilcCommandStatus status;
328 COMMAND_CHECK_STATUS_LIST;
330 /* Save WHOIS info */
331 silc_client_command_reply_whois_save(cmd, status);
333 /* Pending callbacks are not executed if this was an list entry */
334 if (status != SILC_STATUS_OK &&
335 status != SILC_STATUS_LIST_END) {
336 silc_client_command_reply_free(cmd);
341 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
342 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
343 silc_client_command_reply_free(cmd);
346 /* Received reply for WHOWAS command. */
348 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
350 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
351 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
352 SilcCommandStatus status;
353 SilcClientID *client_id;
354 SilcIDCacheEntry id_cache = NULL;
355 SilcClientEntry client_entry = NULL;
357 unsigned char *id_data;
358 char *nickname, *username;
359 char *realname = NULL;
361 COMMAND_CHECK_STATUS_LIST;
363 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
369 client_id = silc_id_payload_parse_id(id_data, len);
375 /* Get the client entry, if exists */
376 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
378 silc_hash_client_id_compare, NULL,
380 client_entry = (SilcClientEntry)id_cache->context;
381 silc_free(client_id);
383 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
384 username = silc_argument_get_arg_type(cmd->args, 4, &len);
385 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
386 if (!nickname || !username) {
391 /* Notify application. We don't save any history information to any
392 cache. Just pass the data to the application for displaying on
394 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
396 /* Pending callbacks are not executed if this was an list entry */
397 if (status != SILC_STATUS_OK &&
398 status != SILC_STATUS_LIST_END) {
399 silc_client_command_reply_free(cmd);
404 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
405 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS);
406 silc_client_command_reply_free(cmd);
410 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
411 SilcCommandStatus status)
413 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
414 SilcClient client = cmd->client;
415 SilcClientID *client_id = NULL;
416 SilcServerID *server_id = NULL;
417 SilcChannelID *channel_id = NULL;
418 SilcIDCacheEntry id_cache = NULL;
419 SilcClientEntry client_entry;
420 SilcServerEntry server_entry;
421 SilcChannelEntry channel_entry;
424 unsigned char *id_data;
425 char *name = NULL, *info = NULL;
426 SilcIDPayload idp = NULL;
429 argc = silc_argument_get_arg_num(cmd->args);
431 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
436 idp = silc_id_payload_parse(id_data, len);
442 name = silc_argument_get_arg_type(cmd->args, 3, &len);
443 info = silc_argument_get_arg_type(cmd->args, 4, &len);
445 id_type = silc_id_payload_get_type(idp);
449 client_id = silc_id_payload_get_id(idp);
451 SILC_LOG_DEBUG(("Received client information"));
453 /* Check if we have this client cached already. */
454 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
457 silc_hash_client_id_compare, NULL,
459 SILC_LOG_DEBUG(("Adding new client entry"));
461 silc_client_add_client(cmd->client, conn, name, info, NULL,
462 silc_id_dup(client_id, id_type), 0);
464 client_entry = (SilcClientEntry)id_cache->context;
465 silc_client_update_client(cmd->client, conn, client_entry,
466 name, info, NULL, 0);
469 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING)
470 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
472 /* Notify application */
473 COMMAND_REPLY((ARGS, client_entry, name, info));
477 server_id = silc_id_payload_get_id(idp);
479 SILC_LOG_DEBUG(("Received server information"));
481 /* Check if we have this server cached already. */
482 if (!silc_idcache_find_by_id_one(conn->server_cache,
483 (void *)server_id, &id_cache)) {
484 SILC_LOG_DEBUG(("Adding new server entry"));
486 server_entry = silc_calloc(1, sizeof(*server_entry));
487 server_entry->server_id = silc_id_dup(server_id, id_type);
489 server_entry->server_name = strdup(name);
491 server_entry->server_info = strdup(info);
493 /* Add server to cache */
494 silc_idcache_add(conn->server_cache, server_entry->server_name,
495 server_entry->server_id, (void *)server_entry,
498 server_entry = (SilcServerEntry)id_cache->context;
501 /* Notify application */
502 COMMAND_REPLY((ARGS, server_entry, name, info));
505 case SILC_ID_CHANNEL:
506 channel_id = silc_id_payload_get_id(idp);
508 SILC_LOG_DEBUG(("Received channel information"));
510 /* Check if we have this channel cached already. */
511 if (!silc_idcache_find_by_id_one(conn->channel_cache,
512 (void *)channel_id, &id_cache)) {
516 SILC_LOG_DEBUG(("Adding new channel entry"));
517 channel_entry = silc_client_new_channel_id(client, conn->sock,
518 strdup(name), 0, idp);
520 channel_entry = (SilcChannelEntry)id_cache->context;
523 /* Notify application */
524 COMMAND_REPLY((ARGS, channel_entry, name, info));
528 silc_id_payload_free(idp);
529 silc_free(client_id);
530 silc_free(server_id);
531 silc_free(channel_id);
534 /* Received reply for IDENTIFY command. This maybe called several times
535 for one IDENTIFY command as server may reply with list of results.
536 This is totally silent and does not print anything on screen. */
538 SILC_CLIENT_CMD_REPLY_FUNC(identify)
540 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
541 SilcCommandStatus status;
543 COMMAND_CHECK_STATUS_LIST;
545 /* Save IDENTIFY info */
546 silc_client_command_reply_identify_save(cmd, status);
548 /* Pending callbacks are not executed if this was an list entry */
549 if (status != SILC_STATUS_OK &&
550 status != SILC_STATUS_LIST_END) {
551 silc_client_command_reply_free(cmd);
556 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
557 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
558 silc_client_command_reply_free(cmd);
561 /* Received reply for command NICK. If everything went without errors
562 we just received our new Client ID. */
564 SILC_CLIENT_CMD_REPLY_FUNC(nick)
566 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
567 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
568 SilcCommandStatus status;
573 SILC_LOG_DEBUG(("Start"));
575 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
576 if (status != SILC_STATUS_OK) {
577 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
578 "Cannot set nickname: %s",
579 silc_client_command_status_message(status));
584 argc = silc_argument_get_arg_num(cmd->args);
585 if (argc < 2 || argc > 2) {
586 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
587 "Cannot set nickname: bad reply to command");
592 /* Take received Client ID */
593 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
594 idp = silc_id_payload_parse(tmp, len);
599 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
601 /* Notify application */
602 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
603 COMMAND_REPLY((ARGS, conn->local_entry));
604 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
605 silc_client_command_reply_free(cmd);
609 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
610 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
611 silc_client_command_reply_free(cmd);
614 /* Received reply to the LIST command. */
616 SILC_CLIENT_CMD_REPLY_FUNC(list)
618 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
619 SilcCommandStatus status;
620 unsigned char *tmp, *name, *topic;
621 uint32 usercount = 0;
623 COMMAND_CHECK_STATUS_LIST;
625 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
626 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
627 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
629 SILC_GET32_MSB(usercount, tmp);
631 /* Notify application */
632 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
634 /* Pending callbacks are not executed if this was an list entry */
635 if (status != SILC_STATUS_OK &&
636 status != SILC_STATUS_LIST_END) {
637 silc_client_command_reply_free(cmd);
642 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
643 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
644 silc_client_command_reply_free(cmd);
647 /* Received reply to topic command. */
649 SILC_CLIENT_CMD_REPLY_FUNC(topic)
651 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
652 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
653 SilcCommandStatus status;
654 SilcChannelEntry channel;
655 SilcChannelID *channel_id = NULL;
656 SilcIDCacheEntry id_cache = NULL;
661 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
662 if (status != SILC_STATUS_OK) {
663 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
664 "%s", silc_client_command_status_message(status));
669 argc = silc_argument_get_arg_num(cmd->args);
670 if (argc < 1 || argc > 3) {
675 /* Take Channel ID */
676 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
681 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
685 channel_id = silc_id_payload_parse_id(tmp, len);
689 /* Get the channel entry */
690 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
692 silc_free(channel_id);
697 channel = (SilcChannelEntry)id_cache->context;
699 /* Notify application */
700 COMMAND_REPLY((ARGS, channel, topic));
703 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
704 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
705 silc_client_command_reply_free(cmd);
708 /* Received reply to invite command. */
710 SILC_CLIENT_CMD_REPLY_FUNC(invite)
712 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
713 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
714 SilcCommandStatus status;
715 SilcChannelEntry channel;
716 SilcChannelID *channel_id;
717 SilcIDCacheEntry id_cache;
721 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
722 SILC_GET16_MSB(status, tmp);
723 if (status != SILC_STATUS_OK) {
724 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
725 "%s", silc_client_command_status_message(status));
730 /* Take Channel ID */
731 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
735 channel_id = silc_id_payload_parse_id(tmp, len);
739 /* Get the channel entry */
740 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
742 silc_free(channel_id);
747 channel = (SilcChannelEntry)id_cache->context;
749 /* Get the invite list */
750 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
752 /* Notify application */
753 COMMAND_REPLY((ARGS, channel, tmp));
756 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
757 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
758 silc_client_command_reply_free(cmd);
761 /* Received reply to the KILL command. */
763 SILC_CLIENT_CMD_REPLY_FUNC(kill)
765 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
766 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
767 SilcCommandStatus status;
769 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
770 if (status != SILC_STATUS_OK) {
771 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
772 "%s", silc_client_command_status_message(status));
777 /* Notify application */
778 COMMAND_REPLY((ARGS));
781 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
782 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
783 silc_client_command_reply_free(cmd);
786 /* Received reply to INFO command. We receive the server ID and some
787 information about the server user requested. */
789 SILC_CLIENT_CMD_REPLY_FUNC(info)
791 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
792 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
793 SilcCommandStatus status;
795 SilcIDCacheEntry id_cache;
796 SilcServerEntry server;
797 SilcServerID *server_id = NULL;
798 char *server_name, *server_info;
801 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
802 SILC_GET16_MSB(status, tmp);
803 if (status != SILC_STATUS_OK) {
804 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
805 "%s", silc_client_command_status_message(status));
811 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
815 server_id = silc_id_payload_parse_id(tmp, len);
819 /* Get server name */
820 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
824 /* Get server info */
825 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
829 /* See whether we have this server cached. If not create it. */
830 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
832 SILC_LOG_DEBUG(("New server entry"));
834 server = silc_calloc(1, sizeof(*server));
835 server->server_name = strdup(server_name);
836 server->server_info = strdup(server_info);
837 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
839 /* Add it to the cache */
840 silc_idcache_add(conn->server_cache, server->server_name,
841 server->server_id, (void *)server, 0, NULL);
843 if (SILC_ID_SERVER_COMPARE(server_id, conn->remote_id))
846 server = (SilcServerEntry)id_cache->context;
849 /* Notify application */
850 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
853 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
854 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
855 silc_free(server_id);
856 silc_client_command_reply_free(cmd);
859 /* Received reply to PING command. The reply time is shown to user. */
861 SILC_CLIENT_CMD_REPLY_FUNC(ping)
863 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
864 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
865 SilcCommandStatus status;
868 time_t diff, curtime;
870 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
871 if (status != SILC_STATUS_OK) {
872 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
873 "%s", silc_client_command_status_message(status));
878 curtime = time(NULL);
879 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
880 cmd->packet->src_id_type);
881 if (!id || !conn->ping) {
886 for (i = 0; i < conn->ping_count; i++) {
887 if (!conn->ping[i].dest_id)
889 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
890 diff = curtime - conn->ping[i].start_time;
891 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
892 "Ping reply from %s: %d second%s",
893 conn->ping[i].dest_name, diff,
894 diff == 1 ? "" : "s");
896 conn->ping[i].start_time = 0;
897 silc_free(conn->ping[i].dest_id);
898 conn->ping[i].dest_id = NULL;
899 silc_free(conn->ping[i].dest_name);
900 conn->ping[i].dest_name = NULL;
907 /* Notify application */
908 COMMAND_REPLY((ARGS));
911 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
912 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
913 silc_client_command_reply_free(cmd);
916 /* Received reply for JOIN command. */
918 SILC_CLIENT_CMD_REPLY_FUNC(join)
920 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
921 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
922 SilcCommandStatus status;
923 SilcIDPayload idp = NULL;
924 SilcChannelEntry channel;
925 SilcIDCacheEntry id_cache = NULL;
927 uint32 argc, mode, len, list_count;
928 char *topic, *tmp, *channel_name = NULL, *hmac;
929 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
932 SILC_LOG_DEBUG(("Start"));
934 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
935 if (status != SILC_STATUS_OK) {
936 if (status != SILC_STATUS_ERR_USER_ON_CHANNEL)
937 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
938 "%s", silc_client_command_status_message(status));
943 argc = silc_argument_get_arg_num(cmd->args);
944 if (argc < 7 || argc > 14) {
945 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
946 "Cannot join channel: Bad reply packet");
951 /* Get channel name */
952 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
954 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
955 "Cannot join channel: Bad reply packet");
959 channel_name = strdup(tmp);
962 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
964 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
965 "Cannot join channel: Bad reply packet");
967 silc_free(channel_name);
970 idp = silc_id_payload_parse(tmp, len);
973 silc_free(channel_name);
977 /* Get channel mode */
978 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
980 SILC_GET32_MSB(mode, tmp);
984 /* Get channel key */
985 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
987 keyp = silc_buffer_alloc(len);
988 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
989 silc_buffer_put(keyp, tmp, len);
993 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
995 /* If we have the channel entry, remove it and create a new one */
996 channel = silc_client_get_channel(cmd->client, conn, channel_name);
998 silc_client_del_channel(cmd->client, conn, channel);
1000 /* Save received Channel ID. This actually creates the channel */
1001 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
1003 silc_id_payload_free(idp);
1005 conn->current_channel = channel;
1008 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1010 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1011 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1012 "Cannot join channel: Unsupported HMAC `%s'",
1014 COMMAND_REPLY_ERROR;
1015 silc_free(channel_name);
1020 /* Get the list count */
1021 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1024 SILC_GET32_MSB(list_count, tmp);
1026 /* Get Client ID list */
1027 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1031 client_id_list = silc_buffer_alloc(len);
1032 silc_buffer_pull_tail(client_id_list, len);
1033 silc_buffer_put(client_id_list, tmp, len);
1035 /* Get client mode list */
1036 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1040 client_mode_list = silc_buffer_alloc(len);
1041 silc_buffer_pull_tail(client_mode_list, len);
1042 silc_buffer_put(client_mode_list, tmp, len);
1044 /* Add clients we received in the reply to the channel */
1045 for (i = 0; i < list_count; i++) {
1048 SilcClientID *client_id;
1049 SilcClientEntry client_entry;
1052 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1054 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1059 SILC_GET32_MSB(mode, client_mode_list->data);
1061 /* Check if we have this client cached already. */
1062 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1065 silc_hash_client_id_compare, NULL,
1067 /* No, we don't have it, add entry for it. */
1069 silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
1070 silc_id_dup(client_id, SILC_ID_CLIENT), 0);
1072 /* Yes, we have it already */
1073 client_entry = (SilcClientEntry)id_cache->context;
1076 /* Join the client to the channel */
1077 chu = silc_calloc(1, sizeof(*chu));
1078 chu->client = client_entry;
1080 silc_list_add(channel->clients, chu);
1081 silc_free(client_id);
1083 silc_buffer_pull(client_id_list, idp_len);
1084 silc_buffer_pull(client_mode_list, 4);
1086 silc_buffer_push(client_id_list, client_id_list->data -
1087 client_id_list->head);
1088 silc_buffer_push(client_mode_list, client_mode_list->data -
1089 client_mode_list->head);
1091 /* Save channel key */
1092 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1093 silc_client_save_channel_key(conn, keyp, channel);
1095 /* Client is now joined to the channel */
1096 channel->on_channel = TRUE;
1098 /* Notify application */
1099 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1100 keyp ? keyp->head : NULL, NULL,
1101 NULL, topic, hmac, list_count, client_id_list,
1105 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1106 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1107 silc_client_command_reply_free(cmd);
1110 silc_buffer_free(keyp);
1112 silc_buffer_free(client_id_list);
1113 if (client_mode_list)
1114 silc_buffer_free(client_mode_list);
1117 /* Received reply for MOTD command */
1119 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1121 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1122 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1123 SilcCommandStatus status;
1126 char *motd = NULL, *cp, line[256];
1128 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1129 SILC_GET16_MSB(status, tmp);
1130 if (status != SILC_STATUS_OK) {
1131 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1132 "%s", silc_client_command_status_message(status));
1133 COMMAND_REPLY_ERROR;
1137 argc = silc_argument_get_arg_num(cmd->args);
1139 COMMAND_REPLY_ERROR;
1144 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1146 COMMAND_REPLY_ERROR;
1153 if (cp[i++] == '\n') {
1154 memset(line, 0, sizeof(line));
1155 strncat(line, cp, i - 1);
1161 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1171 /* Notify application */
1172 COMMAND_REPLY((ARGS, motd));
1175 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1176 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1177 silc_client_command_reply_free(cmd);
1180 /* Received reply tot he UMODE command. Save the current user mode */
1182 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1184 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1185 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1186 SilcCommandStatus status;
1190 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1191 SILC_GET16_MSB(status, tmp);
1192 if (status != SILC_STATUS_OK) {
1193 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1194 "%s", silc_client_command_status_message(status));
1195 COMMAND_REPLY_ERROR;
1199 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1201 COMMAND_REPLY_ERROR;
1205 SILC_GET32_MSB(mode, tmp);
1206 conn->local_entry->mode = mode;
1208 /* Notify application */
1209 COMMAND_REPLY((ARGS, mode));
1212 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1213 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1214 silc_client_command_reply_free(cmd);
1217 /* Received reply for CMODE command. */
1219 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1221 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1222 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1223 SilcCommandStatus status;
1226 SilcIDCacheEntry id_cache;
1227 SilcChannelID *channel_id;
1228 SilcChannelEntry channel;
1231 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1232 if (status != SILC_STATUS_OK) {
1233 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1234 "%s", silc_client_command_status_message(status));
1235 COMMAND_REPLY_ERROR;
1239 /* Take Channel ID */
1240 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1243 channel_id = silc_id_payload_parse_id(tmp, len);
1247 /* Get the channel entry */
1248 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1250 silc_free(channel_id);
1251 COMMAND_REPLY_ERROR;
1255 channel = (SilcChannelEntry)id_cache->context;
1257 /* Get channel mode */
1258 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1260 silc_free(channel_id);
1261 COMMAND_REPLY_ERROR;
1266 SILC_GET32_MSB(mode, tmp);
1267 channel->mode = mode;
1269 /* Notify application */
1270 COMMAND_REPLY((ARGS, channel, mode));
1272 silc_free(channel_id);
1275 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1276 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1277 silc_client_command_reply_free(cmd);
1280 /* Received reply for CUMODE command */
1282 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1284 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1285 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1286 SilcCommandStatus status;
1287 SilcIDCacheEntry id_cache = NULL;
1288 SilcClientID *client_id;
1289 SilcChannelID *channel_id;
1290 SilcClientEntry client_entry;
1291 SilcChannelEntry channel;
1292 SilcChannelUser chu;
1293 unsigned char *modev, *tmp, *id;
1296 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1297 if (status != SILC_STATUS_OK) {
1298 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1299 "%s", silc_client_command_status_message(status));
1300 COMMAND_REPLY_ERROR;
1304 /* Get channel mode */
1305 modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
1307 COMMAND_REPLY_ERROR;
1311 /* Take Channel ID */
1312 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1315 channel_id = silc_id_payload_parse_id(tmp, len);
1319 /* Get the channel entry */
1320 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1322 silc_free(channel_id);
1323 COMMAND_REPLY_ERROR;
1327 channel = (SilcChannelEntry)id_cache->context;
1330 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1332 silc_free(channel_id);
1333 COMMAND_REPLY_ERROR;
1336 client_id = silc_id_payload_parse_id(id, len);
1338 silc_free(channel_id);
1339 COMMAND_REPLY_ERROR;
1343 /* Get client entry */
1344 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1346 silc_hash_client_id_compare, NULL,
1348 silc_free(channel_id);
1349 silc_free(client_id);
1350 COMMAND_REPLY_ERROR;
1354 client_entry = (SilcClientEntry)id_cache->context;
1357 SILC_GET32_MSB(mode, modev);
1358 silc_list_start(channel->clients);
1359 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1360 if (chu->client == client_entry) {
1366 /* Notify application */
1367 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1368 silc_free(client_id);
1369 silc_free(channel_id);
1372 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1373 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1374 silc_client_command_reply_free(cmd);
1377 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1379 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1380 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1381 SilcCommandStatus status;
1384 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1385 SILC_GET16_MSB(status, tmp);
1386 if (status != SILC_STATUS_OK) {
1387 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1388 "%s", silc_client_command_status_message(status));
1389 COMMAND_REPLY_ERROR;
1393 /* Notify application */
1394 COMMAND_REPLY((ARGS));
1397 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1398 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1399 silc_client_command_reply_free(cmd);
1402 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1404 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1405 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1406 SilcCommandStatus status;
1409 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1410 SILC_GET16_MSB(status, tmp);
1411 if (status != SILC_STATUS_OK) {
1412 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1413 "%s", silc_client_command_status_message(status));
1414 COMMAND_REPLY_ERROR;
1418 /* Notify application */
1419 COMMAND_REPLY((ARGS));
1422 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1423 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1424 silc_client_command_reply_free(cmd);
1427 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1429 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1430 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1431 SilcCommandStatus status;
1434 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1435 SILC_GET16_MSB(status, tmp);
1436 if (status != SILC_STATUS_OK) {
1437 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1438 "%s", silc_client_command_status_message(status));
1439 COMMAND_REPLY_ERROR;
1443 /* Notify application */
1444 COMMAND_REPLY((ARGS));
1447 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1448 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1449 silc_client_command_reply_free(cmd);
1452 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1454 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1455 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1456 SilcCommandStatus status;
1459 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1460 SILC_GET16_MSB(status, tmp);
1461 if (status != SILC_STATUS_OK) {
1462 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1463 "%s", silc_client_command_status_message(status));
1464 COMMAND_REPLY_ERROR;
1468 /* Notify application */
1469 COMMAND_REPLY((ARGS));
1472 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1473 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1474 silc_client_command_reply_free(cmd);
1477 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1479 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1480 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1481 SilcCommandStatus status;
1482 SilcIDCacheEntry id_cache = NULL;
1483 SilcChannelEntry channel;
1484 SilcChannelID *channel_id;
1488 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1489 SILC_GET16_MSB(status, tmp);
1490 if (status != SILC_STATUS_OK) {
1491 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1492 "%s", silc_client_command_status_message(status));
1493 COMMAND_REPLY_ERROR;
1497 /* Take Channel ID */
1498 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1502 channel_id = silc_id_payload_parse_id(tmp, len);
1506 /* Get the channel entry */
1507 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1509 silc_free(channel_id);
1510 COMMAND_REPLY_ERROR;
1514 channel = (SilcChannelEntry)id_cache->context;
1516 /* Get the ban list */
1517 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1519 /* Notify application */
1520 COMMAND_REPLY((ARGS, channel, tmp));
1523 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1524 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1525 silc_client_command_reply_free(cmd);
1528 SILC_CLIENT_CMD_REPLY_FUNC(close)
1530 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1531 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1532 SilcCommandStatus status;
1535 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1536 SILC_GET16_MSB(status, tmp);
1537 if (status != SILC_STATUS_OK) {
1538 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1539 "%s", silc_client_command_status_message(status));
1540 COMMAND_REPLY_ERROR;
1544 /* Notify application */
1545 COMMAND_REPLY((ARGS));
1548 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1549 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1550 silc_client_command_reply_free(cmd);
1553 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1555 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1556 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1557 SilcCommandStatus status;
1560 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1561 SILC_GET16_MSB(status, tmp);
1562 if (status != SILC_STATUS_OK) {
1563 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1564 "%s", silc_client_command_status_message(status));
1565 COMMAND_REPLY_ERROR;
1569 /* Notify application */
1570 COMMAND_REPLY((ARGS));
1573 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1574 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1575 silc_client_command_reply_free(cmd);
1578 /* Reply to LEAVE command. */
1580 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1582 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1583 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1584 SilcCommandStatus status;
1587 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1588 SILC_GET16_MSB(status, tmp);
1589 if (status != SILC_STATUS_OK) {
1590 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1591 "%s", silc_client_command_status_message(status));
1592 COMMAND_REPLY_ERROR;
1596 /* Notify application */
1597 COMMAND_REPLY((ARGS));
1600 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1601 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1602 silc_client_command_reply_free(cmd);
1605 /* Reply to USERS command. Received list of client ID's and theirs modes
1606 on the channel we requested. */
1608 SILC_CLIENT_CMD_REPLY_FUNC(users)
1610 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1611 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1612 SilcCommandStatus status;
1613 SilcIDCacheEntry id_cache = NULL;
1614 SilcChannelEntry channel;
1615 SilcChannelUser chu;
1616 SilcChannelID *channel_id = NULL;
1617 SilcBuffer client_id_list = NULL;
1618 SilcBuffer client_mode_list = NULL;
1620 uint32 tmp_len, list_count;
1622 unsigned char **res_argv = NULL;
1623 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1625 SILC_LOG_DEBUG(("Start"));
1627 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1628 SILC_GET16_MSB(status, tmp);
1629 if (status != SILC_STATUS_OK) {
1630 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1631 "%s", silc_client_command_status_message(status));
1632 COMMAND_REPLY_ERROR;
1636 /* Get channel ID */
1637 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1639 COMMAND_REPLY_ERROR;
1642 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1644 COMMAND_REPLY_ERROR;
1648 /* Get the list count */
1649 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1651 COMMAND_REPLY_ERROR;
1654 SILC_GET32_MSB(list_count, tmp);
1656 /* Get Client ID list */
1657 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1659 COMMAND_REPLY_ERROR;
1663 client_id_list = silc_buffer_alloc(tmp_len);
1664 silc_buffer_pull_tail(client_id_list, tmp_len);
1665 silc_buffer_put(client_id_list, tmp, tmp_len);
1667 /* Get client mode list */
1668 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1670 COMMAND_REPLY_ERROR;
1674 client_mode_list = silc_buffer_alloc(tmp_len);
1675 silc_buffer_pull_tail(client_mode_list, tmp_len);
1676 silc_buffer_put(client_mode_list, tmp, tmp_len);
1678 /* Get channel entry */
1679 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1681 /* Resolve the channel from server */
1682 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1684 /* Register pending command callback. After we've received the channel
1685 information we will reprocess this command reply by re-calling this
1686 USERS command reply callback. */
1687 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1688 NULL, silc_client_command_reply_users, cmd);
1691 channel = (SilcChannelEntry)id_cache->context;
1694 /* Remove old client list from channel. */
1695 silc_list_start(channel->clients);
1696 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1697 silc_list_del(channel->clients, chu);
1701 /* Cache the received Client ID's and modes. */
1702 for (i = 0; i < list_count; i++) {
1705 SilcClientID *client_id;
1706 SilcClientEntry client;
1709 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1711 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1716 SILC_GET32_MSB(mode, client_mode_list->data);
1718 /* Check if we have this client cached already. */
1720 silc_idcache_find_by_id_one_ext(conn->client_cache,
1723 silc_hash_client_id_compare, NULL,
1726 if (!id_cache || !((SilcClientEntry)id_cache->context)->username ||
1727 !((SilcClientEntry)id_cache->context)->realname) {
1729 if (id_cache && id_cache->context) {
1730 SilcClientEntry client_entry = (SilcClientEntry)id_cache->context;
1731 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
1732 client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
1733 silc_buffer_pull(client_id_list, idp_len);
1734 silc_buffer_pull(client_mode_list, 4);
1737 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
1740 /* No we don't have it (or it is incomplete in information), query
1741 it from the server. Assemble argument table that will be sent
1742 for the WHOIS command later. */
1743 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1745 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1747 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1749 res_argv[res_argc] = client_id_list->data;
1750 res_argv_lens[res_argc] = idp_len;
1751 res_argv_types[res_argc] = res_argc + 3;
1754 /* Found the client, join it to the channel */
1755 client = (SilcClientEntry)id_cache->context;
1756 chu = silc_calloc(1, sizeof(*chu));
1757 chu->client = client;
1759 silc_list_add(channel->clients, chu);
1761 silc_free(client_id);
1765 silc_buffer_pull(client_id_list, idp_len);
1766 silc_buffer_pull(client_mode_list, 4);
1769 /* Query the client information from server if the list included clients
1770 that we don't know about. */
1774 /* Send the WHOIS command to server */
1775 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1776 res_argc, res_argv, res_argv_lens,
1777 res_argv_types, ++conn->cmd_ident);
1778 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1779 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1782 /* Register pending command callback. After we've received the WHOIS
1783 command reply we will reprocess this command reply by re-calling this
1784 USERS command reply callback. */
1785 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1786 NULL, silc_client_command_reply_users, cmd);
1788 silc_buffer_free(res_cmd);
1790 silc_free(channel_id);
1792 silc_free(res_argv);
1793 silc_free(res_argv_lens);
1794 silc_free(res_argv_types);
1798 /* Notify application */
1799 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1802 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1803 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1804 silc_client_command_reply_free(cmd);
1805 silc_free(channel_id);
1807 silc_buffer_free(client_id_list);
1808 if (client_mode_list)
1809 silc_buffer_free(client_mode_list);
1812 /* Received command reply to GETKEY command. WE've received the remote
1813 client's public key. */
1815 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1817 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1818 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1819 SilcCommandStatus status;
1820 SilcIDCacheEntry id_cache;
1821 SilcIDPayload idp = NULL;
1822 SilcClientID *client_id = NULL;
1823 SilcClientEntry client_entry;
1824 SilcServerID *server_id = NULL;
1825 SilcServerEntry server_entry;
1827 unsigned char *tmp, *pk;
1831 SilcPublicKey public_key = NULL;
1833 SILC_LOG_DEBUG(("Start"));
1835 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1836 SILC_GET16_MSB(status, tmp);
1837 if (status != SILC_STATUS_OK) {
1838 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1839 "%s", silc_client_command_status_message(status));
1840 COMMAND_REPLY_ERROR;
1844 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1846 COMMAND_REPLY_ERROR;
1849 idp = silc_id_payload_parse(tmp, len);
1851 COMMAND_REPLY_ERROR;
1855 /* Get the public key payload */
1856 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1858 /* Decode the public key */
1859 SILC_GET16_MSB(pk_len, tmp);
1860 SILC_GET16_MSB(type, tmp + 2);
1863 if (type != SILC_SKE_PK_TYPE_SILC) {
1864 COMMAND_REPLY_ERROR;
1868 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key)) {
1869 COMMAND_REPLY_ERROR;
1874 id_type = silc_id_payload_get_type(idp);
1875 if (id_type == SILC_ID_CLIENT) {
1876 /* Received client's public key */
1877 client_id = silc_id_payload_get_id(idp);
1878 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1881 silc_hash_client_id_compare, NULL,
1883 COMMAND_REPLY_ERROR;
1887 client_entry = (SilcClientEntry)id_cache->context;
1889 /* Notify application */
1890 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1891 } else if (id_type == SILC_ID_SERVER) {
1892 /* Received server's public key */
1893 server_id = silc_id_payload_get_id(idp);
1894 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1896 COMMAND_REPLY_ERROR;
1900 server_entry = (SilcServerEntry)id_cache->context;
1902 /* Notify application */
1903 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1907 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1908 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1910 silc_id_payload_free(idp);
1912 silc_pkcs_public_key_free(public_key);
1913 silc_free(client_id);
1914 silc_free(server_id);
1915 silc_client_command_reply_free(cmd);