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), "No such Client ID" },
86 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
87 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
88 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
89 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
90 { STAT(USER_ON_CHANNEL), "User already on the channel" },
91 { STAT(NOT_REGISTERED), "You have not registered" },
92 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
93 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
94 { STAT(PERM_DENIED), "Permission denied" },
95 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
96 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
97 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
98 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
99 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
100 { STAT(UNKNOWN_MODE), "Unknown mode" },
101 { STAT(NOT_YOU), "Cannot change mode for other users" },
102 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
103 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
104 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
105 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
106 { STAT(BAD_NICKNAME), "Bad nickname" },
107 { STAT(BAD_CHANNEL), "Bad channel name" },
108 { STAT(AUTH_FAILED), "Authentication failed" },
109 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
110 { STAT(NO_SUCH_SERVER_ID), "No such Server ID" },
114 /* Command reply operation that is called at the end of all command replys.
115 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
116 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
117 #define ARGS cmd->client, cmd->sock->user_data, \
118 cmd->payload, TRUE, silc_command_get(cmd->payload), status
120 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
121 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
122 cmd->sock->user_data, cmd->payload, FALSE, \
123 silc_command_get(cmd->payload), status)
125 /* Process received command reply. */
127 void silc_client_command_reply_process(SilcClient client,
128 SilcSocketConnection sock,
129 SilcPacketContext *packet)
131 SilcBuffer buffer = packet->buffer;
132 SilcClientCommandReply *cmd;
133 SilcClientCommandReplyContext ctx;
134 SilcCommandPayload payload;
138 /* Get command reply payload from packet */
139 payload = silc_command_payload_parse(buffer);
141 /* Silently ignore bad reply packet */
142 SILC_LOG_DEBUG(("Bad command reply packet"));
146 /* Allocate command reply context. This must be free'd by the
147 command reply routine receiving it. */
148 ctx = silc_calloc(1, sizeof(*ctx));
149 ctx->client = client;
151 ctx->payload = payload;
152 ctx->args = silc_command_get_args(ctx->payload);
153 ctx->packet = packet;
154 ident = silc_command_get_ident(ctx->payload);
156 /* Check for pending commands and mark to be exeucted */
157 silc_client_command_pending_check(sock->user_data, ctx,
158 silc_command_get(ctx->payload), ident);
160 /* Execute command reply */
161 command = silc_command_get(ctx->payload);
162 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
163 if (cmd->cmd == command)
166 if (cmd == NULL || !cmd->cb) {
174 /* Returns status message string */
176 char *silc_client_command_status_message(SilcCommandStatus status)
180 for (i = 0; silc_command_status_messages[i].message; i++) {
181 if (silc_command_status_messages[i].status == status)
185 if (silc_command_status_messages[i].message == NULL)
188 return silc_command_status_messages[i].message;
191 /* Free command reply context and its internals. */
193 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
196 silc_command_payload_free(cmd->payload);
202 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
203 SilcCommandStatus status)
205 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
206 SilcClientID *client_id;
207 SilcIDCacheEntry id_cache = NULL;
208 SilcClientEntry client_entry = NULL;
211 unsigned char *id_data, *tmp;
212 char *nickname = NULL, *username = NULL;
213 char *realname = NULL;
214 uint32 idle = 0, mode = 0;
215 SilcBuffer channels = NULL;
217 argc = silc_argument_get_arg_num(cmd->args);
219 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
225 client_id = silc_id_payload_parse_id(id_data, len);
231 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
232 username = silc_argument_get_arg_type(cmd->args, 4, &len);
233 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
234 if (!nickname || !username || !realname) {
239 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
241 channels = silc_buffer_alloc(len);
242 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
243 silc_buffer_put(channels, tmp, len);
246 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
248 SILC_GET32_MSB(mode, tmp);
250 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
252 SILC_GET32_MSB(idle, tmp);
254 /* Check if we have this client cached already. */
255 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
257 silc_hash_client_id_compare, NULL,
259 SILC_LOG_DEBUG(("Adding new client entry"));
261 client_entry = silc_calloc(1, sizeof(*client_entry));
262 client_entry->id = client_id;
263 silc_parse_nickname(nickname, &client_entry->nickname,
264 &client_entry->server, &client_entry->num);
265 client_entry->username = strdup(username);
267 client_entry->realname = strdup(realname);
268 client_entry->mode = mode;
270 /* Add client to cache */
271 silc_idcache_add(conn->client_cache, client_entry->nickname,
272 client_id, (void *)client_entry, FALSE);
274 client_entry = (SilcClientEntry)id_cache->context;
275 if (client_entry->nickname)
276 silc_free(client_entry->nickname);
277 if (client_entry->server)
278 silc_free(client_entry->server);
279 if (client_entry->username)
280 silc_free(client_entry->username);
281 if (client_entry->realname)
282 silc_free(client_entry->realname);
283 client_entry->mode = mode;
285 SILC_LOG_DEBUG(("Updating client entry"));
287 silc_parse_nickname(nickname, &client_entry->nickname,
288 &client_entry->server, &client_entry->num);
289 client_entry->username = strdup(username);
291 client_entry->realname = strdup(realname);
293 /* Remove the old cache entry and create a new one */
294 silc_idcache_del_by_context(conn->client_cache, client_entry);
295 silc_idcache_add(conn->client_cache, client_entry->nickname,
296 client_entry->id, client_entry, FALSE);
297 silc_free(client_id);
300 /* Notify application */
302 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
303 channels, mode, idle));
306 silc_buffer_free(channels);
309 /* Received reply for WHOIS command. This maybe called several times
310 for one WHOIS command as server may reply with list of results. */
312 SILC_CLIENT_CMD_REPLY_FUNC(whois)
314 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
315 SilcCommandStatus status;
318 SILC_LOG_DEBUG(("Start"));
320 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
321 SILC_GET16_MSB(status, tmp);
322 if (status != SILC_STATUS_OK &&
323 status != SILC_STATUS_LIST_START &&
324 status != SILC_STATUS_LIST_ITEM &&
325 status != SILC_STATUS_LIST_END) {
330 /* Display one whois reply */
331 if (status == SILC_STATUS_OK)
332 silc_client_command_reply_whois_save(cmd, status);
335 if (status == SILC_STATUS_LIST_START ||
336 status == SILC_STATUS_LIST_ITEM ||
337 status == SILC_STATUS_LIST_END)
338 silc_client_command_reply_whois_save(cmd, status);
340 /* Pending callbacks are not executed if this was an list entry */
341 if (status != SILC_STATUS_OK &&
342 status != SILC_STATUS_LIST_END) {
343 silc_client_command_reply_free(cmd);
347 /* Execute any pending command callbacks */
348 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
351 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
352 silc_client_command_reply_free(cmd);
355 /* Received reply for WHOWAS command. */
357 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
359 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
360 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
361 SilcCommandStatus status;
362 SilcClientID *client_id;
363 SilcIDCacheEntry id_cache = NULL;
364 SilcClientEntry client_entry = NULL;
366 unsigned char *id_data, *tmp;
367 char *nickname, *username;
368 char *realname = NULL;
370 SILC_LOG_DEBUG(("Start"));
372 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
373 SILC_GET16_MSB(status, tmp);
374 if (status != SILC_STATUS_OK &&
375 status != SILC_STATUS_LIST_START &&
376 status != SILC_STATUS_LIST_ITEM &&
377 status != SILC_STATUS_LIST_END) {
382 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
388 client_id = silc_id_payload_parse_id(id_data, len);
394 /* Get the client entry, if exists */
395 if (silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
397 silc_hash_client_id_compare, NULL,
399 client_entry = (SilcClientEntry)id_cache->context;
400 silc_free(client_id);
402 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
403 username = silc_argument_get_arg_type(cmd->args, 4, &len);
404 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
405 if (!nickname || !username) {
409 /* Notify application. We don't save any history information to any
410 cache. Just pass the data to the application for displaying on
412 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
414 /* Pending callbacks are not executed if this was an list entry */
415 if (status != SILC_STATUS_OK &&
416 status != SILC_STATUS_LIST_END) {
417 silc_client_command_reply_free(cmd);
421 /* Execute any pending command callbacks */
422 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
425 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
426 silc_client_command_reply_free(cmd);
430 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
431 SilcCommandStatus status)
433 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
434 SilcClientID *client_id;
435 SilcIDCacheEntry id_cache = NULL;
436 SilcClientEntry client_entry = NULL;
439 unsigned char *id_data;
440 char *nickname = NULL, *username = NULL;
442 argc = silc_argument_get_arg_num(cmd->args);
444 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
450 client_id = silc_id_payload_parse_id(id_data, len);
456 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
457 username = silc_argument_get_arg_type(cmd->args, 4, &len);
459 /* Check if we have this client cached already. */
460 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
462 silc_hash_client_id_compare, NULL,
464 SILC_LOG_DEBUG(("Adding new client entry"));
466 client_entry = silc_calloc(1, sizeof(*client_entry));
467 client_entry->id = client_id;
468 silc_parse_nickname(nickname, &client_entry->nickname,
469 &client_entry->server, &client_entry->num);
471 client_entry->username = strdup(username);
473 /* Add client to cache */
474 silc_idcache_add(conn->client_cache, client_entry->nickname,
475 client_id, (void *)client_entry, FALSE);
477 client_entry = (SilcClientEntry)id_cache->context;
478 if (client_entry->nickname)
479 silc_free(client_entry->nickname);
480 if (client_entry->server)
481 silc_free(client_entry->server);
482 if (username && client_entry->username)
483 silc_free(client_entry->username);
485 SILC_LOG_DEBUG(("Updating client entry"));
487 silc_parse_nickname(nickname, &client_entry->nickname,
488 &client_entry->server, &client_entry->num);
491 client_entry->username = strdup(username);
493 /* Remove the old cache entry and create a new one */
494 silc_idcache_del_by_context(conn->client_cache, client_entry);
495 silc_idcache_add(conn->client_cache, client_entry->nickname,
496 client_entry->id, client_entry, FALSE);
497 silc_free(client_id);
500 /* Notify application */
501 COMMAND_REPLY((ARGS, client_entry, nickname, username));
504 /* Received reply for IDENTIFY command. This maybe called several times
505 for one IDENTIFY command as server may reply with list of results.
506 This is totally silent and does not print anything on screen. */
508 SILC_CLIENT_CMD_REPLY_FUNC(identify)
510 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
511 SilcCommandStatus status;
514 SILC_LOG_DEBUG(("Start"));
516 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
517 SILC_GET16_MSB(status, tmp);
518 if (status != SILC_STATUS_OK &&
519 status != SILC_STATUS_LIST_START &&
520 status != SILC_STATUS_LIST_ITEM &&
521 status != SILC_STATUS_LIST_END) {
526 /* Save one IDENTIFY entry */
527 if (status == SILC_STATUS_OK)
528 silc_client_command_reply_identify_save(cmd, status);
531 if (status == SILC_STATUS_LIST_START ||
532 status == SILC_STATUS_LIST_ITEM ||
533 status == SILC_STATUS_LIST_END)
534 silc_client_command_reply_identify_save(cmd, status);
536 /* Pending callbacks are not executed if this was an list entry */
537 if (status != SILC_STATUS_OK &&
538 status != SILC_STATUS_LIST_END) {
539 silc_client_command_reply_free(cmd);
543 /* Execute any pending command callbacks */
544 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
547 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
548 silc_client_command_reply_free(cmd);
551 /* Received reply for command NICK. If everything went without errors
552 we just received our new Client ID. */
554 SILC_CLIENT_CMD_REPLY_FUNC(nick)
556 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
557 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
558 SilcCommandStatus status;
563 SILC_LOG_DEBUG(("Start"));
565 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
566 if (status != SILC_STATUS_OK) {
567 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
568 silc_client_command_status_message(status));
573 argc = silc_argument_get_arg_num(cmd->args);
574 if (argc < 2 || argc > 2) {
575 cmd->client->ops->say(cmd->client, conn,
576 "Cannot set nickname: bad reply to command");
581 /* Take received Client ID */
582 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
583 idp = silc_id_payload_parse_data(tmp, len);
588 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
590 /* Notify application */
591 COMMAND_REPLY((ARGS, conn->local_entry));
593 /* Execute any pending command callbacks */
594 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
597 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
598 silc_client_command_reply_free(cmd);
601 /* Received reply to the LIST command. */
603 SILC_CLIENT_CMD_REPLY_FUNC(list)
605 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
606 SilcCommandStatus status;
607 unsigned char *tmp, *name, *topic;
608 uint32 usercount = 0;
610 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
611 SILC_GET16_MSB(status, tmp);
612 if (status != SILC_STATUS_OK &&
613 status != SILC_STATUS_LIST_START &&
614 status != SILC_STATUS_LIST_ITEM &&
615 status != SILC_STATUS_LIST_END) {
620 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
621 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
622 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
624 SILC_GET32_MSB(usercount, tmp);
626 /* Notify application */
627 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
629 /* Pending callbacks are not executed if this was an list entry */
630 if (status != SILC_STATUS_OK &&
631 status != SILC_STATUS_LIST_END) {
632 silc_client_command_reply_free(cmd);
636 /* Execute any pending command callbacks */
637 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
640 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
641 silc_client_command_reply_free(cmd);
644 /* Received reply to topic command. */
646 SILC_CLIENT_CMD_REPLY_FUNC(topic)
648 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
649 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
650 SilcCommandStatus status;
651 SilcChannelEntry channel;
652 SilcChannelID *channel_id = NULL;
653 SilcIDCacheEntry id_cache = NULL;
658 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
659 if (status != SILC_STATUS_OK) {
660 cmd->client->ops->say(cmd->client, conn,
661 "%s", silc_client_command_status_message(status));
663 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
664 silc_client_command_reply_free(cmd);
668 argc = silc_argument_get_arg_num(cmd->args);
669 if (argc < 1 || argc > 3) {
674 /* Take Channel ID */
675 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
680 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
684 channel_id = silc_id_payload_parse_id(tmp, len);
688 /* Get the channel entry */
689 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
691 silc_free(channel_id);
696 channel = (SilcChannelEntry)id_cache->context;
698 /* Notify application */
699 COMMAND_REPLY((ARGS, channel, topic));
701 /* Execute any pending command callbacks */
702 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
705 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
706 silc_client_command_reply_free(cmd);
709 /* Received reply to invite command. */
711 SILC_CLIENT_CMD_REPLY_FUNC(invite)
713 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
714 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
715 SilcCommandStatus status;
716 SilcChannelEntry channel;
717 SilcChannelID *channel_id;
718 SilcIDCacheEntry id_cache;
722 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
723 SILC_GET16_MSB(status, tmp);
724 if (status != SILC_STATUS_OK) {
725 cmd->client->ops->say(cmd->client, conn,
726 "%s", silc_client_command_status_message(status));
728 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
729 silc_client_command_reply_free(cmd);
733 /* Take Channel ID */
734 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
738 channel_id = silc_id_payload_parse_id(tmp, len);
742 /* Get the channel entry */
743 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
745 silc_free(channel_id);
750 channel = (SilcChannelEntry)id_cache->context;
752 /* Get the invite list */
753 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
755 /* Notify application */
756 COMMAND_REPLY((ARGS, channel, tmp));
758 /* Execute any pending command callbacks */
759 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
762 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
763 silc_client_command_reply_free(cmd);
766 /* Received reply to the KILL command. */
768 SILC_CLIENT_CMD_REPLY_FUNC(kill)
770 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
771 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
772 SilcCommandStatus status;
775 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
776 SILC_GET16_MSB(status, tmp);
777 if (status != SILC_STATUS_OK) {
778 cmd->client->ops->say(cmd->client, conn,
779 "%s", silc_client_command_status_message(status));
784 /* Notify application */
785 COMMAND_REPLY((ARGS));
787 /* Execute any pending command callbacks */
788 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
791 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
792 silc_client_command_reply_free(cmd);
795 /* Received reply to INFO command. We receive the server ID and some
796 information about the server user requested. */
798 SILC_CLIENT_CMD_REPLY_FUNC(info)
800 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
801 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
802 SilcClient client = cmd->client;
803 SilcCommandStatus status;
806 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
807 SILC_GET16_MSB(status, tmp);
808 if (status != SILC_STATUS_OK) {
809 cmd->client->ops->say(cmd->client, conn,
810 "%s", silc_client_command_status_message(status));
812 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
813 silc_client_command_reply_free(cmd);
818 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
822 /* XXX save server id */
824 /* Get server name */
825 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
829 /* Get server info */
830 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
834 client->ops->say(cmd->client, conn, "Info: %s", tmp);
836 /* Notify application */
837 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
839 /* Execute any pending command callbacks */
840 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
843 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
844 silc_client_command_reply_free(cmd);
847 /* Received reply to PING command. The reply time is shown to user. */
849 SILC_CLIENT_CMD_REPLY_FUNC(ping)
851 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
852 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
853 SilcCommandStatus status;
856 time_t diff, curtime;
858 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
859 if (status != SILC_STATUS_OK) {
860 cmd->client->ops->say(cmd->client, conn,
861 "%s", silc_client_command_status_message(status));
866 curtime = time(NULL);
867 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
868 cmd->packet->src_id_type);
874 for (i = 0; i < conn->ping_count; i++) {
875 if (SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
876 diff = curtime - conn->ping[i].start_time;
877 cmd->client->ops->say(cmd->client, conn,
878 "Ping reply from %s: %d second%s",
879 conn->ping[i].dest_name, diff,
880 diff == 1 ? "" : "s");
882 conn->ping[i].start_time = 0;
883 silc_free(conn->ping[i].dest_id);
884 conn->ping[i].dest_id = NULL;
885 silc_free(conn->ping[i].dest_name);
886 conn->ping[i].dest_name = NULL;
893 /* Notify application */
894 COMMAND_REPLY((ARGS));
896 /* Execute any pending command callbacks */
897 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
900 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
901 silc_client_command_reply_free(cmd);
904 /* Received reply for JOIN command. */
906 SILC_CLIENT_CMD_REPLY_FUNC(join)
908 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
909 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
910 SilcCommandStatus status;
911 SilcIDPayload idp = NULL;
912 SilcChannelEntry channel;
913 SilcIDCacheEntry id_cache = NULL;
915 uint32 argc, mode, len, list_count;
916 char *topic, *tmp, *channel_name = NULL, *hmac;
917 SilcBuffer keyp = NULL, client_id_list, client_mode_list;
920 SILC_LOG_DEBUG(("Start"));
922 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
923 if (status != SILC_STATUS_OK) {
924 cmd->client->ops->say(cmd->client, conn,
925 "%s", silc_client_command_status_message(status));
930 argc = silc_argument_get_arg_num(cmd->args);
931 if (argc < 7 || argc > 14) {
932 cmd->client->ops->say(cmd->client, conn,
933 "Cannot join channel: Bad reply packet");
938 /* Get channel name */
939 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
941 cmd->client->ops->say(cmd->client, conn,
942 "Cannot join channel: Bad reply packet");
946 channel_name = strdup(tmp);
949 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
951 cmd->client->ops->say(cmd->client, conn,
952 "Cannot join channel: Bad reply packet");
954 silc_free(channel_name);
957 idp = silc_id_payload_parse_data(tmp, len);
960 silc_free(channel_name);
964 /* Get channel mode */
965 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
967 SILC_GET32_MSB(mode, tmp);
971 /* Get channel key */
972 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
974 keyp = silc_buffer_alloc(len);
975 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
976 silc_buffer_put(keyp, tmp, len);
980 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
982 /* Save received Channel ID. This actually creates the channel */
983 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
985 silc_id_payload_free(idp);
988 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
990 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
991 cmd->client->ops->say(cmd->client, conn,
992 "Cannot join channel: Unsupported HMAC `%s'",
995 silc_free(channel_name);
1000 /* Get the list count */
1001 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1004 SILC_GET32_MSB(list_count, tmp);
1006 /* Get Client ID list */
1007 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1011 client_id_list = silc_buffer_alloc(len);
1012 silc_buffer_pull_tail(client_id_list, len);
1013 silc_buffer_put(client_id_list, tmp, len);
1015 /* Get client mode list */
1016 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1020 client_mode_list = silc_buffer_alloc(len);
1021 silc_buffer_pull_tail(client_mode_list, len);
1022 silc_buffer_put(client_mode_list, tmp, len);
1024 /* Add clients we received in the reply to the channel */
1025 for (i = 0; i < list_count; i++) {
1028 SilcClientID *client_id;
1029 SilcClientEntry client_entry;
1032 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1034 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1039 SILC_GET32_MSB(mode, client_mode_list->data);
1041 /* Check if we have this client cached already. */
1042 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1045 silc_hash_client_id_compare, NULL,
1047 /* No, we don't have it, add entry for it. */
1048 client_entry = silc_calloc(1, sizeof(*client_entry));
1049 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1050 silc_idcache_add(conn->client_cache, NULL, client_entry->id,
1051 (void *)client_entry, FALSE);
1053 /* Yes, we have it already */
1054 client_entry = (SilcClientEntry)id_cache->context;
1057 /* Join the client to the channel */
1058 chu = silc_calloc(1, sizeof(*chu));
1059 chu->client = client_entry;
1061 silc_list_add(channel->clients, chu);
1062 silc_free(client_id);
1064 silc_buffer_pull(client_id_list, idp_len);
1065 silc_buffer_pull(client_mode_list, 4);
1067 silc_buffer_push(client_id_list, client_id_list->data -
1068 client_id_list->head);
1069 silc_buffer_push(client_mode_list, client_mode_list->data -
1070 client_mode_list->head);
1072 /* Save channel key */
1073 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1074 silc_client_save_channel_key(conn, keyp, channel);
1076 /* Client is now joined to the channel */
1077 channel->on_channel = TRUE;
1079 /* Notify application */
1080 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1081 keyp ? keyp->head : NULL, NULL,
1082 NULL, topic, hmac, list_count, client_id_list,
1085 /* Execute any pending command callbacks */
1086 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1089 silc_buffer_free(keyp);
1090 silc_buffer_free(client_id_list);
1091 silc_buffer_free(client_mode_list);
1094 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1095 silc_client_command_reply_free(cmd);
1098 /* Received reply for MOTD command */
1100 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1102 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1103 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1104 SilcCommandStatus status;
1107 char *motd = NULL, *cp, line[256];
1109 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1110 SILC_GET16_MSB(status, tmp);
1111 if (status != SILC_STATUS_OK) {
1112 cmd->client->ops->say(cmd->client, conn,
1113 "%s", silc_client_command_status_message(status));
1114 COMMAND_REPLY_ERROR;
1118 argc = silc_argument_get_arg_num(cmd->args);
1120 COMMAND_REPLY_ERROR;
1125 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1127 COMMAND_REPLY_ERROR;
1134 if (cp[i++] == '\n') {
1135 memset(line, 0, sizeof(line));
1136 strncat(line, cp, i - 1);
1142 cmd->client->ops->say(cmd->client, conn, "%s", line);
1151 /* Notify application */
1152 COMMAND_REPLY((ARGS, motd));
1154 /* Execute any pending command callbacks */
1155 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1158 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1159 silc_client_command_reply_free(cmd);
1162 /* Received reply tot he UMODE command. Save the current user mode */
1164 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1166 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1167 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1168 SilcCommandStatus status;
1172 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1173 SILC_GET16_MSB(status, tmp);
1174 if (status != SILC_STATUS_OK) {
1175 cmd->client->ops->say(cmd->client, conn,
1176 "%s", silc_client_command_status_message(status));
1177 COMMAND_REPLY_ERROR;
1181 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1183 COMMAND_REPLY_ERROR;
1187 SILC_GET32_MSB(mode, tmp);
1188 conn->local_entry->mode = mode;
1190 /* Notify application */
1191 COMMAND_REPLY((ARGS, mode));
1193 /* Execute any pending command callbacks */
1194 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1197 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1198 silc_client_command_reply_free(cmd);
1201 /* Received reply for CMODE command. */
1203 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1205 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1206 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1207 SilcCommandStatus status;
1210 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1211 if (status != SILC_STATUS_OK) {
1212 cmd->client->ops->say(cmd->client, conn,
1213 "%s", silc_client_command_status_message(status));
1214 COMMAND_REPLY_ERROR;
1218 /* Get channel mode */
1219 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1221 COMMAND_REPLY_ERROR;
1225 /* Notify application */
1226 COMMAND_REPLY((ARGS, tmp));
1228 /* Execute any pending command callbacks */
1229 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1232 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1233 silc_client_command_reply_free(cmd);
1236 /* Received reply for CUMODE command */
1238 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1240 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1241 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1242 SilcCommandStatus status;
1243 SilcIDCacheEntry id_cache = NULL;
1244 SilcClientID *client_id;
1245 unsigned char *tmp, *id;
1248 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1249 if (status != SILC_STATUS_OK) {
1250 cmd->client->ops->say(cmd->client, conn,
1251 "%s", silc_client_command_status_message(status));
1252 COMMAND_REPLY_ERROR;
1256 /* Get channel mode */
1257 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1259 COMMAND_REPLY_ERROR;
1264 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1266 COMMAND_REPLY_ERROR;
1269 client_id = silc_id_payload_parse_id(id, len);
1271 COMMAND_REPLY_ERROR;
1275 /* Get client entry */
1276 if (!silc_idcache_find_by_id_one_ext(conn->client_cache, (void *)client_id,
1278 silc_hash_client_id_compare, NULL,
1280 COMMAND_REPLY_ERROR;
1284 /* Notify application */
1285 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1286 silc_free(client_id);
1288 /* Execute any pending command callbacks */
1289 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1292 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1293 silc_client_command_reply_free(cmd);
1296 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1298 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1299 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1300 SilcCommandStatus status;
1303 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1304 SILC_GET16_MSB(status, tmp);
1305 if (status != SILC_STATUS_OK) {
1306 cmd->client->ops->say(cmd->client, conn,
1307 "%s", silc_client_command_status_message(status));
1308 COMMAND_REPLY_ERROR;
1312 /* Notify application */
1313 COMMAND_REPLY((ARGS));
1315 /* Execute any pending command callbacks */
1316 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1319 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1320 silc_client_command_reply_free(cmd);
1323 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1325 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1326 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1327 SilcCommandStatus status;
1330 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1331 SILC_GET16_MSB(status, tmp);
1332 if (status != SILC_STATUS_OK) {
1333 cmd->client->ops->say(cmd->client, conn,
1334 "%s", silc_client_command_status_message(status));
1335 COMMAND_REPLY_ERROR;
1339 /* Notify application */
1340 COMMAND_REPLY((ARGS));
1342 /* Execute any pending command callbacks */
1343 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1346 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1347 silc_client_command_reply_free(cmd);
1350 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1352 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1353 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1354 SilcCommandStatus status;
1357 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1358 SILC_GET16_MSB(status, tmp);
1359 if (status != SILC_STATUS_OK) {
1360 cmd->client->ops->say(cmd->client, conn,
1361 "%s", silc_client_command_status_message(status));
1362 COMMAND_REPLY_ERROR;
1366 /* Notify application */
1367 COMMAND_REPLY((ARGS));
1369 /* Execute any pending command callbacks */
1370 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1373 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1374 silc_client_command_reply_free(cmd);
1377 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1379 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1380 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1381 SilcCommandStatus status;
1384 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1385 SILC_GET16_MSB(status, tmp);
1386 if (status != SILC_STATUS_OK) {
1387 cmd->client->ops->say(cmd->client, conn,
1388 "%s", silc_client_command_status_message(status));
1389 COMMAND_REPLY_ERROR;
1393 /* Notify application */
1394 COMMAND_REPLY((ARGS));
1396 /* Execute any pending command callbacks */
1397 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1400 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1401 silc_client_command_reply_free(cmd);
1404 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1406 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1407 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1408 SilcCommandStatus status;
1409 SilcIDCacheEntry id_cache = NULL;
1410 SilcChannelEntry channel;
1411 SilcChannelID *channel_id;
1415 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1416 SILC_GET16_MSB(status, tmp);
1417 if (status != SILC_STATUS_OK) {
1418 cmd->client->ops->say(cmd->client, conn,
1419 "%s", silc_client_command_status_message(status));
1420 COMMAND_REPLY_ERROR;
1424 /* Take Channel ID */
1425 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1429 channel_id = silc_id_payload_parse_id(tmp, len);
1433 /* Get the channel entry */
1434 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1436 silc_free(channel_id);
1437 COMMAND_REPLY_ERROR;
1441 channel = (SilcChannelEntry)id_cache->context;
1443 /* Get the ban list */
1444 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1446 /* Notify application */
1447 COMMAND_REPLY((ARGS, channel, tmp));
1449 /* Execute any pending command callbacks */
1450 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1453 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1454 silc_client_command_reply_free(cmd);
1457 SILC_CLIENT_CMD_REPLY_FUNC(close)
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,
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_CLOSE);
1480 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1481 silc_client_command_reply_free(cmd);
1484 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
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,
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_SHUTDOWN);
1507 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1508 silc_client_command_reply_free(cmd);
1511 /* Reply to LEAVE command. */
1513 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1515 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1516 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1517 SilcCommandStatus status;
1520 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1521 SILC_GET16_MSB(status, tmp);
1522 if (status != SILC_STATUS_OK) {
1523 cmd->client->ops->say(cmd->client, conn,
1524 "%s", silc_client_command_status_message(status));
1525 COMMAND_REPLY_ERROR;
1529 /* Notify application */
1530 COMMAND_REPLY((ARGS));
1532 /* Execute any pending command callbacks */
1533 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1536 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1537 silc_client_command_reply_free(cmd);
1540 /* Reply to USERS command. Received list of client ID's and theirs modes
1541 on the channel we requested. */
1543 SILC_CLIENT_CMD_REPLY_FUNC(users)
1545 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1546 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1547 SilcCommandStatus status;
1548 SilcIDCacheEntry id_cache = NULL;
1549 SilcChannelEntry channel;
1550 SilcChannelUser chu;
1551 SilcChannelID *channel_id = NULL;
1552 SilcBuffer client_id_list;
1553 SilcBuffer client_mode_list;
1555 uint32 tmp_len, list_count;
1557 unsigned char **res_argv = NULL;
1558 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1560 SILC_LOG_DEBUG(("Start"));
1562 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1563 SILC_GET16_MSB(status, tmp);
1564 if (status != SILC_STATUS_OK) {
1565 cmd->client->ops->say(cmd->client, conn,
1566 "%s", silc_client_command_status_message(status));
1567 COMMAND_REPLY_ERROR;
1571 /* Get channel ID */
1572 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1575 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1579 /* Get the list count */
1580 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1583 SILC_GET32_MSB(list_count, tmp);
1585 /* Get Client ID list */
1586 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1590 client_id_list = silc_buffer_alloc(tmp_len);
1591 silc_buffer_pull_tail(client_id_list, tmp_len);
1592 silc_buffer_put(client_id_list, tmp, tmp_len);
1594 /* Get client mode list */
1595 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1599 client_mode_list = silc_buffer_alloc(tmp_len);
1600 silc_buffer_pull_tail(client_mode_list, tmp_len);
1601 silc_buffer_put(client_mode_list, tmp, tmp_len);
1603 /* Get channel entry */
1604 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1606 COMMAND_REPLY_ERROR;
1609 channel = (SilcChannelEntry)id_cache->context;
1611 /* Remove old client list from channel. */
1612 silc_list_start(channel->clients);
1613 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1614 silc_list_del(channel->clients, chu);
1618 /* Cache the received Client ID's and modes. This cache expires
1619 whenever server sends notify message to channel. It means two things;
1620 some user has joined or leaved the channel. XXX! */
1621 for (i = 0; i < list_count; i++) {
1624 SilcClientID *client_id;
1625 SilcClientEntry client;
1628 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1630 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1635 SILC_GET32_MSB(mode, client_mode_list->data);
1637 /* Check if we have this client cached already. */
1639 silc_idcache_find_by_id_one_ext(conn->client_cache,
1642 silc_hash_client_id_compare, NULL,
1645 if (!id_cache || !((SilcClientEntry)id_cache->context)->username) {
1646 /* No we don't have it (or it is incomplete in information), query
1647 it from the server. Assemble argument table that will be sent
1648 for the IDENTIFY command later. */
1649 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1651 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1653 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1655 res_argv[res_argc] = client_id_list->data;
1656 res_argv_lens[res_argc] = idp_len;
1657 res_argv_types[res_argc] = res_argc + 3;
1660 /* Found the client, join it to the channel */
1661 client = (SilcClientEntry)id_cache->context;
1662 chu = silc_calloc(1, sizeof(*chu));
1663 chu->client = client;
1665 silc_list_add(channel->clients, chu);
1667 silc_free(client_id);
1671 silc_buffer_pull(client_id_list, idp_len);
1672 silc_buffer_pull(client_mode_list, 4);
1675 /* Query the client information from server if the list included clients
1676 that we don't know about. */
1680 /* Send the IDENTIFY command to server */
1681 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1682 res_argc, res_argv, res_argv_lens,
1683 res_argv_types, ++conn->cmd_ident);
1684 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1685 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1688 /* Register pending command callback. After we've received the IDENTIFY
1689 command reply we will reprocess this command reply by re-calling this
1690 USERS command reply callback. */
1691 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1692 NULL, silc_client_command_reply_users, cmd);
1694 silc_buffer_free(res_cmd);
1696 silc_free(channel_id);
1698 silc_free(res_argv);
1699 silc_free(res_argv_lens);
1700 silc_free(res_argv_types);
1704 /* Notify application */
1705 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1707 /* Execute any pending command callbacks */
1708 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1710 silc_buffer_free(client_id_list);
1711 silc_buffer_free(client_mode_list);
1715 silc_free(channel_id);
1716 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1717 silc_client_command_reply_free(cmd);
1720 /* Received command reply to GETKEY command. WE've received the remote
1721 client's public key. */
1723 SILC_CLIENT_CMD_REPLY_FUNC(getkey)
1725 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1726 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1727 SilcCommandStatus status;
1728 SilcIDCacheEntry id_cache;
1729 SilcIDPayload idp = NULL;
1730 SilcClientID *client_id = NULL;
1731 SilcClientEntry client_entry;
1733 unsigned char *tmp, *pk;
1737 SilcPublicKey public_key = NULL;
1739 SILC_LOG_DEBUG(("Start"));
1741 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1742 SILC_GET16_MSB(status, tmp);
1743 if (status != SILC_STATUS_OK) {
1744 cmd->client->ops->say(cmd->client, conn,
1745 "%s", silc_client_command_status_message(status));
1746 COMMAND_REPLY_ERROR;
1750 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1753 idp = silc_id_payload_parse_data(tmp, len);
1757 /* Get the public key payload */
1758 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1762 /* Decode the public key */
1764 SILC_GET16_MSB(pk_len, tmp);
1765 SILC_GET16_MSB(type, tmp + 2);
1768 if (type != SILC_SKE_PK_TYPE_SILC)
1771 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1774 id_type = silc_id_payload_get_type(idp);
1775 if (id_type == SILC_ID_CLIENT) {
1776 client_id = silc_id_payload_get_id(idp);
1778 if (!silc_idcache_find_by_id_one_ext(conn->client_cache,
1781 silc_hash_client_id_compare, NULL,
1785 client_entry = (SilcClientEntry)id_cache->context;
1787 /* Notify application */
1788 COMMAND_REPLY((ARGS, id_type, client_entry, public_key));
1789 } else if (id_type == SILC_ID_SERVER) {
1790 /* XXX we don't have server entries at all */
1797 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1799 silc_id_payload_free(idp);
1801 silc_pkcs_public_key_free(public_key);
1802 silc_free(client_id);
1803 silc_client_command_reply_free(cmd);