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 /* 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 SilcClient client = cmd->client;
435 SilcClientID *client_id = NULL;
436 SilcServerID *server_id = NULL;
437 SilcChannelID *channel_id = NULL;
438 SilcIDCacheEntry id_cache = NULL;
439 SilcClientEntry client_entry;
440 SilcServerEntry server_entry;
441 SilcChannelEntry channel_entry;
444 unsigned char *id_data;
445 char *name = NULL, *info = NULL;
446 SilcIDPayload idp = NULL;
449 argc = silc_argument_get_arg_num(cmd->args);
451 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
456 idp = silc_id_payload_parse_data(id_data, len);
462 name = silc_argument_get_arg_type(cmd->args, 3, &len);
463 info = silc_argument_get_arg_type(cmd->args, 4, &len);
465 id_type = silc_id_payload_get_type(idp);
469 client_id = silc_id_payload_get_id(idp);
471 SILC_LOG_DEBUG(("Received client information"));
473 /* Check if we have this client cached already. */
474 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
477 silc_hash_client_id_compare, NULL,
479 SILC_LOG_DEBUG(("Adding new client entry"));
481 client_entry = silc_calloc(1, sizeof(*client_entry));
482 client_entry->id = silc_id_dup(client_id, id_type);
483 silc_parse_nickname(name, &client_entry->nickname,
484 &client_entry->server, &client_entry->num);
486 client_entry->username = strdup(info);
488 /* Add client to cache */
489 silc_idcache_add(conn->client_cache, client_entry->nickname,
490 client_entry->id, (void *)client_entry, FALSE);
492 client_entry = (SilcClientEntry)id_cache->context;
493 if (client_entry->nickname)
494 silc_free(client_entry->nickname);
495 if (client_entry->server)
496 silc_free(client_entry->server);
497 if (info && client_entry->username)
498 silc_free(client_entry->username);
500 SILC_LOG_DEBUG(("Updating client entry"));
502 silc_parse_nickname(name, &client_entry->nickname,
503 &client_entry->server, &client_entry->num);
506 client_entry->username = strdup(info);
508 /* Remove the old cache entry and create a new one */
509 silc_idcache_del_by_context(conn->client_cache, client_entry);
510 silc_idcache_add(conn->client_cache, client_entry->nickname,
511 client_entry->id, client_entry, FALSE);
514 /* Notify application */
515 COMMAND_REPLY((ARGS, client_entry, name, info));
519 server_id = silc_id_payload_get_id(idp);
521 SILC_LOG_DEBUG(("Received server information"));
523 /* Check if we have this server cached already. */
524 if (!silc_idcache_find_by_id_one(conn->server_cache,
525 (void *)server_id, &id_cache)) {
526 SILC_LOG_DEBUG(("Adding new server entry"));
528 server_entry = silc_calloc(1, sizeof(*server_entry));
529 server_entry->server_id = silc_id_dup(server_id, id_type);
531 server_entry->server_name = strdup(name);
533 server_entry->server_info = strdup(info);
535 /* Add server to cache */
536 silc_idcache_add(conn->server_cache, server_entry->server_name,
537 server_entry->server_id, (void *)server_entry, FALSE);
539 server_entry = (SilcServerEntry)id_cache->context;
542 /* Notify application */
543 COMMAND_REPLY((ARGS, server_entry, name, info));
546 case SILC_ID_CHANNEL:
547 channel_id = silc_id_payload_get_id(idp);
549 SILC_LOG_DEBUG(("Received channel information"));
551 /* Check if we have this channel cached already. */
552 if (!silc_idcache_find_by_id_one(conn->channel_cache,
553 (void *)channel_id, &id_cache)) {
557 SILC_LOG_DEBUG(("Adding new channel entry"));
558 channel_entry = silc_client_new_channel_id(client, conn->sock,
559 strdup(name), 0, idp);
561 channel_entry = (SilcChannelEntry)id_cache->context;
564 /* Notify application */
565 COMMAND_REPLY((ARGS, channel_entry, name, info));
569 silc_id_payload_free(idp);
570 silc_free(client_id);
571 silc_free(server_id);
572 silc_free(channel_id);
575 /* Received reply for IDENTIFY command. This maybe called several times
576 for one IDENTIFY command as server may reply with list of results.
577 This is totally silent and does not print anything on screen. */
579 SILC_CLIENT_CMD_REPLY_FUNC(identify)
581 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
582 SilcCommandStatus status;
585 SILC_LOG_DEBUG(("Start"));
587 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
588 SILC_GET16_MSB(status, tmp);
589 if (status != SILC_STATUS_OK &&
590 status != SILC_STATUS_LIST_START &&
591 status != SILC_STATUS_LIST_ITEM &&
592 status != SILC_STATUS_LIST_END) {
597 /* Save one IDENTIFY entry */
598 if (status == SILC_STATUS_OK)
599 silc_client_command_reply_identify_save(cmd, status);
602 if (status == SILC_STATUS_LIST_START ||
603 status == SILC_STATUS_LIST_ITEM ||
604 status == SILC_STATUS_LIST_END)
605 silc_client_command_reply_identify_save(cmd, status);
607 /* Pending callbacks are not executed if this was an list entry */
608 if (status != SILC_STATUS_OK &&
609 status != SILC_STATUS_LIST_END) {
610 silc_client_command_reply_free(cmd);
614 /* Execute any pending command callbacks */
615 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
618 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
619 silc_client_command_reply_free(cmd);
622 /* Received reply for command NICK. If everything went without errors
623 we just received our new Client ID. */
625 SILC_CLIENT_CMD_REPLY_FUNC(nick)
627 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
628 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
629 SilcCommandStatus status;
634 SILC_LOG_DEBUG(("Start"));
636 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
637 if (status != SILC_STATUS_OK) {
638 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
639 "Cannot set nickname: %s",
640 silc_client_command_status_message(status));
645 argc = silc_argument_get_arg_num(cmd->args);
646 if (argc < 2 || argc > 2) {
647 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
648 "Cannot set nickname: bad reply to command");
653 /* Take received Client ID */
654 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
655 idp = silc_id_payload_parse_data(tmp, len);
660 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
662 /* Notify application */
663 COMMAND_REPLY((ARGS, conn->local_entry));
665 /* Execute any pending command callbacks */
666 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
669 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
670 silc_client_command_reply_free(cmd);
673 /* Received reply to the LIST command. */
675 SILC_CLIENT_CMD_REPLY_FUNC(list)
677 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
678 SilcCommandStatus status;
679 unsigned char *tmp, *name, *topic;
680 uint32 usercount = 0;
682 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
683 SILC_GET16_MSB(status, tmp);
684 if (status != SILC_STATUS_OK &&
685 status != SILC_STATUS_LIST_START &&
686 status != SILC_STATUS_LIST_ITEM &&
687 status != SILC_STATUS_LIST_END) {
692 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
693 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
694 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
696 SILC_GET32_MSB(usercount, tmp);
698 /* Notify application */
699 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
701 /* Pending callbacks are not executed if this was an list entry */
702 if (status != SILC_STATUS_OK &&
703 status != SILC_STATUS_LIST_END) {
704 silc_client_command_reply_free(cmd);
708 /* Execute any pending command callbacks */
709 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
712 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
713 silc_client_command_reply_free(cmd);
716 /* Received reply to topic command. */
718 SILC_CLIENT_CMD_REPLY_FUNC(topic)
720 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
721 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
722 SilcCommandStatus status;
723 SilcChannelEntry channel;
724 SilcChannelID *channel_id = NULL;
725 SilcIDCacheEntry id_cache = NULL;
730 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
731 if (status != SILC_STATUS_OK) {
732 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
733 "%s", silc_client_command_status_message(status));
735 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
736 silc_client_command_reply_free(cmd);
740 argc = silc_argument_get_arg_num(cmd->args);
741 if (argc < 1 || argc > 3) {
746 /* Take Channel ID */
747 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
752 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
756 channel_id = silc_id_payload_parse_id(tmp, len);
760 /* Get the channel entry */
761 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
763 silc_free(channel_id);
768 channel = (SilcChannelEntry)id_cache->context;
770 /* Notify application */
771 COMMAND_REPLY((ARGS, channel, topic));
773 /* Execute any pending command callbacks */
774 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
777 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
778 silc_client_command_reply_free(cmd);
781 /* Received reply to invite command. */
783 SILC_CLIENT_CMD_REPLY_FUNC(invite)
785 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
786 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
787 SilcCommandStatus status;
788 SilcChannelEntry channel;
789 SilcChannelID *channel_id;
790 SilcIDCacheEntry id_cache;
794 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
795 SILC_GET16_MSB(status, tmp);
796 if (status != SILC_STATUS_OK) {
797 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
798 "%s", silc_client_command_status_message(status));
800 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
801 silc_client_command_reply_free(cmd);
805 /* Take Channel ID */
806 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
810 channel_id = silc_id_payload_parse_id(tmp, len);
814 /* Get the channel entry */
815 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
817 silc_free(channel_id);
822 channel = (SilcChannelEntry)id_cache->context;
824 /* Get the invite list */
825 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
827 /* Notify application */
828 COMMAND_REPLY((ARGS, channel, tmp));
830 /* Execute any pending command callbacks */
831 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
834 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
835 silc_client_command_reply_free(cmd);
838 /* Received reply to the KILL command. */
840 SILC_CLIENT_CMD_REPLY_FUNC(kill)
842 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
843 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
844 SilcCommandStatus status;
847 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
848 SILC_GET16_MSB(status, tmp);
849 if (status != SILC_STATUS_OK) {
850 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
851 "%s", silc_client_command_status_message(status));
856 /* Notify application */
857 COMMAND_REPLY((ARGS));
859 /* Execute any pending command callbacks */
860 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
863 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
864 silc_client_command_reply_free(cmd);
867 /* Received reply to INFO command. We receive the server ID and some
868 information about the server user requested. */
870 SILC_CLIENT_CMD_REPLY_FUNC(info)
872 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
873 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
874 SilcCommandStatus status;
876 SilcIDCacheEntry id_cache;
877 SilcServerEntry server;
878 SilcServerID *server_id = NULL;
879 char *server_name, *server_info;
882 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
883 SILC_GET16_MSB(status, tmp);
884 if (status != SILC_STATUS_OK) {
885 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
886 "%s", silc_client_command_status_message(status));
888 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
889 silc_client_command_reply_free(cmd);
894 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
898 server_id = silc_id_payload_parse_id(tmp, len);
902 /* Get server name */
903 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
907 /* Get server info */
908 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
912 /* See whether we have this server cached. If not create it. */
913 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
915 SILC_LOG_DEBUG(("New server entry"));
917 server = silc_calloc(1, sizeof(*server));
918 server->server_name = strdup(server_name);
919 server->server_info = strdup(server_info);
920 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
922 /* Add it to the cache */
923 silc_idcache_add(conn->server_cache, server->server_name,
924 server->server_id, (void *)server, FALSE);
926 server = (SilcServerEntry)id_cache->context;
929 /* Notify application */
930 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
932 /* Execute any pending command callbacks */
933 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
937 silc_free(server_id);
938 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
939 silc_client_command_reply_free(cmd);
942 /* Received reply to PING command. The reply time is shown to user. */
944 SILC_CLIENT_CMD_REPLY_FUNC(ping)
946 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
947 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
948 SilcCommandStatus status;
951 time_t diff, curtime;
953 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
954 if (status != SILC_STATUS_OK) {
955 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
956 "%s", silc_client_command_status_message(status));
961 curtime = time(NULL);
962 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
963 cmd->packet->src_id_type);
969 for (i = 0; i < conn->ping_count; i++) {
970 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
971 diff = curtime - conn->ping[i].start_time;
972 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
973 "Ping reply from %s: %d second%s",
974 conn->ping[i].dest_name, diff,
975 diff == 1 ? "" : "s");
977 conn->ping[i].start_time = 0;
978 silc_free(conn->ping[i].dest_id);
979 conn->ping[i].dest_id = NULL;
980 silc_free(conn->ping[i].dest_name);
981 conn->ping[i].dest_name = NULL;
988 /* Notify application */
989 COMMAND_REPLY((ARGS));
991 /* Execute any pending command callbacks */
992 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
995 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
996 silc_client_command_reply_free(cmd);
999 /* Received reply for JOIN command. */
1001 SILC_CLIENT_CMD_REPLY_FUNC(join)
1003 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1004 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1005 SilcCommandStatus status;
1006 SilcIDPayload idp = NULL;
1007 SilcChannelEntry channel;
1008 SilcIDCacheEntry id_cache = NULL;
1009 SilcChannelUser chu;
1010 uint32 argc, mode, len, list_count;
1011 char *topic, *tmp, *channel_name = NULL, *hmac;
1012 SilcBuffer keyp = NULL, client_id_list, client_mode_list;
1015 SILC_LOG_DEBUG(("Start"));
1017 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1018 if (status != SILC_STATUS_OK) {
1019 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1020 "%s", silc_client_command_status_message(status));
1021 COMMAND_REPLY_ERROR;
1025 argc = silc_argument_get_arg_num(cmd->args);
1026 if (argc < 7 || argc > 14) {
1027 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1028 "Cannot join channel: Bad reply packet");
1029 COMMAND_REPLY_ERROR;
1033 /* Get channel name */
1034 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1036 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1037 "Cannot join channel: Bad reply packet");
1038 COMMAND_REPLY_ERROR;
1041 channel_name = strdup(tmp);
1043 /* Get Channel ID */
1044 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1046 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1047 "Cannot join channel: Bad reply packet");
1048 COMMAND_REPLY_ERROR;
1049 silc_free(channel_name);
1052 idp = silc_id_payload_parse_data(tmp, len);
1054 COMMAND_REPLY_ERROR;
1055 silc_free(channel_name);
1059 /* Get channel mode */
1060 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1062 SILC_GET32_MSB(mode, tmp);
1066 /* Get channel key */
1067 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1069 keyp = silc_buffer_alloc(len);
1070 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1071 silc_buffer_put(keyp, tmp, len);
1075 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1077 /* Save received Channel ID. This actually creates the channel */
1078 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
1080 silc_id_payload_free(idp);
1082 conn->current_channel = channel;
1085 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1087 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1088 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1089 "Cannot join channel: Unsupported HMAC `%s'",
1091 COMMAND_REPLY_ERROR;
1092 silc_free(channel_name);
1097 /* Get the list count */
1098 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1101 SILC_GET32_MSB(list_count, tmp);
1103 /* Get Client ID list */
1104 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1108 client_id_list = silc_buffer_alloc(len);
1109 silc_buffer_pull_tail(client_id_list, len);
1110 silc_buffer_put(client_id_list, tmp, len);
1112 /* Get client mode list */
1113 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1117 client_mode_list = silc_buffer_alloc(len);
1118 silc_buffer_pull_tail(client_mode_list, len);
1119 silc_buffer_put(client_mode_list, tmp, len);
1121 /* Add clients we received in the reply to the channel */
1122 for (i = 0; i < list_count; i++) {
1125 SilcClientID *client_id;
1126 SilcClientEntry client_entry;
1129 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1131 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1136 SILC_GET32_MSB(mode, client_mode_list->data);
1138 /* Check if we have this client cached already. */
1139 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1142 silc_hash_client_id_compare, NULL,
1144 /* No, we don't have it, add entry for it. */
1145 client_entry = silc_calloc(1, sizeof(*client_entry));
1146 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1147 silc_idcache_add(conn->client_cache, NULL, client_entry->id,
1148 (void *)client_entry, FALSE);
1150 /* Yes, we have it already */
1151 client_entry = (SilcClientEntry)id_cache->context;
1154 /* Join the client to the channel */
1155 chu = silc_calloc(1, sizeof(*chu));
1156 chu->client = client_entry;
1158 silc_list_add(channel->clients, chu);
1159 silc_free(client_id);
1161 silc_buffer_pull(client_id_list, idp_len);
1162 silc_buffer_pull(client_mode_list, 4);
1164 silc_buffer_push(client_id_list, client_id_list->data -
1165 client_id_list->head);
1166 silc_buffer_push(client_mode_list, client_mode_list->data -
1167 client_mode_list->head);
1169 /* Save channel key */
1170 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1171 silc_client_save_channel_key(conn, keyp, channel);
1173 /* Client is now joined to the channel */
1174 channel->on_channel = TRUE;
1176 /* Notify application */
1177 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1178 keyp ? keyp->head : NULL, NULL,
1179 NULL, topic, hmac, list_count, client_id_list,
1182 /* Execute any pending command callbacks */
1183 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1186 silc_buffer_free(keyp);
1187 silc_buffer_free(client_id_list);
1188 silc_buffer_free(client_mode_list);
1191 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1192 silc_client_command_reply_free(cmd);
1195 /* Received reply for MOTD command */
1197 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1199 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1200 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1201 SilcCommandStatus status;
1204 char *motd = NULL, *cp, line[256];
1206 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1207 SILC_GET16_MSB(status, tmp);
1208 if (status != SILC_STATUS_OK) {
1209 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1210 "%s", silc_client_command_status_message(status));
1211 COMMAND_REPLY_ERROR;
1215 argc = silc_argument_get_arg_num(cmd->args);
1217 COMMAND_REPLY_ERROR;
1222 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1224 COMMAND_REPLY_ERROR;
1231 if (cp[i++] == '\n') {
1232 memset(line, 0, sizeof(line));
1233 strncat(line, cp, i - 1);
1239 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1249 /* Notify application */
1250 COMMAND_REPLY((ARGS, motd));
1252 /* Execute any pending command callbacks */
1253 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1256 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1257 silc_client_command_reply_free(cmd);
1260 /* Received reply tot he UMODE command. Save the current user mode */
1262 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1264 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1265 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1266 SilcCommandStatus status;
1270 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1271 SILC_GET16_MSB(status, tmp);
1272 if (status != SILC_STATUS_OK) {
1273 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1274 "%s", silc_client_command_status_message(status));
1275 COMMAND_REPLY_ERROR;
1279 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1281 COMMAND_REPLY_ERROR;
1285 SILC_GET32_MSB(mode, tmp);
1286 conn->local_entry->mode = mode;
1288 /* Notify application */
1289 COMMAND_REPLY((ARGS, mode));
1291 /* Execute any pending command callbacks */
1292 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1295 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1296 silc_client_command_reply_free(cmd);
1299 /* Received reply for CMODE command. */
1301 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1303 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1304 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1305 SilcCommandStatus status;
1308 SilcIDCacheEntry id_cache;
1309 SilcChannelID *channel_id;
1310 SilcChannelEntry channel;
1313 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1314 if (status != SILC_STATUS_OK) {
1315 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1316 "%s", silc_client_command_status_message(status));
1317 COMMAND_REPLY_ERROR;
1321 /* Take Channel ID */
1322 tmp = silc_argument_get_arg_type(cmd->args, 2, &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;
1339 /* Get channel mode */
1340 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1342 silc_free(channel_id);
1343 COMMAND_REPLY_ERROR;
1348 SILC_GET32_MSB(mode, tmp);
1349 channel->mode = mode;
1351 /* Notify application */
1352 COMMAND_REPLY((ARGS, channel, mode));
1353 silc_free(channel_id);
1355 /* Execute any pending command callbacks */
1356 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1359 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1360 silc_client_command_reply_free(cmd);
1363 /* Received reply for CUMODE command */
1365 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1367 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1368 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1369 SilcCommandStatus status;
1370 SilcIDCacheEntry id_cache = NULL;
1371 SilcClientID *client_id;
1372 SilcChannelID *channel_id;
1373 SilcClientEntry client_entry;
1374 SilcChannelEntry channel;
1375 SilcChannelUser chu;
1376 unsigned char *tmp, *id;
1379 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1380 if (status != SILC_STATUS_OK) {
1381 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1382 "%s", silc_client_command_status_message(status));
1383 COMMAND_REPLY_ERROR;
1387 /* Get channel mode */
1388 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1390 COMMAND_REPLY_ERROR;
1394 /* Take Channel ID */
1395 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1398 channel_id = silc_id_payload_parse_id(tmp, len);
1402 /* Get the channel entry */
1403 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1405 silc_free(channel_id);
1406 COMMAND_REPLY_ERROR;
1410 channel = (SilcChannelEntry)id_cache->context;
1413 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1415 silc_free(channel_id);
1416 COMMAND_REPLY_ERROR;
1419 client_id = silc_id_payload_parse_id(id, len);
1421 silc_free(channel_id);
1422 COMMAND_REPLY_ERROR;
1426 /* Get client entry */
1427 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1429 silc_hash_client_id_compare, NULL,
1431 silc_free(channel_id);
1432 silc_free(client_id);
1433 COMMAND_REPLY_ERROR;
1437 client_entry = (SilcClientEntry)id_cache->context;
1440 SILC_GET32_MSB(mode, tmp);
1441 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1442 if (chu->client == client_entry) {
1448 /* Notify application */
1449 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1450 silc_free(client_id);
1451 silc_free(channel_id);
1453 /* Execute any pending command callbacks */
1454 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1457 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1458 silc_client_command_reply_free(cmd);
1461 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1463 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1464 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1465 SilcCommandStatus status;
1468 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1469 SILC_GET16_MSB(status, tmp);
1470 if (status != SILC_STATUS_OK) {
1471 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1472 "%s", silc_client_command_status_message(status));
1473 COMMAND_REPLY_ERROR;
1477 /* Notify application */
1478 COMMAND_REPLY((ARGS));
1480 /* Execute any pending command callbacks */
1481 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1484 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1485 silc_client_command_reply_free(cmd);
1488 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1490 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1491 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1492 SilcCommandStatus status;
1495 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1496 SILC_GET16_MSB(status, tmp);
1497 if (status != SILC_STATUS_OK) {
1498 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1499 "%s", silc_client_command_status_message(status));
1500 COMMAND_REPLY_ERROR;
1504 /* Notify application */
1505 COMMAND_REPLY((ARGS));
1507 /* Execute any pending command callbacks */
1508 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1511 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1512 silc_client_command_reply_free(cmd);
1515 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1517 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1518 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1519 SilcCommandStatus status;
1522 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1523 SILC_GET16_MSB(status, tmp);
1524 if (status != SILC_STATUS_OK) {
1525 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1526 "%s", silc_client_command_status_message(status));
1527 COMMAND_REPLY_ERROR;
1531 /* Notify application */
1532 COMMAND_REPLY((ARGS));
1534 /* Execute any pending command callbacks */
1535 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1538 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1539 silc_client_command_reply_free(cmd);
1542 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1544 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1545 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1546 SilcCommandStatus status;
1549 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1550 SILC_GET16_MSB(status, tmp);
1551 if (status != SILC_STATUS_OK) {
1552 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1553 "%s", silc_client_command_status_message(status));
1554 COMMAND_REPLY_ERROR;
1558 /* Notify application */
1559 COMMAND_REPLY((ARGS));
1561 /* Execute any pending command callbacks */
1562 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1565 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1566 silc_client_command_reply_free(cmd);
1569 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1571 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1572 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1573 SilcCommandStatus status;
1574 SilcIDCacheEntry id_cache = NULL;
1575 SilcChannelEntry channel;
1576 SilcChannelID *channel_id;
1580 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1581 SILC_GET16_MSB(status, tmp);
1582 if (status != SILC_STATUS_OK) {
1583 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1584 "%s", silc_client_command_status_message(status));
1585 COMMAND_REPLY_ERROR;
1589 /* Take Channel ID */
1590 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1594 channel_id = silc_id_payload_parse_id(tmp, len);
1598 /* Get the channel entry */
1599 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1601 silc_free(channel_id);
1602 COMMAND_REPLY_ERROR;
1606 channel = (SilcChannelEntry)id_cache->context;
1608 /* Get the ban list */
1609 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1611 /* Notify application */
1612 COMMAND_REPLY((ARGS, channel, tmp));
1614 /* Execute any pending command callbacks */
1615 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1618 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1619 silc_client_command_reply_free(cmd);
1622 SILC_CLIENT_CMD_REPLY_FUNC(close)
1624 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1625 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1626 SilcCommandStatus status;
1629 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1630 SILC_GET16_MSB(status, tmp);
1631 if (status != SILC_STATUS_OK) {
1632 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1633 "%s", silc_client_command_status_message(status));
1634 COMMAND_REPLY_ERROR;
1638 /* Notify application */
1639 COMMAND_REPLY((ARGS));
1641 /* Execute any pending command callbacks */
1642 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1645 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1646 silc_client_command_reply_free(cmd);
1649 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1651 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1652 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1653 SilcCommandStatus status;
1656 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1657 SILC_GET16_MSB(status, tmp);
1658 if (status != SILC_STATUS_OK) {
1659 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1660 "%s", silc_client_command_status_message(status));
1661 COMMAND_REPLY_ERROR;
1665 /* Notify application */
1666 COMMAND_REPLY((ARGS));
1668 /* Execute any pending command callbacks */
1669 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1672 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1673 silc_client_command_reply_free(cmd);
1676 /* Reply to LEAVE command. */
1678 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1680 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1681 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1682 SilcCommandStatus status;
1685 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1686 SILC_GET16_MSB(status, tmp);
1687 if (status != SILC_STATUS_OK) {
1688 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1689 "%s", silc_client_command_status_message(status));
1690 COMMAND_REPLY_ERROR;
1694 /* Notify application */
1695 COMMAND_REPLY((ARGS));
1697 /* Execute any pending command callbacks */
1698 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1701 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1702 silc_client_command_reply_free(cmd);
1705 /* Reply to USERS command. Received list of client ID's and theirs modes
1706 on the channel we requested. */
1708 SILC_CLIENT_CMD_REPLY_FUNC(users)
1710 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1711 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1712 SilcCommandStatus status;
1713 SilcIDCacheEntry id_cache = NULL;
1714 SilcChannelEntry channel;
1715 SilcChannelUser chu;
1716 SilcChannelID *channel_id = NULL;
1717 SilcBuffer client_id_list;
1718 SilcBuffer client_mode_list;
1720 uint32 tmp_len, list_count;
1722 unsigned char **res_argv = NULL;
1723 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1725 SILC_LOG_DEBUG(("Start"));
1727 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1728 SILC_GET16_MSB(status, tmp);
1729 if (status != SILC_STATUS_OK) {
1730 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1731 "%s", silc_client_command_status_message(status));
1732 COMMAND_REPLY_ERROR;
1736 /* Get channel ID */
1737 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1739 COMMAND_REPLY_ERROR;
1742 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1744 COMMAND_REPLY_ERROR;
1748 /* Get the list count */
1749 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1751 COMMAND_REPLY_ERROR;
1754 SILC_GET32_MSB(list_count, tmp);
1756 /* Get Client ID list */
1757 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1759 COMMAND_REPLY_ERROR;
1763 client_id_list = silc_buffer_alloc(tmp_len);
1764 silc_buffer_pull_tail(client_id_list, tmp_len);
1765 silc_buffer_put(client_id_list, tmp, tmp_len);
1767 /* Get client mode list */
1768 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1770 COMMAND_REPLY_ERROR;
1774 client_mode_list = silc_buffer_alloc(tmp_len);
1775 silc_buffer_pull_tail(client_mode_list, tmp_len);
1776 silc_buffer_put(client_mode_list, tmp, tmp_len);
1778 /* Get channel entry */
1779 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1781 /* Resolve the channel from server */
1782 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1784 /* Register pending command callback. After we've received the channel
1785 information we will reprocess this command reply by re-calling this
1786 USERS command reply callback. */
1787 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1788 NULL, silc_client_command_reply_users, cmd);
1791 channel = (SilcChannelEntry)id_cache->context;
1794 /* Remove old client list from channel. */
1795 silc_list_start(channel->clients);
1796 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1797 silc_list_del(channel->clients, chu);
1801 /* Cache the received Client ID's and modes. */
1802 for (i = 0; i < list_count; i++) {
1805 SilcClientID *client_id;
1806 SilcClientEntry client;
1809 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1811 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1816 SILC_GET32_MSB(mode, client_mode_list->data);
1818 /* Check if we have this client cached already. */
1820 silc_idcache_find_by_id_one_ext(conn->client_cache,
1823 silc_hash_client_id_compare, NULL,
1826 if (!id_cache || !((SilcClientEntry)id_cache->context)->username) {
1827 /* No we don't have it (or it is incomplete in information), query
1828 it from the server. Assemble argument table that will be sent
1829 for the WHOIS command later. */
1830 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1832 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1834 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1836 res_argv[res_argc] = client_id_list->data;
1837 res_argv_lens[res_argc] = idp_len;
1838 res_argv_types[res_argc] = res_argc + 3;
1841 /* Found the client, join it to the channel */
1842 client = (SilcClientEntry)id_cache->context;
1843 chu = silc_calloc(1, sizeof(*chu));
1844 chu->client = client;
1846 silc_list_add(channel->clients, chu);
1848 silc_free(client_id);
1852 silc_buffer_pull(client_id_list, idp_len);
1853 silc_buffer_pull(client_mode_list, 4);
1856 /* Query the client information from server if the list included clients
1857 that we don't know about. */
1861 /* Send the WHOIS command to server */
1862 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1863 res_argc, res_argv, res_argv_lens,
1864 res_argv_types, ++conn->cmd_ident);
1865 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1866 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1869 /* Register pending command callback. After we've received the WHOIS
1870 command reply we will reprocess this command reply by re-calling this
1871 USERS command reply callback. */
1872 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1873 NULL, silc_client_command_reply_users, cmd);
1875 silc_buffer_free(res_cmd);
1877 silc_free(channel_id);
1879 silc_free(res_argv);
1880 silc_free(res_argv_lens);
1881 silc_free(res_argv_types);
1885 /* Notify application */
1886 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1888 /* Execute any pending command callbacks */
1889 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1891 silc_buffer_free(client_id_list);
1892 silc_buffer_free(client_mode_list);
1896 silc_free(channel_id);
1897 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1898 silc_client_command_reply_free(cmd);
1901 /* Received command reply to GETKEY command. WE've received the remote
1902 client's public key. */
1904 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1906 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1907 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1908 SilcCommandStatus status;
1909 SilcIDCacheEntry id_cache;
1910 SilcIDPayload idp = NULL;
1911 SilcClientID *client_id = NULL;
1912 SilcClientEntry client_entry;
1913 SilcServerID *server_id = NULL;
1914 SilcServerEntry server_entry;
1916 unsigned char *tmp, *pk;
1920 SilcPublicKey public_key = NULL;
1922 SILC_LOG_DEBUG(("Start"));
1924 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1925 SILC_GET16_MSB(status, tmp);
1926 if (status != SILC_STATUS_OK) {
1927 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1928 "%s", silc_client_command_status_message(status));
1929 COMMAND_REPLY_ERROR;
1933 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1936 idp = silc_id_payload_parse_data(tmp, len);
1940 /* Get the public key payload */
1941 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1943 /* Decode the public key */
1944 SILC_GET16_MSB(pk_len, tmp);
1945 SILC_GET16_MSB(type, tmp + 2);
1948 if (type != SILC_SKE_PK_TYPE_SILC)
1951 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1955 id_type = silc_id_payload_get_type(idp);
1956 if (id_type == SILC_ID_CLIENT) {
1957 /* Received client's public key */
1958 client_id = silc_id_payload_get_id(idp);
1959 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1962 silc_hash_client_id_compare, NULL,
1966 client_entry = (SilcClientEntry)id_cache->context;
1968 /* Notify application */
1969 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1970 } else if (id_type == SILC_ID_SERVER) {
1971 /* Received server's public key */
1972 server_id = silc_id_payload_get_id(idp);
1973 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1977 server_entry = (SilcServerEntry)id_cache->context;
1979 /* Notify application */
1980 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1984 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1986 silc_id_payload_free(idp);
1988 silc_pkcs_public_key_free(public_key);
1989 silc_free(client_id);
1990 silc_free(server_id);
1991 silc_client_command_reply_free(cmd);