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 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);
530 server_entry->server_name = strdup(name);
532 server_entry->server_info = strdup(info);
534 /* Add server to cache */
535 silc_idcache_add(conn->server_cache, server_entry->server_name,
536 server_entry->server_id, (void *)server_entry, FALSE);
538 server_entry = (SilcServerEntry)id_cache->context;
541 /* Notify application */
542 COMMAND_REPLY((ARGS, server_entry, name, info));
545 case SILC_ID_CHANNEL:
546 channel_id = silc_id_payload_get_id(idp);
548 SILC_LOG_DEBUG(("Received channel information"));
550 /* Check if we have this channel cached already. */
551 if (!silc_idcache_find_by_id_one(conn->channel_cache,
552 (void *)channel_id, &id_cache)) {
553 SILC_LOG_DEBUG(("Adding new channel entry"));
554 channel_entry = silc_client_new_channel_id(client, conn->sock,
557 channel_entry = (SilcChannelEntry)id_cache->context;
560 /* Notify application */
561 COMMAND_REPLY((ARGS, channel_entry, name, info));
565 silc_id_payload_free(idp);
566 silc_free(client_id);
567 silc_free(server_id);
568 silc_free(channel_id);
571 /* Received reply for IDENTIFY command. This maybe called several times
572 for one IDENTIFY command as server may reply with list of results.
573 This is totally silent and does not print anything on screen. */
575 SILC_CLIENT_CMD_REPLY_FUNC(identify)
577 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
578 SilcCommandStatus status;
581 SILC_LOG_DEBUG(("Start"));
583 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
584 SILC_GET16_MSB(status, tmp);
585 if (status != SILC_STATUS_OK &&
586 status != SILC_STATUS_LIST_START &&
587 status != SILC_STATUS_LIST_ITEM &&
588 status != SILC_STATUS_LIST_END) {
593 /* Save one IDENTIFY entry */
594 if (status == SILC_STATUS_OK)
595 silc_client_command_reply_identify_save(cmd, status);
598 if (status == SILC_STATUS_LIST_START ||
599 status == SILC_STATUS_LIST_ITEM ||
600 status == SILC_STATUS_LIST_END)
601 silc_client_command_reply_identify_save(cmd, status);
603 /* Pending callbacks are not executed if this was an list entry */
604 if (status != SILC_STATUS_OK &&
605 status != SILC_STATUS_LIST_END) {
606 silc_client_command_reply_free(cmd);
610 /* Execute any pending command callbacks */
611 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
614 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
615 silc_client_command_reply_free(cmd);
618 /* Received reply for command NICK. If everything went without errors
619 we just received our new Client ID. */
621 SILC_CLIENT_CMD_REPLY_FUNC(nick)
623 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
624 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
625 SilcCommandStatus status;
630 SILC_LOG_DEBUG(("Start"));
632 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
633 if (status != SILC_STATUS_OK) {
634 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
635 "Cannot set nickname: %s",
636 silc_client_command_status_message(status));
641 argc = silc_argument_get_arg_num(cmd->args);
642 if (argc < 2 || argc > 2) {
643 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
644 "Cannot set nickname: bad reply to command");
649 /* Take received Client ID */
650 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
651 idp = silc_id_payload_parse_data(tmp, len);
656 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
658 /* Notify application */
659 COMMAND_REPLY((ARGS, conn->local_entry));
661 /* Execute any pending command callbacks */
662 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
665 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
666 silc_client_command_reply_free(cmd);
669 /* Received reply to the LIST command. */
671 SILC_CLIENT_CMD_REPLY_FUNC(list)
673 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
674 SilcCommandStatus status;
675 unsigned char *tmp, *name, *topic;
676 uint32 usercount = 0;
678 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
679 SILC_GET16_MSB(status, tmp);
680 if (status != SILC_STATUS_OK &&
681 status != SILC_STATUS_LIST_START &&
682 status != SILC_STATUS_LIST_ITEM &&
683 status != SILC_STATUS_LIST_END) {
688 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
689 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
690 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
692 SILC_GET32_MSB(usercount, tmp);
694 /* Notify application */
695 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
697 /* Pending callbacks are not executed if this was an list entry */
698 if (status != SILC_STATUS_OK &&
699 status != SILC_STATUS_LIST_END) {
700 silc_client_command_reply_free(cmd);
704 /* Execute any pending command callbacks */
705 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
708 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
709 silc_client_command_reply_free(cmd);
712 /* Received reply to topic command. */
714 SILC_CLIENT_CMD_REPLY_FUNC(topic)
716 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
717 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
718 SilcCommandStatus status;
719 SilcChannelEntry channel;
720 SilcChannelID *channel_id = NULL;
721 SilcIDCacheEntry id_cache = NULL;
726 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
727 if (status != SILC_STATUS_OK) {
728 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
729 "%s", silc_client_command_status_message(status));
731 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
732 silc_client_command_reply_free(cmd);
736 argc = silc_argument_get_arg_num(cmd->args);
737 if (argc < 1 || argc > 3) {
742 /* Take Channel ID */
743 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
748 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
752 channel_id = silc_id_payload_parse_id(tmp, len);
756 /* Get the channel entry */
757 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
759 silc_free(channel_id);
764 channel = (SilcChannelEntry)id_cache->context;
766 /* Notify application */
767 COMMAND_REPLY((ARGS, channel, topic));
769 /* Execute any pending command callbacks */
770 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
773 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
774 silc_client_command_reply_free(cmd);
777 /* Received reply to invite command. */
779 SILC_CLIENT_CMD_REPLY_FUNC(invite)
781 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
782 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
783 SilcCommandStatus status;
784 SilcChannelEntry channel;
785 SilcChannelID *channel_id;
786 SilcIDCacheEntry id_cache;
790 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
791 SILC_GET16_MSB(status, tmp);
792 if (status != SILC_STATUS_OK) {
793 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
794 "%s", silc_client_command_status_message(status));
796 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
797 silc_client_command_reply_free(cmd);
801 /* Take Channel ID */
802 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
806 channel_id = silc_id_payload_parse_id(tmp, len);
810 /* Get the channel entry */
811 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
813 silc_free(channel_id);
818 channel = (SilcChannelEntry)id_cache->context;
820 /* Get the invite list */
821 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
823 /* Notify application */
824 COMMAND_REPLY((ARGS, channel, tmp));
826 /* Execute any pending command callbacks */
827 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
830 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
831 silc_client_command_reply_free(cmd);
834 /* Received reply to the KILL command. */
836 SILC_CLIENT_CMD_REPLY_FUNC(kill)
838 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
839 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
840 SilcCommandStatus status;
843 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
844 SILC_GET16_MSB(status, tmp);
845 if (status != SILC_STATUS_OK) {
846 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
847 "%s", silc_client_command_status_message(status));
852 /* Notify application */
853 COMMAND_REPLY((ARGS));
855 /* Execute any pending command callbacks */
856 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
859 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
860 silc_client_command_reply_free(cmd);
863 /* Received reply to INFO command. We receive the server ID and some
864 information about the server user requested. */
866 SILC_CLIENT_CMD_REPLY_FUNC(info)
868 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
869 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
870 SilcCommandStatus status;
872 SilcIDCacheEntry id_cache;
873 SilcServerEntry server;
874 SilcServerID *server_id = NULL;
875 char *server_name, *server_info;
878 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
879 SILC_GET16_MSB(status, tmp);
880 if (status != SILC_STATUS_OK) {
881 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
882 "%s", silc_client_command_status_message(status));
884 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
885 silc_client_command_reply_free(cmd);
890 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
894 server_id = silc_id_payload_parse_id(tmp, len);
898 /* Get server name */
899 server_name = silc_argument_get_arg_type(cmd->args, 3, NULL);
903 /* Get server info */
904 server_info = silc_argument_get_arg_type(cmd->args, 4, NULL);
908 /* See whether we have this server cached. If not create it. */
909 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
911 SILC_LOG_DEBUG(("New server entry"));
913 server = silc_calloc(1, sizeof(*server));
914 server->server_name = strdup(server_name);
915 server->server_info = strdup(server_info);
916 server->server_id = silc_id_dup(server_id, SILC_ID_SERVER);
918 /* Add it to the cache */
919 silc_idcache_add(conn->server_cache, server->server_name,
920 server->server_id, (void *)server, FALSE);
922 server = (SilcServerEntry)id_cache->context;
925 /* Notify application */
926 COMMAND_REPLY((ARGS, server, server->server_name, server->server_info));
928 /* Execute any pending command callbacks */
929 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
933 silc_free(server_id);
934 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
935 silc_client_command_reply_free(cmd);
938 /* Received reply to PING command. The reply time is shown to user. */
940 SILC_CLIENT_CMD_REPLY_FUNC(ping)
942 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
943 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
944 SilcCommandStatus status;
947 time_t diff, curtime;
949 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
950 if (status != SILC_STATUS_OK) {
951 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
952 "%s", silc_client_command_status_message(status));
957 curtime = time(NULL);
958 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
959 cmd->packet->src_id_type);
965 for (i = 0; i < conn->ping_count; i++) {
966 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
967 diff = curtime - conn->ping[i].start_time;
968 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
969 "Ping reply from %s: %d second%s",
970 conn->ping[i].dest_name, diff,
971 diff == 1 ? "" : "s");
973 conn->ping[i].start_time = 0;
974 silc_free(conn->ping[i].dest_id);
975 conn->ping[i].dest_id = NULL;
976 silc_free(conn->ping[i].dest_name);
977 conn->ping[i].dest_name = NULL;
984 /* Notify application */
985 COMMAND_REPLY((ARGS));
987 /* Execute any pending command callbacks */
988 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
991 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
992 silc_client_command_reply_free(cmd);
995 /* Received reply for JOIN command. */
997 SILC_CLIENT_CMD_REPLY_FUNC(join)
999 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1000 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1001 SilcCommandStatus status;
1002 SilcIDPayload idp = NULL;
1003 SilcChannelEntry channel;
1004 SilcIDCacheEntry id_cache = NULL;
1005 SilcChannelUser chu;
1006 uint32 argc, mode, len, list_count;
1007 char *topic, *tmp, *channel_name = NULL, *hmac;
1008 SilcBuffer keyp = NULL, client_id_list, client_mode_list;
1011 SILC_LOG_DEBUG(("Start"));
1013 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1014 if (status != SILC_STATUS_OK) {
1015 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1016 "%s", silc_client_command_status_message(status));
1017 COMMAND_REPLY_ERROR;
1021 argc = silc_argument_get_arg_num(cmd->args);
1022 if (argc < 7 || argc > 14) {
1023 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1024 "Cannot join channel: Bad reply packet");
1025 COMMAND_REPLY_ERROR;
1029 /* Get channel name */
1030 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1032 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1033 "Cannot join channel: Bad reply packet");
1034 COMMAND_REPLY_ERROR;
1037 channel_name = strdup(tmp);
1039 /* Get Channel ID */
1040 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1042 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1043 "Cannot join channel: Bad reply packet");
1044 COMMAND_REPLY_ERROR;
1045 silc_free(channel_name);
1048 idp = silc_id_payload_parse_data(tmp, len);
1050 COMMAND_REPLY_ERROR;
1051 silc_free(channel_name);
1055 /* Get channel mode */
1056 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1058 SILC_GET32_MSB(mode, tmp);
1062 /* Get channel key */
1063 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
1065 keyp = silc_buffer_alloc(len);
1066 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
1067 silc_buffer_put(keyp, tmp, len);
1071 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
1073 /* Save received Channel ID. This actually creates the channel */
1074 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
1076 silc_id_payload_free(idp);
1078 conn->current_channel = channel;
1081 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
1083 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
1084 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1085 "Cannot join channel: Unsupported HMAC `%s'",
1087 COMMAND_REPLY_ERROR;
1088 silc_free(channel_name);
1093 /* Get the list count */
1094 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1097 SILC_GET32_MSB(list_count, tmp);
1099 /* Get Client ID list */
1100 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1104 client_id_list = silc_buffer_alloc(len);
1105 silc_buffer_pull_tail(client_id_list, len);
1106 silc_buffer_put(client_id_list, tmp, len);
1108 /* Get client mode list */
1109 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1113 client_mode_list = silc_buffer_alloc(len);
1114 silc_buffer_pull_tail(client_mode_list, len);
1115 silc_buffer_put(client_mode_list, tmp, len);
1117 /* Add clients we received in the reply to the channel */
1118 for (i = 0; i < list_count; i++) {
1121 SilcClientID *client_id;
1122 SilcClientEntry client_entry;
1125 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1127 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1132 SILC_GET32_MSB(mode, client_mode_list->data);
1134 /* Check if we have this client cached already. */
1135 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1138 silc_hash_client_id_compare, NULL,
1140 /* No, we don't have it, add entry for it. */
1141 client_entry = silc_calloc(1, sizeof(*client_entry));
1142 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1143 silc_idcache_add(conn->client_cache, NULL, client_entry->id,
1144 (void *)client_entry, FALSE);
1146 /* Yes, we have it already */
1147 client_entry = (SilcClientEntry)id_cache->context;
1150 /* Join the client to the channel */
1151 chu = silc_calloc(1, sizeof(*chu));
1152 chu->client = client_entry;
1154 silc_list_add(channel->clients, chu);
1155 silc_free(client_id);
1157 silc_buffer_pull(client_id_list, idp_len);
1158 silc_buffer_pull(client_mode_list, 4);
1160 silc_buffer_push(client_id_list, client_id_list->data -
1161 client_id_list->head);
1162 silc_buffer_push(client_mode_list, client_mode_list->data -
1163 client_mode_list->head);
1165 /* Save channel key */
1166 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1167 silc_client_save_channel_key(conn, keyp, channel);
1169 /* Client is now joined to the channel */
1170 channel->on_channel = TRUE;
1172 /* Notify application */
1173 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1174 keyp ? keyp->head : NULL, NULL,
1175 NULL, topic, hmac, list_count, client_id_list,
1178 /* Execute any pending command callbacks */
1179 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1182 silc_buffer_free(keyp);
1183 silc_buffer_free(client_id_list);
1184 silc_buffer_free(client_mode_list);
1187 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1188 silc_client_command_reply_free(cmd);
1191 /* Received reply for MOTD command */
1193 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1195 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1196 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1197 SilcCommandStatus status;
1200 char *motd = NULL, *cp, line[256];
1202 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1203 SILC_GET16_MSB(status, tmp);
1204 if (status != SILC_STATUS_OK) {
1205 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1206 "%s", silc_client_command_status_message(status));
1207 COMMAND_REPLY_ERROR;
1211 argc = silc_argument_get_arg_num(cmd->args);
1213 COMMAND_REPLY_ERROR;
1218 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1220 COMMAND_REPLY_ERROR;
1227 if (cp[i++] == '\n') {
1228 memset(line, 0, sizeof(line));
1229 strncat(line, cp, i - 1);
1235 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
1245 /* Notify application */
1246 COMMAND_REPLY((ARGS, motd));
1248 /* Execute any pending command callbacks */
1249 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1252 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1253 silc_client_command_reply_free(cmd);
1256 /* Received reply tot he UMODE command. Save the current user mode */
1258 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1260 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1261 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1262 SilcCommandStatus status;
1266 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1267 SILC_GET16_MSB(status, tmp);
1268 if (status != SILC_STATUS_OK) {
1269 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1270 "%s", silc_client_command_status_message(status));
1271 COMMAND_REPLY_ERROR;
1275 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1277 COMMAND_REPLY_ERROR;
1281 SILC_GET32_MSB(mode, tmp);
1282 conn->local_entry->mode = mode;
1284 /* Notify application */
1285 COMMAND_REPLY((ARGS, mode));
1287 /* Execute any pending command callbacks */
1288 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1291 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1292 silc_client_command_reply_free(cmd);
1295 /* Received reply for CMODE command. */
1297 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1299 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1300 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1301 SilcCommandStatus status;
1304 SilcIDCacheEntry id_cache;
1305 SilcChannelID *channel_id;
1306 SilcChannelEntry channel;
1309 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1310 if (status != SILC_STATUS_OK) {
1311 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1312 "%s", silc_client_command_status_message(status));
1313 COMMAND_REPLY_ERROR;
1317 /* Take Channel ID */
1318 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1321 channel_id = silc_id_payload_parse_id(tmp, len);
1325 /* Get the channel entry */
1326 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1328 silc_free(channel_id);
1329 COMMAND_REPLY_ERROR;
1333 channel = (SilcChannelEntry)id_cache->context;
1335 /* Get channel mode */
1336 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
1338 silc_free(channel_id);
1339 COMMAND_REPLY_ERROR;
1344 SILC_GET32_MSB(mode, tmp);
1345 channel->mode = mode;
1347 /* Notify application */
1348 COMMAND_REPLY((ARGS, channel, mode));
1349 silc_free(channel_id);
1351 /* Execute any pending command callbacks */
1352 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1355 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1356 silc_client_command_reply_free(cmd);
1359 /* Received reply for CUMODE command */
1361 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1363 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1364 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1365 SilcCommandStatus status;
1366 SilcIDCacheEntry id_cache = NULL;
1367 SilcClientID *client_id;
1368 SilcChannelID *channel_id;
1369 SilcClientEntry client_entry;
1370 SilcChannelEntry channel;
1371 SilcChannelUser chu;
1372 unsigned char *tmp, *id;
1375 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1376 if (status != SILC_STATUS_OK) {
1377 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1378 "%s", silc_client_command_status_message(status));
1379 COMMAND_REPLY_ERROR;
1383 /* Get channel mode */
1384 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1386 COMMAND_REPLY_ERROR;
1390 /* Take Channel ID */
1391 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1394 channel_id = silc_id_payload_parse_id(tmp, len);
1398 /* Get the channel entry */
1399 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1401 silc_free(channel_id);
1402 COMMAND_REPLY_ERROR;
1406 channel = (SilcChannelEntry)id_cache->context;
1409 id = silc_argument_get_arg_type(cmd->args, 4, &len);
1411 silc_free(channel_id);
1412 COMMAND_REPLY_ERROR;
1415 client_id = silc_id_payload_parse_id(id, len);
1417 silc_free(channel_id);
1418 COMMAND_REPLY_ERROR;
1422 /* Get client entry */
1423 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1425 silc_hash_client_id_compare, NULL,
1427 silc_free(channel_id);
1428 silc_free(client_id);
1429 COMMAND_REPLY_ERROR;
1433 client_entry = (SilcClientEntry)id_cache->context;
1436 SILC_GET32_MSB(mode, tmp);
1437 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1438 if (chu->client == client_entry) {
1444 /* Notify application */
1445 COMMAND_REPLY((ARGS, mode, channel, client_entry));
1446 silc_free(client_id);
1447 silc_free(channel_id);
1449 /* Execute any pending command callbacks */
1450 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1453 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1454 silc_client_command_reply_free(cmd);
1457 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1459 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1460 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1461 SilcCommandStatus status;
1464 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1465 SILC_GET16_MSB(status, tmp);
1466 if (status != SILC_STATUS_OK) {
1467 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1468 "%s", silc_client_command_status_message(status));
1469 COMMAND_REPLY_ERROR;
1473 /* Notify application */
1474 COMMAND_REPLY((ARGS));
1476 /* Execute any pending command callbacks */
1477 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1480 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1481 silc_client_command_reply_free(cmd);
1484 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1486 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1487 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1488 SilcCommandStatus status;
1491 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1492 SILC_GET16_MSB(status, tmp);
1493 if (status != SILC_STATUS_OK) {
1494 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1495 "%s", silc_client_command_status_message(status));
1496 COMMAND_REPLY_ERROR;
1500 /* Notify application */
1501 COMMAND_REPLY((ARGS));
1503 /* Execute any pending command callbacks */
1504 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1507 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1508 silc_client_command_reply_free(cmd);
1511 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1513 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1514 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1515 SilcCommandStatus status;
1518 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1519 SILC_GET16_MSB(status, tmp);
1520 if (status != SILC_STATUS_OK) {
1521 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1522 "%s", silc_client_command_status_message(status));
1523 COMMAND_REPLY_ERROR;
1527 /* Notify application */
1528 COMMAND_REPLY((ARGS));
1530 /* Execute any pending command callbacks */
1531 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1534 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1535 silc_client_command_reply_free(cmd);
1538 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1540 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1541 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1542 SilcCommandStatus status;
1545 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1546 SILC_GET16_MSB(status, tmp);
1547 if (status != SILC_STATUS_OK) {
1548 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1549 "%s", silc_client_command_status_message(status));
1550 COMMAND_REPLY_ERROR;
1554 /* Notify application */
1555 COMMAND_REPLY((ARGS));
1557 /* Execute any pending command callbacks */
1558 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1561 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1562 silc_client_command_reply_free(cmd);
1565 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1567 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1568 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1569 SilcCommandStatus status;
1570 SilcIDCacheEntry id_cache = NULL;
1571 SilcChannelEntry channel;
1572 SilcChannelID *channel_id;
1576 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1577 SILC_GET16_MSB(status, tmp);
1578 if (status != SILC_STATUS_OK) {
1579 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1580 "%s", silc_client_command_status_message(status));
1581 COMMAND_REPLY_ERROR;
1585 /* Take Channel ID */
1586 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1590 channel_id = silc_id_payload_parse_id(tmp, len);
1594 /* Get the channel entry */
1595 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1597 silc_free(channel_id);
1598 COMMAND_REPLY_ERROR;
1602 channel = (SilcChannelEntry)id_cache->context;
1604 /* Get the ban list */
1605 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1607 /* Notify application */
1608 COMMAND_REPLY((ARGS, channel, tmp));
1610 /* Execute any pending command callbacks */
1611 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1614 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1615 silc_client_command_reply_free(cmd);
1618 SILC_CLIENT_CMD_REPLY_FUNC(close)
1620 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1621 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1622 SilcCommandStatus status;
1625 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1626 SILC_GET16_MSB(status, tmp);
1627 if (status != SILC_STATUS_OK) {
1628 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1629 "%s", silc_client_command_status_message(status));
1630 COMMAND_REPLY_ERROR;
1634 /* Notify application */
1635 COMMAND_REPLY((ARGS));
1637 /* Execute any pending command callbacks */
1638 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1641 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1642 silc_client_command_reply_free(cmd);
1645 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1647 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1648 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1649 SilcCommandStatus status;
1652 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1653 SILC_GET16_MSB(status, tmp);
1654 if (status != SILC_STATUS_OK) {
1655 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1656 "%s", silc_client_command_status_message(status));
1657 COMMAND_REPLY_ERROR;
1661 /* Notify application */
1662 COMMAND_REPLY((ARGS));
1664 /* Execute any pending command callbacks */
1665 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1668 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1669 silc_client_command_reply_free(cmd);
1672 /* Reply to LEAVE command. */
1674 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1676 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1677 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1678 SilcCommandStatus status;
1681 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1682 SILC_GET16_MSB(status, tmp);
1683 if (status != SILC_STATUS_OK) {
1684 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1685 "%s", silc_client_command_status_message(status));
1686 COMMAND_REPLY_ERROR;
1690 /* Notify application */
1691 COMMAND_REPLY((ARGS));
1693 /* Execute any pending command callbacks */
1694 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1697 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1698 silc_client_command_reply_free(cmd);
1701 /* Reply to USERS command. Received list of client ID's and theirs modes
1702 on the channel we requested. */
1704 SILC_CLIENT_CMD_REPLY_FUNC(users)
1706 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1707 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1708 SilcCommandStatus status;
1709 SilcIDCacheEntry id_cache = NULL;
1710 SilcChannelEntry channel;
1711 SilcChannelUser chu;
1712 SilcChannelID *channel_id = NULL;
1713 SilcBuffer client_id_list;
1714 SilcBuffer client_mode_list;
1716 uint32 tmp_len, list_count;
1718 unsigned char **res_argv = NULL;
1719 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1721 SILC_LOG_DEBUG(("Start"));
1723 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1724 SILC_GET16_MSB(status, tmp);
1725 if (status != SILC_STATUS_OK) {
1726 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1727 "%s", silc_client_command_status_message(status));
1728 COMMAND_REPLY_ERROR;
1732 /* Get channel ID */
1733 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1735 COMMAND_REPLY_ERROR;
1738 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1740 COMMAND_REPLY_ERROR;
1744 /* Get the list count */
1745 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1747 COMMAND_REPLY_ERROR;
1750 SILC_GET32_MSB(list_count, tmp);
1752 /* Get Client ID list */
1753 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1755 COMMAND_REPLY_ERROR;
1759 client_id_list = silc_buffer_alloc(tmp_len);
1760 silc_buffer_pull_tail(client_id_list, tmp_len);
1761 silc_buffer_put(client_id_list, tmp, tmp_len);
1763 /* Get client mode list */
1764 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1766 COMMAND_REPLY_ERROR;
1770 client_mode_list = silc_buffer_alloc(tmp_len);
1771 silc_buffer_pull_tail(client_mode_list, tmp_len);
1772 silc_buffer_put(client_mode_list, tmp, tmp_len);
1774 /* Get channel entry */
1775 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1777 /* Resolve the channel from server */
1778 silc_idlist_get_channel_by_id(cmd->client, conn, channel_id, TRUE);
1780 /* Register pending command callback. After we've received the channel
1781 information we will reprocess this command reply by re-calling this
1782 USERS command reply callback. */
1783 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1784 NULL, silc_client_command_reply_users, cmd);
1787 channel = (SilcChannelEntry)id_cache->context;
1790 /* Remove old client list from channel. */
1791 silc_list_start(channel->clients);
1792 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1793 silc_list_del(channel->clients, chu);
1797 /* Cache the received Client ID's and modes. */
1798 for (i = 0; i < list_count; i++) {
1801 SilcClientID *client_id;
1802 SilcClientEntry client;
1805 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1807 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1812 SILC_GET32_MSB(mode, client_mode_list->data);
1814 /* Check if we have this client cached already. */
1816 silc_idcache_find_by_id_one_ext(conn->client_cache,
1819 silc_hash_client_id_compare, NULL,
1822 if (!id_cache || !((SilcClientEntry)id_cache->context)->username) {
1823 /* No we don't have it (or it is incomplete in information), query
1824 it from the server. Assemble argument table that will be sent
1825 for the WHOIS command later. */
1826 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1828 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1830 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1832 res_argv[res_argc] = client_id_list->data;
1833 res_argv_lens[res_argc] = idp_len;
1834 res_argv_types[res_argc] = res_argc + 3;
1837 /* Found the client, join it to the channel */
1838 client = (SilcClientEntry)id_cache->context;
1839 chu = silc_calloc(1, sizeof(*chu));
1840 chu->client = client;
1842 silc_list_add(channel->clients, chu);
1844 silc_free(client_id);
1848 silc_buffer_pull(client_id_list, idp_len);
1849 silc_buffer_pull(client_mode_list, 4);
1852 /* Query the client information from server if the list included clients
1853 that we don't know about. */
1857 /* Send the WHOIS command to server */
1858 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1859 res_argc, res_argv, res_argv_lens,
1860 res_argv_types, ++conn->cmd_ident);
1861 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1862 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1865 /* Register pending command callback. After we've received the WHOIS
1866 command reply we will reprocess this command reply by re-calling this
1867 USERS command reply callback. */
1868 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
1869 NULL, silc_client_command_reply_users, cmd);
1871 silc_buffer_free(res_cmd);
1873 silc_free(channel_id);
1875 silc_free(res_argv);
1876 silc_free(res_argv_lens);
1877 silc_free(res_argv_types);
1881 /* Notify application */
1882 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1884 /* Execute any pending command callbacks */
1885 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1887 silc_buffer_free(client_id_list);
1888 silc_buffer_free(client_mode_list);
1892 silc_free(channel_id);
1893 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1894 silc_client_command_reply_free(cmd);
1897 /* Received command reply to GETKEY command. WE've received the remote
1898 client's public key. */
1900 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1902 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1903 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1904 SilcCommandStatus status;
1905 SilcIDCacheEntry id_cache;
1906 SilcIDPayload idp = NULL;
1907 SilcClientID *client_id = NULL;
1908 SilcClientEntry client_entry;
1909 SilcServerID *server_id = NULL;
1910 SilcServerEntry server_entry;
1912 unsigned char *tmp, *pk;
1916 SilcPublicKey public_key = NULL;
1918 SILC_LOG_DEBUG(("Start"));
1920 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1921 SILC_GET16_MSB(status, tmp);
1922 if (status != SILC_STATUS_OK) {
1923 cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
1924 "%s", silc_client_command_status_message(status));
1925 COMMAND_REPLY_ERROR;
1929 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1932 idp = silc_id_payload_parse_data(tmp, len);
1936 /* Get the public key payload */
1937 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1941 /* Decode the public key */
1943 SILC_GET16_MSB(pk_len, tmp);
1944 SILC_GET16_MSB(type, tmp + 2);
1947 if (type != SILC_SKE_PK_TYPE_SILC)
1950 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1953 id_type = silc_id_payload_get_type(idp);
1954 if (id_type == SILC_ID_CLIENT) {
1955 /* Received client's public key */
1956 client_id = silc_id_payload_get_id(idp);
1957 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1960 silc_hash_client_id_compare, NULL,
1964 client_entry = (SilcClientEntry)id_cache->context;
1966 /* Notify application */
1967 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1968 } else if (id_type == SILC_ID_SERVER) {
1969 /* Received server's public key */
1970 server_id = silc_id_payload_get_id(idp);
1971 if (!silc_idcache_find_by_id_one(conn->server_cache, (void *)server_id,
1975 server_entry = (SilcServerEntry)id_cache->context;
1977 /* Notify application */
1978 COMMAND_REPLY((ARGS, id_type, server_entry, public_key));
1982 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1984 silc_id_payload_free(idp);
1986 silc_pkcs_public_key_free(public_key);
1987 silc_free(client_id);
1988 silc_free(server_id);
1989 silc_client_command_reply_free(cmd);