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 was no such client" },
86 { STAT(NO_SUCH_CHANNEL_ID),"There was 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 /* Process received command reply. */
127 void silc_client_command_reply_process(SilcClient client,
128 SilcSocketConnection sock,
129 SilcPacketContext *packet)
131 SilcBuffer buffer = packet->buffer;
132 SilcClientCommandReply *cmd;
133 SilcClientCommandReplyContext ctx;
134 SilcCommandPayload payload;
138 /* Get command reply payload from packet */
139 payload = silc_command_payload_parse(buffer);
141 /* Silently ignore bad reply packet */
142 SILC_LOG_DEBUG(("Bad command reply packet"));
146 /* Allocate command reply context. This must be free'd by the
147 command reply routine receiving it. */
148 ctx = silc_calloc(1, sizeof(*ctx));
149 ctx->client = client;
151 ctx->payload = payload;
152 ctx->args = silc_command_get_args(ctx->payload);
153 ctx->packet = packet;
154 ident = silc_command_get_ident(ctx->payload);
156 /* Check for pending commands and mark to be exeucted */
157 silc_client_command_pending_check(sock->user_data, ctx,
158 silc_command_get(ctx->payload), ident);
160 /* Execute command reply */
161 command = silc_command_get(ctx->payload);
162 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
163 if (cmd->cmd == command)
166 if (cmd == NULL || !cmd->cb) {
174 /* Returns status message string */
176 char *silc_client_command_status_message(SilcCommandStatus status)
180 for (i = 0; silc_command_status_messages[i].message; i++) {
181 if (silc_command_status_messages[i].status == status)
185 if (silc_command_status_messages[i].message == NULL)
188 return silc_command_status_messages[i].message;
191 /* Free command reply context and its internals. */
193 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
196 silc_command_payload_free(cmd->payload);
202 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
203 SilcCommandStatus status)
205 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
206 SilcClientID *client_id;
207 SilcIDCacheEntry id_cache = NULL;
208 SilcClientEntry client_entry = NULL;
211 unsigned char *id_data, *tmp;
212 char *nickname = NULL, *username = NULL;
213 char *realname = NULL;
214 uint32 idle = 0, mode = 0;
215 SilcBuffer channels = NULL;
217 argc = silc_argument_get_arg_num(cmd->args);
219 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
225 client_id = silc_id_payload_parse_id(id_data, len);
231 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
232 username = silc_argument_get_arg_type(cmd->args, 4, &len);
233 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
234 if (!nickname || !username || !realname) {
239 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
241 channels = silc_buffer_alloc(len);
242 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
243 silc_buffer_put(channels, tmp, len);
246 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
248 SILC_GET32_MSB(mode, tmp);
250 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
252 SILC_GET32_MSB(idle, tmp);
254 /* Check if we have this client cached already. */
255 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
257 silc_hash_client_id_compare, NULL,
259 SILC_LOG_DEBUG(("Adding new client entry"));
261 client_entry = silc_calloc(1, sizeof(*client_entry));
262 client_entry->id = client_id;
263 silc_parse_nickname(nickname, &client_entry->nickname,
264 &client_entry->server, &client_entry->num);
265 client_entry->username = strdup(username);
267 client_entry->realname = strdup(realname);
268 client_entry->mode = mode;
270 /* Add client to cache */
271 silc_idcache_add(conn->client_cache, client_entry->nickname,
272 client_id, (void *)client_entry, FALSE);
274 client_entry = (SilcClientEntry)id_cache->context;
275 if (client_entry->nickname)
276 silc_free(client_entry->nickname);
277 if (client_entry->server)
278 silc_free(client_entry->server);
279 if (client_entry->username)
280 silc_free(client_entry->username);
281 if (client_entry->realname)
282 silc_free(client_entry->realname);
283 client_entry->mode = mode;
285 SILC_LOG_DEBUG(("Updating client entry"));
287 silc_parse_nickname(nickname, &client_entry->nickname,
288 &client_entry->server, &client_entry->num);
289 client_entry->username = strdup(username);
291 client_entry->realname = strdup(realname);
293 /* Remove the old cache entry and create a new one */
294 silc_idcache_del_by_context(conn->client_cache, client_entry);
295 silc_idcache_add(conn->client_cache, client_entry->nickname,
296 client_entry->id, client_entry, FALSE);
297 silc_free(client_id);
300 /* Notify application */
302 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
303 channels, mode, idle));
306 silc_buffer_free(channels);
309 /* Received reply for WHOIS command. This maybe called several times
310 for one WHOIS command as server may reply with list of results. */
312 SILC_CLIENT_CMD_REPLY_FUNC(whois)
314 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
315 SilcCommandStatus status;
318 SILC_LOG_DEBUG(("Start"));
320 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
321 SILC_GET16_MSB(status, tmp);
322 if (status != SILC_STATUS_OK &&
323 status != SILC_STATUS_LIST_START &&
324 status != SILC_STATUS_LIST_ITEM &&
325 status != SILC_STATUS_LIST_END) {
330 /* Display one whois reply */
331 if (status == SILC_STATUS_OK)
332 silc_client_command_reply_whois_save(cmd, status);
335 if (status == SILC_STATUS_LIST_START ||
336 status == SILC_STATUS_LIST_ITEM ||
337 status == SILC_STATUS_LIST_END)
338 silc_client_command_reply_whois_save(cmd, status);
340 /* Pending callbacks are not executed if this was an list entry */
341 if (status != SILC_STATUS_OK &&
342 status != SILC_STATUS_LIST_END) {
343 silc_client_command_reply_free(cmd);
347 /* Execute any pending command callbacks */
348 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
351 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
352 silc_client_command_reply_free(cmd);
355 /* Received reply for WHOWAS command. */
357 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
359 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
360 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
361 SilcCommandStatus status;
362 SilcClientID *client_id;
363 SilcIDCacheEntry id_cache = NULL;
364 SilcClientEntry client_entry = NULL;
366 unsigned char *id_data, *tmp;
367 char *nickname, *username;
368 char *realname = NULL;
370 SILC_LOG_DEBUG(("Start"));
372 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
373 SILC_GET16_MSB(status, tmp);
374 if (status != SILC_STATUS_OK &&
375 status != SILC_STATUS_LIST_START &&
376 status != SILC_STATUS_LIST_ITEM &&
377 status != SILC_STATUS_LIST_END) {
382 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
388 client_id = silc_id_payload_parse_id(id_data, len);
394 /* Get the client entry, if exists */
395 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
397 silc_hash_client_id_compare, NULL,
399 client_entry = (SilcClientEntry)id_cache->context;
400 silc_free(client_id);
402 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
403 username = silc_argument_get_arg_type(cmd->args, 4, &len);
404 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
405 if (!nickname || !username) {
409 /* Notify application. We don't save any history information to any
410 cache. Just pass the data to the application for displaying on
412 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
414 /* Pending callbacks are not executed if this was an list entry */
415 if (status != SILC_STATUS_OK &&
416 status != SILC_STATUS_LIST_END) {
417 silc_client_command_reply_free(cmd);
421 /* Execute any pending command callbacks */
422 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
425 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
426 silc_client_command_reply_free(cmd);
430 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
431 SilcCommandStatus status)
433 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
434 SilcClientID *client_id;
435 SilcIDCacheEntry id_cache = NULL;
436 SilcClientEntry client_entry = NULL;
439 unsigned char *id_data;
440 char *nickname = NULL, *username = NULL;
442 argc = silc_argument_get_arg_num(cmd->args);
444 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
450 client_id = silc_id_payload_parse_id(id_data, len);
456 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
457 username = silc_argument_get_arg_type(cmd->args, 4, &len);
459 /* Check if we have this client cached already. */
460 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
462 silc_hash_client_id_compare, NULL,
464 SILC_LOG_DEBUG(("Adding new client entry"));
466 client_entry = silc_calloc(1, sizeof(*client_entry));
467 client_entry->id = client_id;
468 silc_parse_nickname(nickname, &client_entry->nickname,
469 &client_entry->server, &client_entry->num);
471 client_entry->username = strdup(username);
473 /* Add client to cache */
474 silc_idcache_add(conn->client_cache, client_entry->nickname,
475 client_id, (void *)client_entry, FALSE);
477 client_entry = (SilcClientEntry)id_cache->context;
478 if (client_entry->nickname)
479 silc_free(client_entry->nickname);
480 if (client_entry->server)
481 silc_free(client_entry->server);
482 if (username && client_entry->username)
483 silc_free(client_entry->username);
485 SILC_LOG_DEBUG(("Updating client entry"));
487 silc_parse_nickname(nickname, &client_entry->nickname,
488 &client_entry->server, &client_entry->num);
491 client_entry->username = strdup(username);
493 /* Remove the old cache entry and create a new one */
494 silc_idcache_del_by_context(conn->client_cache, client_entry);
495 silc_idcache_add(conn->client_cache, client_entry->nickname,
496 client_entry->id, client_entry, FALSE);
497 silc_free(client_id);
500 /* Notify application */
501 COMMAND_REPLY((ARGS, client_entry, nickname, username));
504 /* Received reply for IDENTIFY command. This maybe called several times
505 for one IDENTIFY command as server may reply with list of results.
506 This is totally silent and does not print anything on screen. */
508 SILC_CLIENT_CMD_REPLY_FUNC(identify)
510 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
511 SilcCommandStatus status;
514 SILC_LOG_DEBUG(("Start"));
516 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
517 SILC_GET16_MSB(status, tmp);
518 if (status != SILC_STATUS_OK &&
519 status != SILC_STATUS_LIST_START &&
520 status != SILC_STATUS_LIST_ITEM &&
521 status != SILC_STATUS_LIST_END) {
526 /* Save one IDENTIFY entry */
527 if (status == SILC_STATUS_OK)
528 silc_client_command_reply_identify_save(cmd, status);
531 if (status == SILC_STATUS_LIST_START ||
532 status == SILC_STATUS_LIST_ITEM ||
533 status == SILC_STATUS_LIST_END)
534 silc_client_command_reply_identify_save(cmd, status);
536 /* Pending callbacks are not executed if this was an list entry */
537 if (status != SILC_STATUS_OK &&
538 status != SILC_STATUS_LIST_END) {
539 silc_client_command_reply_free(cmd);
543 /* Execute any pending command callbacks */
544 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
547 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
548 silc_client_command_reply_free(cmd);
551 /* Received reply for command NICK. If everything went without errors
552 we just received our new Client ID. */
554 SILC_CLIENT_CMD_REPLY_FUNC(nick)
556 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
557 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
558 SilcCommandStatus status;
563 SILC_LOG_DEBUG(("Start"));
565 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
566 if (status != SILC_STATUS_OK) {
567 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
568 "Cannot set nickname: %s",
569 silc_client_command_status_message(status));
574 argc = silc_argument_get_arg_num(cmd->args);
575 if (argc < 2 || argc > 2) {
576 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
577 "Cannot set nickname: bad reply to command");
582 /* Take received Client ID */
583 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
584 idp = silc_id_payload_parse_data(tmp, len);
589 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
591 /* Notify application */
592 COMMAND_REPLY((ARGS, conn->local_entry));
594 /* Execute any pending command callbacks */
595 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
598 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
599 silc_client_command_reply_free(cmd);
602 /* Received reply to the LIST command. */
604 SILC_CLIENT_CMD_REPLY_FUNC(list)
606 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
607 SilcCommandStatus status;
608 unsigned char *tmp, *name, *topic;
609 uint32 usercount = 0;
611 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
612 SILC_GET16_MSB(status, tmp);
613 if (status != SILC_STATUS_OK &&
614 status != SILC_STATUS_LIST_START &&
615 status != SILC_STATUS_LIST_ITEM &&
616 status != SILC_STATUS_LIST_END) {
621 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
622 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
623 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
625 SILC_GET32_MSB(usercount, tmp);
627 /* Notify application */
628 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
630 /* Pending callbacks are not executed if this was an list entry */
631 if (status != SILC_STATUS_OK &&
632 status != SILC_STATUS_LIST_END) {
633 silc_client_command_reply_free(cmd);
637 /* Execute any pending command callbacks */
638 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
641 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
642 silc_client_command_reply_free(cmd);
645 /* Received reply to topic command. */
647 SILC_CLIENT_CMD_REPLY_FUNC(topic)
649 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
650 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
651 SilcCommandStatus status;
652 SilcChannelEntry channel;
653 SilcChannelID *channel_id = NULL;
654 SilcIDCacheEntry id_cache = NULL;
659 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
660 if (status != SILC_STATUS_OK) {
661 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
662 "%s", silc_client_command_status_message(status));
664 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
665 silc_client_command_reply_free(cmd);
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));
702 /* Execute any pending command callbacks */
703 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
706 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
707 silc_client_command_reply_free(cmd);
710 /* Received reply to invite command. */
712 SILC_CLIENT_CMD_REPLY_FUNC(invite)
714 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
715 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
716 SilcCommandStatus status;
717 SilcChannelEntry channel;
718 SilcChannelID *channel_id;
719 SilcIDCacheEntry id_cache;
723 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
724 SILC_GET16_MSB(status, tmp);
725 if (status != SILC_STATUS_OK) {
726 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
727 "%s", silc_client_command_status_message(status));
729 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
730 silc_client_command_reply_free(cmd);
734 /* Take Channel ID */
735 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
739 channel_id = silc_id_payload_parse_id(tmp, len);
743 /* Get the channel entry */
744 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
746 silc_free(channel_id);
751 channel = (SilcChannelEntry)id_cache->context;
753 /* Get the invite list */
754 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
756 /* Notify application */
757 COMMAND_REPLY((ARGS, channel, tmp));
759 /* Execute any pending command callbacks */
760 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
763 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
764 silc_client_command_reply_free(cmd);
767 /* Received reply to the KILL command. */
769 SILC_CLIENT_CMD_REPLY_FUNC(kill)
771 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
772 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
773 SilcCommandStatus status;
776 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
777 SILC_GET16_MSB(status, tmp);
778 if (status != SILC_STATUS_OK) {
779 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
780 "%s", silc_client_command_status_message(status));
785 /* Notify application */
786 COMMAND_REPLY((ARGS));
788 /* Execute any pending command callbacks */
789 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
792 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
793 silc_client_command_reply_free(cmd);
796 /* Received reply to INFO command. We receive the server ID and some
797 information about the server user requested. */
799 SILC_CLIENT_CMD_REPLY_FUNC(info)
801 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
802 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
803 SilcCommandStatus status;
805 SilcIDCacheEntry id_cache;
806 SilcServerEntry server;
807 SilcServerID *server_id = NULL;
808 char *server_name, *server_info;
811 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
812 SILC_GET16_MSB(status, tmp);
813 if (status != SILC_STATUS_OK) {
814 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
815 "%s", silc_client_command_status_message(status));
817 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
818 silc_client_command_reply_free(cmd);
823 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
827 server_id = silc_id_payload_parse_id(tmp, len);
831 /* Get server name */
832 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
836 /* Get server info */
837 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
841 /* See whether we have this server cached. If not create it. */
842 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
844 SILC_LOG_DEBUG(("New server entry"));
846 server = silc_calloc(1, sizeof(*server));
847 server->server_name = strdup(server_name);
848 server->server_info = strdup(server_info);
849 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
851 /* Add it to the cache */
852 silc_idcache_add(conn->server_cache, server->server_name,
853 server->server_id, (void *)server, FALSE);
855 server = (SilcServerEntry)id_cache->context;
858 /* Notify application */
859 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
861 /* Execute any pending command callbacks */
862 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
866 silc_free(server_id);
867 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
868 silc_client_command_reply_free(cmd);
871 /* Received reply to PING command. The reply time is shown to user. */
873 SILC_CLIENT_CMD_REPLY_FUNC(ping)
875 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
876 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
877 SilcCommandStatus status;
880 time_t diff, curtime;
882 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
883 if (status != SILC_STATUS_OK) {
884 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
885 "%s", silc_client_command_status_message(status));
890 curtime = time(NULL);
891 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
892 cmd->packet->src_id_type);
898 for (i = 0; i < conn->ping_count; i++) {
899 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
900 diff = curtime - conn->ping[i].start_time;
901 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
902 "Ping reply from %s: %d second%s",
903 conn->ping[i].dest_name, diff,
904 diff == 1 ? "" : "s");
906 conn->ping[i].start_time = 0;
907 silc_free(conn->ping[i].dest_id);
908 conn->ping[i].dest_id = NULL;
909 silc_free(conn->ping[i].dest_name);
910 conn->ping[i].dest_name = NULL;
917 /* Notify application */
918 COMMAND_REPLY((ARGS));
920 /* Execute any pending command callbacks */
921 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
924 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
925 silc_client_command_reply_free(cmd);
928 /* Received reply for JOIN command. */
930 SILC_CLIENT_CMD_REPLY_FUNC(join)
932 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
933 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
934 SilcCommandStatus status;
935 SilcIDPayload idp = NULL;
936 SilcChannelEntry channel;
937 SilcIDCacheEntry id_cache = NULL;
939 uint32 argc, mode, len, list_count;
940 char *topic, *tmp, *channel_name = NULL, *hmac;
941 SilcBuffer keyp = NULL, client_id_list, client_mode_list;
944 SILC_LOG_DEBUG(("Start"));
946 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
947 if (status != SILC_STATUS_OK) {
948 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
949 "%s", silc_client_command_status_message(status));
954 argc = silc_argument_get_arg_num(cmd->args);
955 if (argc < 7 || argc > 14) {
956 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
957 "Cannot join channel: Bad reply packet");
962 /* Get channel name */
963 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
965 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
966 "Cannot join channel: Bad reply packet");
970 channel_name = strdup(tmp);
973 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
975 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
976 "Cannot join channel: Bad reply packet");
978 silc_free(channel_name);
981 idp = silc_id_payload_parse_data(tmp, len);
984 silc_free(channel_name);
988 /* Get channel mode */
989 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
991 SILC_GET32_MSB(mode, tmp);
995 /* Get channel key */
996 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
998 keyp = silc_buffer_alloc(len);
999 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1000 silc_buffer_put(keyp, tmp, len);
1004 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1006 /* Save received Channel ID. This actually creates the channel */
1007 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
1009 silc_id_payload_free(idp);
1012 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1014 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1015 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1016 "Cannot join channel: Unsupported HMAC `%s'",
1018 COMMAND_REPLY_ERROR;
1019 silc_free(channel_name);
1024 /* Get the list count */
1025 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1028 SILC_GET32_MSB(list_count, tmp);
1030 /* Get Client ID list */
1031 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1035 client_id_list = silc_buffer_alloc(len);
1036 silc_buffer_pull_tail(client_id_list, len);
1037 silc_buffer_put(client_id_list, tmp, len);
1039 /* Get client mode list */
1040 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1044 client_mode_list = silc_buffer_alloc(len);
1045 silc_buffer_pull_tail(client_mode_list, len);
1046 silc_buffer_put(client_mode_list, tmp, len);
1048 /* Add clients we received in the reply to the channel */
1049 for (i = 0; i < list_count; i++) {
1052 SilcClientID *client_id;
1053 SilcClientEntry client_entry;
1056 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1058 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1063 SILC_GET32_MSB(mode, client_mode_list->data);
1065 /* Check if we have this client cached already. */
1066 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1069 silc_hash_client_id_compare, NULL,
1071 /* No, we don't have it, add entry for it. */
1072 client_entry = silc_calloc(1, sizeof(*client_entry));
1073 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1074 silc_idcache_add(conn->client_cache, NULL, client_entry->id,
1075 (void *)client_entry, FALSE);
1077 /* Yes, we have it already */
1078 client_entry = (SilcClientEntry)id_cache->context;
1081 /* Join the client to the channel */
1082 chu = silc_calloc(1, sizeof(*chu));
1083 chu->client = client_entry;
1085 silc_list_add(channel->clients, chu);
1086 silc_free(client_id);
1088 silc_buffer_pull(client_id_list, idp_len);
1089 silc_buffer_pull(client_mode_list, 4);
1091 silc_buffer_push(client_id_list, client_id_list->data -
1092 client_id_list->head);
1093 silc_buffer_push(client_mode_list, client_mode_list->data -
1094 client_mode_list->head);
1096 /* Save channel key */
1097 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1098 silc_client_save_channel_key(conn, keyp, channel);
1100 /* Client is now joined to the channel */
1101 channel->on_channel = TRUE;
1103 /* Notify application */
1104 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1105 keyp ? keyp->head : NULL, NULL,
1106 NULL, topic, hmac, list_count, client_id_list,
1109 /* Execute any pending command callbacks */
1110 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1113 silc_buffer_free(keyp);
1114 silc_buffer_free(client_id_list);
1115 silc_buffer_free(client_mode_list);
1118 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1119 silc_client_command_reply_free(cmd);
1122 /* Received reply for MOTD command */
1124 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1126 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1127 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1128 SilcCommandStatus status;
1131 char *motd = NULL, *cp, line[256];
1133 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1134 SILC_GET16_MSB(status, tmp);
1135 if (status != SILC_STATUS_OK) {
1136 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1137 "%s", silc_client_command_status_message(status));
1138 COMMAND_REPLY_ERROR;
1142 argc = silc_argument_get_arg_num(cmd->args);
1144 COMMAND_REPLY_ERROR;
1149 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1151 COMMAND_REPLY_ERROR;
1158 if (cp[i++] == '\n') {
1159 memset(line, 0, sizeof(line));
1160 strncat(line, cp, i - 1);
1166 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1176 /* Notify application */
1177 COMMAND_REPLY((ARGS, motd));
1179 /* Execute any pending command callbacks */
1180 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1183 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1184 silc_client_command_reply_free(cmd);
1187 /* Received reply tot he UMODE command. Save the current user mode */
1189 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1191 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1192 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1193 SilcCommandStatus status;
1197 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1198 SILC_GET16_MSB(status, tmp);
1199 if (status != SILC_STATUS_OK) {
1200 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1201 "%s", silc_client_command_status_message(status));
1202 COMMAND_REPLY_ERROR;
1206 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1208 COMMAND_REPLY_ERROR;
1212 SILC_GET32_MSB(mode, tmp);
1213 conn->local_entry->mode = mode;
1215 /* Notify application */
1216 COMMAND_REPLY((ARGS, mode));
1218 /* Execute any pending command callbacks */
1219 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1222 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1223 silc_client_command_reply_free(cmd);
1226 /* Received reply for CMODE command. */
1228 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1230 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1231 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1232 SilcCommandStatus status;
1235 SilcIDCacheEntry id_cache;
1236 SilcChannelID *channel_id;
1237 SilcChannelEntry channel;
1240 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1241 if (status != SILC_STATUS_OK) {
1242 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1243 "%s", silc_client_command_status_message(status));
1244 COMMAND_REPLY_ERROR;
1248 /* Take Channel ID */
1249 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1252 channel_id = silc_id_payload_parse_id(tmp, len);
1256 /* Get the channel entry */
1257 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1259 silc_free(channel_id);
1260 COMMAND_REPLY_ERROR;
1264 channel = (SilcChannelEntry)id_cache->context;
1266 /* Get channel mode */
1267 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1269 silc_free(channel_id);
1270 COMMAND_REPLY_ERROR;
1275 SILC_GET32_MSB(mode, tmp);
1276 channel->mode = mode;
1278 /* Notify application */
1279 COMMAND_REPLY((ARGS, channel, mode));
1280 silc_free(channel_id);
1282 /* Execute any pending command callbacks */
1283 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1286 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1287 silc_client_command_reply_free(cmd);
1290 /* Received reply for CUMODE command */
1292 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1294 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1295 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1296 SilcCommandStatus status;
1297 SilcIDCacheEntry id_cache = NULL;
1298 SilcClientID *client_id;
1299 SilcChannelID *channel_id;
1300 SilcClientEntry client_entry;
1301 SilcChannelEntry channel;
1302 SilcChannelUser chu;
1303 unsigned char *tmp, *id;
1306 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1307 if (status != SILC_STATUS_OK) {
1308 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1309 "%s", silc_client_command_status_message(status));
1310 COMMAND_REPLY_ERROR;
1314 /* Get channel mode */
1315 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1317 COMMAND_REPLY_ERROR;
1321 /* Take Channel ID */
1322 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1325 channel_id = silc_id_payload_parse_id(tmp, len);
1329 /* Get the channel entry */
1330 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1332 silc_free(channel_id);
1333 COMMAND_REPLY_ERROR;
1337 channel = (SilcChannelEntry)id_cache->context;
1340 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1342 silc_free(channel_id);
1343 COMMAND_REPLY_ERROR;
1346 client_id = silc_id_payload_parse_id(id, len);
1348 silc_free(channel_id);
1349 COMMAND_REPLY_ERROR;
1353 /* Get client entry */
1354 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1356 silc_hash_client_id_compare, NULL,
1358 silc_free(channel_id);
1359 silc_free(client_id);
1360 COMMAND_REPLY_ERROR;
1364 client_entry = (SilcClientEntry)id_cache->context;
1367 SILC_GET32_MSB(mode, tmp);
1368 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1369 if (chu->client == client_entry) {
1375 /* Notify application */
1376 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1377 silc_free(client_id);
1378 silc_free(channel_id);
1380 /* Execute any pending command callbacks */
1381 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1384 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1385 silc_client_command_reply_free(cmd);
1388 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1390 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1391 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1392 SilcCommandStatus status;
1395 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1396 SILC_GET16_MSB(status, tmp);
1397 if (status != SILC_STATUS_OK) {
1398 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1399 "%s", silc_client_command_status_message(status));
1400 COMMAND_REPLY_ERROR;
1404 /* Notify application */
1405 COMMAND_REPLY((ARGS));
1407 /* Execute any pending command callbacks */
1408 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1411 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1412 silc_client_command_reply_free(cmd);
1415 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1417 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1418 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1419 SilcCommandStatus status;
1422 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1423 SILC_GET16_MSB(status, tmp);
1424 if (status != SILC_STATUS_OK) {
1425 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1426 "%s", silc_client_command_status_message(status));
1427 COMMAND_REPLY_ERROR;
1431 /* Notify application */
1432 COMMAND_REPLY((ARGS));
1434 /* Execute any pending command callbacks */
1435 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1438 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1439 silc_client_command_reply_free(cmd);
1442 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1444 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1445 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1446 SilcCommandStatus status;
1449 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1450 SILC_GET16_MSB(status, tmp);
1451 if (status != SILC_STATUS_OK) {
1452 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1453 "%s", silc_client_command_status_message(status));
1454 COMMAND_REPLY_ERROR;
1458 /* Notify application */
1459 COMMAND_REPLY((ARGS));
1461 /* Execute any pending command callbacks */
1462 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1465 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1466 silc_client_command_reply_free(cmd);
1469 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1471 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1472 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1473 SilcCommandStatus status;
1476 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1477 SILC_GET16_MSB(status, tmp);
1478 if (status != SILC_STATUS_OK) {
1479 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1480 "%s", silc_client_command_status_message(status));
1481 COMMAND_REPLY_ERROR;
1485 /* Notify application */
1486 COMMAND_REPLY((ARGS));
1488 /* Execute any pending command callbacks */
1489 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1492 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1493 silc_client_command_reply_free(cmd);
1496 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1498 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1499 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1500 SilcCommandStatus status;
1501 SilcIDCacheEntry id_cache = NULL;
1502 SilcChannelEntry channel;
1503 SilcChannelID *channel_id;
1507 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1508 SILC_GET16_MSB(status, tmp);
1509 if (status != SILC_STATUS_OK) {
1510 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1511 "%s", silc_client_command_status_message(status));
1512 COMMAND_REPLY_ERROR;
1516 /* Take Channel ID */
1517 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1521 channel_id = silc_id_payload_parse_id(tmp, len);
1525 /* Get the channel entry */
1526 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1528 silc_free(channel_id);
1529 COMMAND_REPLY_ERROR;
1533 channel = (SilcChannelEntry)id_cache->context;
1535 /* Get the ban list */
1536 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1538 /* Notify application */
1539 COMMAND_REPLY((ARGS, channel, tmp));
1541 /* Execute any pending command callbacks */
1542 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1545 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1546 silc_client_command_reply_free(cmd);
1549 SILC_CLIENT_CMD_REPLY_FUNC(close)
1551 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1552 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1553 SilcCommandStatus status;
1556 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1557 SILC_GET16_MSB(status, tmp);
1558 if (status != SILC_STATUS_OK) {
1559 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1560 "%s", silc_client_command_status_message(status));
1561 COMMAND_REPLY_ERROR;
1565 /* Notify application */
1566 COMMAND_REPLY((ARGS));
1568 /* Execute any pending command callbacks */
1569 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1572 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1573 silc_client_command_reply_free(cmd);
1576 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1578 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1579 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1580 SilcCommandStatus status;
1583 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1584 SILC_GET16_MSB(status, tmp);
1585 if (status != SILC_STATUS_OK) {
1586 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1587 "%s", silc_client_command_status_message(status));
1588 COMMAND_REPLY_ERROR;
1592 /* Notify application */
1593 COMMAND_REPLY((ARGS));
1595 /* Execute any pending command callbacks */
1596 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1599 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1600 silc_client_command_reply_free(cmd);
1603 /* Reply to LEAVE command. */
1605 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1607 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1608 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1609 SilcCommandStatus status;
1612 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1613 SILC_GET16_MSB(status, tmp);
1614 if (status != SILC_STATUS_OK) {
1615 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1616 "%s", silc_client_command_status_message(status));
1617 COMMAND_REPLY_ERROR;
1621 /* Notify application */
1622 COMMAND_REPLY((ARGS));
1624 /* Execute any pending command callbacks */
1625 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1628 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1629 silc_client_command_reply_free(cmd);
1632 /* Reply to USERS command. Received list of client ID's and theirs modes
1633 on the channel we requested. */
1635 SILC_CLIENT_CMD_REPLY_FUNC(users)
1637 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1638 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1639 SilcCommandStatus status;
1640 SilcIDCacheEntry id_cache = NULL;
1641 SilcChannelEntry channel;
1642 SilcChannelUser chu;
1643 SilcChannelID *channel_id = NULL;
1644 SilcBuffer client_id_list;
1645 SilcBuffer client_mode_list;
1647 uint32 tmp_len, list_count;
1649 unsigned char **res_argv = NULL;
1650 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1652 SILC_LOG_DEBUG(("Start"));
1654 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1655 SILC_GET16_MSB(status, tmp);
1656 if (status != SILC_STATUS_OK) {
1657 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1658 "%s", silc_client_command_status_message(status));
1659 COMMAND_REPLY_ERROR;
1663 /* Get channel ID */
1664 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1667 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1671 /* Get the list count */
1672 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1675 SILC_GET32_MSB(list_count, tmp);
1677 /* Get Client ID list */
1678 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1682 client_id_list = silc_buffer_alloc(tmp_len);
1683 silc_buffer_pull_tail(client_id_list, tmp_len);
1684 silc_buffer_put(client_id_list, tmp, tmp_len);
1686 /* Get client mode list */
1687 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1691 client_mode_list = silc_buffer_alloc(tmp_len);
1692 silc_buffer_pull_tail(client_mode_list, tmp_len);
1693 silc_buffer_put(client_mode_list, tmp, tmp_len);
1695 /* Get channel entry */
1696 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1698 COMMAND_REPLY_ERROR;
1701 channel = (SilcChannelEntry)id_cache->context;
1703 /* Remove old client list from channel. */
1704 silc_list_start(channel->clients);
1705 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1706 silc_list_del(channel->clients, chu);
1710 /* Cache the received Client ID's and modes. This cache expires
1711 whenever server sends notify message to channel. It means two things;
1712 some user has joined or leaved the channel. XXX! */
1713 for (i = 0; i < list_count; i++) {
1716 SilcClientID *client_id;
1717 SilcClientEntry client;
1720 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1722 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1727 SILC_GET32_MSB(mode, client_mode_list->data);
1729 /* Check if we have this client cached already. */
1731 silc_idcache_find_by_id_one_ext(conn->client_cache,
1734 silc_hash_client_id_compare, NULL,
1737 if (!id_cache || !((SilcClientEntry)id_cache->context)->username) {
1738 /* No we don't have it (or it is incomplete in information), query
1739 it from the server. Assemble argument table that will be sent
1740 for the WHOIS command later. */
1741 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1743 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1745 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1747 res_argv[res_argc] = client_id_list->data;
1748 res_argv_lens[res_argc] = idp_len;
1749 res_argv_types[res_argc] = res_argc + 3;
1752 /* Found the client, join it to the channel */
1753 client = (SilcClientEntry)id_cache->context;
1754 chu = silc_calloc(1, sizeof(*chu));
1755 chu->client = client;
1757 silc_list_add(channel->clients, chu);
1759 silc_free(client_id);
1763 silc_buffer_pull(client_id_list, idp_len);
1764 silc_buffer_pull(client_mode_list, 4);
1767 /* Query the client information from server if the list included clients
1768 that we don't know about. */
1772 /* Send the WHOIS command to server */
1773 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1774 res_argc, res_argv, res_argv_lens,
1775 res_argv_types, ++conn->cmd_ident);
1776 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1777 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1780 /* Register pending command callback. After we've received the WHOIS
1781 command reply we will reprocess this command reply by re-calling this
1782 USERS command reply callback. */
1783 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1784 NULL, silc_client_command_reply_users, cmd);
1786 silc_buffer_free(res_cmd);
1788 silc_free(channel_id);
1790 silc_free(res_argv);
1791 silc_free(res_argv_lens);
1792 silc_free(res_argv_types);
1796 /* Notify application */
1797 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1799 /* Execute any pending command callbacks */
1800 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1802 silc_buffer_free(client_id_list);
1803 silc_buffer_free(client_mode_list);
1807 silc_free(channel_id);
1808 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1809 silc_client_command_reply_free(cmd);
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;
1825 unsigned char *tmp, *pk;
1829 SilcPublicKey public_key = NULL;
1831 SILC_LOG_DEBUG(("Start"));
1833 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1834 SILC_GET16_MSB(status, tmp);
1835 if (status != SILC_STATUS_OK) {
1836 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1837 "%s", silc_client_command_status_message(status));
1838 COMMAND_REPLY_ERROR;
1842 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1845 idp = silc_id_payload_parse_data(tmp, len);
1849 /* Get the public key payload */
1850 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1854 /* Decode the public key */
1856 SILC_GET16_MSB(pk_len, tmp);
1857 SILC_GET16_MSB(type, tmp + 2);
1860 if (type != SILC_SKE_PK_TYPE_SILC)
1863 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1866 id_type = silc_id_payload_get_type(idp);
1867 if (id_type == SILC_ID_CLIENT) {
1868 client_id = silc_id_payload_get_id(idp);
1870 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1873 silc_hash_client_id_compare, NULL,
1877 client_entry = (SilcClientEntry)id_cache->context;
1879 /* Notify application */
1880 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1881 } else if (id_type == SILC_ID_SERVER) {
1882 /* XXX we don't have server entries at all */
1889 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1891 silc_id_payload_free(idp);
1893 silc_pkcs_public_key_free(public_key);
1894 silc_free(client_id);
1895 silc_client_command_reply_free(cmd);