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(restart, RESTART),
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),
70 /* Status message structure. Messages are defined below. */
72 SilcCommandStatus status;
74 } SilcCommandStatusMessage;
76 /* Status messages returned by the server */
77 #define STAT(x) SILC_STATUS_ERR_##x
78 const SilcCommandStatusMessage silc_command_status_messages[] = {
80 { STAT(NO_SUCH_NICK), "No such nickname" },
81 { STAT(NO_SUCH_CHANNEL), "No such channel" },
82 { STAT(NO_SUCH_SERVER), "No such server" },
83 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
84 { STAT(NO_RECIPIENT), "No recipient given" },
85 { STAT(UNKNOWN_COMMAND), "Unknown command" },
86 { STAT(WILDCARDS), "Unknown command" },
87 { STAT(NO_CLIENT_ID), "No Client ID given" },
88 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
89 { STAT(NO_SERVER_ID), "No Server ID given" },
90 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
91 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
92 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
93 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
94 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
95 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
96 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
97 { STAT(USER_ON_CHANNEL), "User already on the channel" },
98 { STAT(NOT_REGISTERED), "You have not registered" },
99 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
100 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
101 { STAT(PERM_DENIED), "Your host is not among the privileged" },
102 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
103 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
104 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
105 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
106 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
107 { STAT(UNKNOWN_MODE), "Unknown mode" },
108 { STAT(NOT_YOU), "Cannot change mode for other users" },
109 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
110 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
111 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
112 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
113 { STAT(BAD_NICKNAME), "Bad nickname" },
114 { STAT(BAD_CHANNEL), "Bad channel name" },
115 { STAT(AUTH_FAILED), "Authentication failed" },
116 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
121 /* Command reply operation that is called at the end of all command replys.
122 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
123 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
124 #define ARGS cmd->client, cmd->sock->user_data, \
125 cmd->payload, TRUE, silc_command_get(cmd->payload), status
127 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
128 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
129 cmd->sock->user_data, cmd->payload, FALSE, \
130 silc_command_get(cmd->payload), status)
132 /* Process received command reply. */
134 void silc_client_command_reply_process(SilcClient client,
135 SilcSocketConnection sock,
136 SilcPacketContext *packet)
138 SilcBuffer buffer = packet->buffer;
139 SilcClientCommandReply *cmd;
140 SilcClientCommandReplyContext ctx;
141 SilcCommandPayload payload;
143 unsigned short ident;
145 /* Get command reply payload from packet */
146 payload = silc_command_payload_parse(buffer);
148 /* Silently ignore bad reply packet */
149 SILC_LOG_DEBUG(("Bad command reply packet"));
153 /* Allocate command reply context. This must be free'd by the
154 command reply routine receiving it. */
155 ctx = silc_calloc(1, sizeof(*ctx));
156 ctx->client = client;
158 ctx->payload = payload;
159 ctx->args = silc_command_get_args(ctx->payload);
160 ctx->packet = packet;
161 ident = silc_command_get_ident(ctx->payload);
163 /* Check for pending commands and mark to be exeucted */
164 silc_client_command_pending_check(sock->user_data, ctx,
165 silc_command_get(ctx->payload), ident);
167 /* Execute command reply */
168 command = silc_command_get(ctx->payload);
169 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
170 if (cmd->cmd == command)
173 if (cmd == NULL || !cmd->cb) {
181 /* Returns status message string */
184 silc_client_command_status_message(SilcCommandStatus status)
188 for (i = 0; silc_command_status_messages[i].message; i++) {
189 if (silc_command_status_messages[i].status == status)
193 if (silc_command_status_messages[i].message == NULL)
196 return silc_command_status_messages[i].message;
199 /* Free command reply context and its internals. */
201 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
204 silc_command_free_payload(cmd->payload);
210 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
211 SilcCommandStatus status)
213 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
214 SilcClientID *client_id;
215 SilcIDCacheEntry id_cache = NULL;
216 SilcClientEntry client_entry = NULL;
218 unsigned char *id_data, *tmp;
219 char *nickname = NULL, *username = NULL;
220 char *realname = NULL;
221 unsigned int idle = 0;
223 argc = silc_argument_get_arg_num(cmd->args);
225 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
231 client_id = silc_id_payload_parse_id(id_data, len);
237 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
238 username = silc_argument_get_arg_type(cmd->args, 4, &len);
239 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
240 if (!nickname || !username || !realname) {
245 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
247 SILC_GET32_MSB(idle, tmp);
249 /* Check if we have this client cached already. */
250 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
251 SILC_ID_CLIENT, &id_cache)) {
252 SILC_LOG_DEBUG(("Adding new client entry"));
254 client_entry = silc_calloc(1, sizeof(*client_entry));
255 client_entry->id = client_id;
256 silc_parse_nickname(nickname, &client_entry->nickname,
257 &client_entry->server, &client_entry->num);
258 client_entry->username = strdup(username);
260 client_entry->realname = strdup(realname);
262 /* Add client to cache */
263 silc_idcache_add(conn->client_cache, client_entry->nickname,
264 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
266 client_entry = (SilcClientEntry)id_cache->context;
267 if (client_entry->nickname)
268 silc_free(client_entry->nickname);
269 if (client_entry->server)
270 silc_free(client_entry->server);
271 if (client_entry->username)
272 silc_free(client_entry->username);
273 if (client_entry->realname)
274 silc_free(client_entry->realname);
276 SILC_LOG_DEBUG(("Updating client entry"));
278 silc_parse_nickname(nickname, &client_entry->nickname,
279 &client_entry->server, &client_entry->num);
280 client_entry->username = strdup(username);
282 client_entry->realname = strdup(realname);
284 id_cache->data = client_entry->nickname;
285 silc_idcache_sort_by_data(conn->client_cache);
287 silc_free(client_id);
290 /* Notify application */
292 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
296 /* Received reply for WHOIS command. This maybe called several times
297 for one WHOIS command as server may reply with list of results. */
299 SILC_CLIENT_CMD_REPLY_FUNC(whois)
301 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
302 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
303 SilcCommandStatus status;
306 SILC_LOG_DEBUG(("Start"));
308 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
309 SILC_GET16_MSB(status, tmp);
310 if (status != SILC_STATUS_OK &&
311 status != SILC_STATUS_LIST_START &&
312 status != SILC_STATUS_LIST_ITEM &&
313 status != SILC_STATUS_LIST_END) {
314 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
315 /* Take nickname which may be provided */
316 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
318 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
319 silc_client_command_status_message(status));
321 cmd->client->ops->say(cmd->client, conn, "%s",
322 silc_client_command_status_message(status));
326 cmd->client->ops->say(cmd->client, conn,
327 "%s", silc_client_command_status_message(status));
333 /* Display one whois reply */
334 if (status == SILC_STATUS_OK)
335 silc_client_command_reply_whois_save(cmd, status);
338 if (status == SILC_STATUS_LIST_START ||
339 status == SILC_STATUS_LIST_ITEM ||
340 status == SILC_STATUS_LIST_END)
341 silc_client_command_reply_whois_save(cmd, status);
343 /* Pending callbacks are not executed if this was an list entry */
344 if (status != SILC_STATUS_OK &&
345 status != SILC_STATUS_LIST_END) {
346 silc_client_command_reply_free(cmd);
350 /* Execute any pending command callbacks */
351 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
354 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
355 silc_client_command_reply_free(cmd);
358 /* Received reply for WHOWAS command. */
360 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
366 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
367 SilcCommandStatus status)
369 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
370 SilcClientID *client_id;
371 SilcIDCacheEntry id_cache = NULL;
372 SilcClientEntry client_entry = NULL;
374 unsigned char *id_data;
375 char *nickname = NULL, *username = NULL;
377 argc = silc_argument_get_arg_num(cmd->args);
379 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
385 client_id = silc_id_payload_parse_id(id_data, len);
391 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
392 username = silc_argument_get_arg_type(cmd->args, 4, &len);
394 /* Check if we have this client cached already. */
395 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
396 SILC_ID_CLIENT, &id_cache)) {
397 SILC_LOG_DEBUG(("Adding new client entry"));
399 client_entry = silc_calloc(1, sizeof(*client_entry));
400 client_entry->id = client_id;
401 silc_parse_nickname(nickname, &client_entry->nickname,
402 &client_entry->server, &client_entry->num);
404 client_entry->username = strdup(username);
406 /* Add client to cache */
407 silc_idcache_add(conn->client_cache, client_entry->nickname,
408 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
410 client_entry = (SilcClientEntry)id_cache->context;
411 if (client_entry->nickname)
412 silc_free(client_entry->nickname);
413 if (client_entry->server)
414 silc_free(client_entry->server);
415 if (username && client_entry->username)
416 silc_free(client_entry->username);
418 SILC_LOG_DEBUG(("Updating client entry"));
420 silc_parse_nickname(nickname, &client_entry->nickname,
421 &client_entry->server, &client_entry->num);
424 client_entry->username = strdup(username);
426 id_cache->data = client_entry->nickname;
427 silc_idcache_sort_by_data(conn->client_cache);
429 silc_free(client_id);
432 /* Notify application */
433 COMMAND_REPLY((ARGS, client_entry, nickname, username));
436 /* Received reply for IDENTIFY command. This maybe called several times
437 for one IDENTIFY command as server may reply with list of results.
438 This is totally silent and does not print anything on screen. */
440 SILC_CLIENT_CMD_REPLY_FUNC(identify)
442 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
443 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
444 SilcCommandStatus status;
447 SILC_LOG_DEBUG(("Start"));
449 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
450 SILC_GET16_MSB(status, tmp);
451 if (status != SILC_STATUS_OK &&
452 status != SILC_STATUS_LIST_START &&
453 status != SILC_STATUS_LIST_ITEM &&
454 status != SILC_STATUS_LIST_END) {
455 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
456 /* Take nickname which may be provided */
457 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
459 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
460 silc_client_command_status_message(status));
462 cmd->client->ops->say(cmd->client, conn, "%s",
463 silc_client_command_status_message(status));
467 cmd->client->ops->say(cmd->client, conn,
468 "%s", silc_client_command_status_message(status));
474 /* Save one IDENTIFY entry */
475 if (status == SILC_STATUS_OK)
476 silc_client_command_reply_identify_save(cmd, status);
479 if (status == SILC_STATUS_LIST_START ||
480 status == SILC_STATUS_LIST_ITEM ||
481 status == SILC_STATUS_LIST_END)
482 silc_client_command_reply_identify_save(cmd, status);
484 /* Pending callbacks are not executed if this was an list entry */
485 if (status != SILC_STATUS_OK &&
486 status != SILC_STATUS_LIST_END) {
487 silc_client_command_reply_free(cmd);
491 /* Execute any pending command callbacks */
492 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
495 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
496 silc_client_command_reply_free(cmd);
499 /* Received reply for command NICK. If everything went without errors
500 we just received our new Client ID. */
502 SILC_CLIENT_CMD_REPLY_FUNC(nick)
504 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
505 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
506 SilcCommandStatus status;
509 unsigned int argc, len;
511 SILC_LOG_DEBUG(("Start"));
513 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
514 if (status != SILC_STATUS_OK) {
515 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
516 silc_client_command_status_message(status));
521 argc = silc_argument_get_arg_num(cmd->args);
522 if (argc < 2 || argc > 2) {
523 cmd->client->ops->say(cmd->client, conn,
524 "Cannot set nickname: bad reply to command");
529 /* Take received Client ID */
530 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
531 idp = silc_id_payload_parse_data(tmp, len);
536 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
538 /* Notify application */
539 COMMAND_REPLY((ARGS, conn->local_entry));
541 /* Execute any pending command callbacks */
542 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
545 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
546 silc_client_command_reply_free(cmd);
549 SILC_CLIENT_CMD_REPLY_FUNC(list)
553 /* Received reply to topic command. */
555 SILC_CLIENT_CMD_REPLY_FUNC(topic)
557 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
558 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
559 SilcCommandStatus status;
560 SilcChannelEntry channel;
561 SilcChannelID *channel_id = NULL;
562 SilcIDCacheEntry id_cache = NULL;
565 unsigned int argc, len;
567 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
568 if (status != SILC_STATUS_OK) {
569 cmd->client->ops->say(cmd->client, conn,
570 "%s", silc_client_command_status_message(status));
572 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
573 silc_client_command_reply_free(cmd);
577 argc = silc_argument_get_arg_num(cmd->args);
578 if (argc < 1 || argc > 3) {
583 /* Take Channel ID */
584 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
589 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
593 channel_id = silc_id_payload_parse_id(tmp, len);
597 /* Get the channel name */
598 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
599 SILC_ID_CHANNEL, &id_cache)) {
600 silc_free(channel_id);
605 channel = (SilcChannelEntry)id_cache->context;
607 cmd->client->ops->say(cmd->client, conn,
608 "Topic on channel %s: %s", channel->channel_name,
611 /* Notify application */
612 COMMAND_REPLY((ARGS, channel, topic));
614 /* Execute any pending command callbacks */
615 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
618 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
619 silc_client_command_reply_free(cmd);
622 /* Received reply to invite command. */
624 SILC_CLIENT_CMD_REPLY_FUNC(invite)
626 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
627 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
628 SilcCommandStatus status;
631 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
632 SILC_GET16_MSB(status, tmp);
633 if (status != SILC_STATUS_OK) {
634 cmd->client->ops->say(cmd->client, conn,
635 "%s", silc_client_command_status_message(status));
637 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
638 silc_client_command_reply_free(cmd);
642 /* Notify application */
643 COMMAND_REPLY((ARGS));
645 /* Execute any pending command callbacks */
646 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
648 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
649 silc_client_command_reply_free(cmd);
652 SILC_CLIENT_CMD_REPLY_FUNC(kill)
656 /* Received reply to INFO command. We receive the server ID and some
657 information about the server user requested. */
659 SILC_CLIENT_CMD_REPLY_FUNC(info)
661 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
662 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
663 SilcClient client = cmd->client;
664 SilcCommandStatus status;
667 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
668 SILC_GET16_MSB(status, tmp);
669 if (status != SILC_STATUS_OK) {
670 cmd->client->ops->say(cmd->client, conn,
671 "%s", silc_client_command_status_message(status));
673 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
674 silc_client_command_reply_free(cmd);
679 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
683 /* XXX save server id */
685 /* Get server info */
686 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
690 client->ops->say(cmd->client, conn, "Info: %s", tmp);
692 /* Notify application */
693 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
695 /* Execute any pending command callbacks */
696 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
699 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
700 silc_client_command_reply_free(cmd);
703 /* Received reply to PING command. The reply time is shown to user. */
705 SILC_CLIENT_CMD_REPLY_FUNC(ping)
707 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
708 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
709 SilcCommandStatus status;
712 time_t diff, curtime;
714 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
715 if (status != SILC_STATUS_OK) {
716 cmd->client->ops->say(cmd->client, conn,
717 "%s", silc_client_command_status_message(status));
722 curtime = time(NULL);
723 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
724 cmd->packet->src_id_type);
730 for (i = 0; i < conn->ping_count; i++) {
731 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
732 diff = curtime - conn->ping[i].start_time;
733 cmd->client->ops->say(cmd->client, conn,
734 "Ping reply from %s: %d second%s",
735 conn->ping[i].dest_name, diff,
736 diff == 1 ? "" : "s");
738 conn->ping[i].start_time = 0;
739 silc_free(conn->ping[i].dest_id);
740 conn->ping[i].dest_id = NULL;
741 silc_free(conn->ping[i].dest_name);
742 conn->ping[i].dest_name = NULL;
749 /* Notify application */
750 COMMAND_REPLY((ARGS));
752 /* Execute any pending command callbacks */
753 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
756 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
757 silc_client_command_reply_free(cmd);
760 /* Received reply for JOIN command. */
762 SILC_CLIENT_CMD_REPLY_FUNC(join)
764 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
765 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
766 SilcCommandStatus status;
767 SilcIDPayload idp = NULL;
768 SilcChannelEntry channel;
769 SilcIDCacheEntry id_cache = NULL;
771 unsigned int argc, mode, len, list_count;
772 char *topic, *tmp, *channel_name = NULL, *hmac;
773 SilcBuffer keyp, client_id_list, client_mode_list;
776 SILC_LOG_DEBUG(("Start"));
778 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
779 if (status != SILC_STATUS_OK) {
780 cmd->client->ops->say(cmd->client, conn,
781 "%s", silc_client_command_status_message(status));
786 argc = silc_argument_get_arg_num(cmd->args);
787 if (argc < 7 || argc > 14) {
788 cmd->client->ops->say(cmd->client, conn,
789 "Cannot join channel: Bad reply packet");
794 /* Get channel name */
795 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
797 cmd->client->ops->say(cmd->client, conn,
798 "Cannot join channel: Bad reply packet");
802 channel_name = strdup(tmp);
805 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
807 cmd->client->ops->say(cmd->client, conn,
808 "Cannot join channel: Bad reply packet");
810 silc_free(channel_name);
813 idp = silc_id_payload_parse_data(tmp, len);
816 silc_free(channel_name);
820 /* Get channel mode */
821 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
823 SILC_GET32_MSB(mode, tmp);
827 /* Get channel key */
828 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
830 silc_id_payload_free(idp);
831 silc_free(channel_name);
834 keyp = silc_buffer_alloc(len);
835 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
836 silc_buffer_put(keyp, tmp, len);
839 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
841 /* Save received Channel ID. This actually creates the channel */
842 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
844 silc_id_payload_free(idp);
847 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
849 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
850 cmd->client->ops->say(cmd->client, conn,
851 "Cannot join channel: Unsupported HMAC `%s'",
854 silc_free(channel_name);
859 /* Get the list count */
860 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
863 SILC_GET32_MSB(list_count, tmp);
865 /* Get Client ID list */
866 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
870 client_id_list = silc_buffer_alloc(len);
871 silc_buffer_pull_tail(client_id_list, len);
872 silc_buffer_put(client_id_list, tmp, len);
874 /* Get client mode list */
875 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
879 client_mode_list = silc_buffer_alloc(len);
880 silc_buffer_pull_tail(client_mode_list, len);
881 silc_buffer_put(client_mode_list, tmp, len);
883 /* Add clients we received in the reply to the channel */
884 for (i = 0; i < list_count; i++) {
885 unsigned short idp_len;
887 SilcClientID *client_id;
888 SilcClientEntry client_entry;
891 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
893 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
898 SILC_GET32_MSB(mode, client_mode_list->data);
900 /* Check if we have this client cached already. */
901 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
902 SILC_ID_CLIENT, &id_cache)) {
903 /* No, we don't have it, add entry for it. */
904 client_entry = silc_calloc(1, sizeof(*client_entry));
905 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
906 silc_idcache_add(conn->client_cache, NULL, SILC_ID_CLIENT,
907 client_entry->id, (void *)client_entry, FALSE);
909 /* Yes, we have it already */
910 client_entry = (SilcClientEntry)id_cache->context;
913 /* Join the client to the channel */
914 chu = silc_calloc(1, sizeof(*chu));
915 chu->client = client_entry;
917 silc_list_add(channel->clients, chu);
918 silc_free(client_id);
920 silc_buffer_pull(client_id_list, idp_len);
921 silc_buffer_pull(client_mode_list, 4);
923 silc_buffer_push(client_id_list, client_id_list->data -
924 client_id_list->head);
925 silc_buffer_push(client_mode_list, client_mode_list->data -
926 client_mode_list->head);
928 /* Save channel key */
929 silc_client_save_channel_key(conn, keyp, channel);
931 /* Notify application */
932 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, keyp->head, NULL,
933 NULL, topic, hmac, list_count, client_id_list,
936 /* Execute any pending command callbacks */
937 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
939 silc_buffer_free(keyp);
940 silc_buffer_free(client_id_list);
941 silc_buffer_free(client_mode_list);
944 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
945 silc_client_command_reply_free(cmd);
948 /* Received reply for MOTD command */
950 SILC_CLIENT_CMD_REPLY_FUNC(motd)
952 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
953 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
954 SilcCommandStatus status;
955 unsigned int argc, i;
957 char *motd = NULL, *cp, line[256];
959 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
960 SILC_GET16_MSB(status, tmp);
961 if (status != SILC_STATUS_OK) {
962 cmd->client->ops->say(cmd->client, conn,
963 "%s", silc_client_command_status_message(status));
968 argc = silc_argument_get_arg_num(cmd->args);
975 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
984 if (cp[i++] == '\n') {
985 memset(line, 0, sizeof(line));
986 strncat(line, cp, i - 1);
992 cmd->client->ops->say(cmd->client, conn, "%s", line);
1001 /* Notify application */
1002 COMMAND_REPLY((ARGS, motd));
1004 /* Execute any pending command callbacks */
1005 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1008 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1009 silc_client_command_reply_free(cmd);
1012 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1016 /* Received reply for CMODE command. */
1018 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1020 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1021 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1022 SilcCommandStatus status;
1025 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1026 if (status != SILC_STATUS_OK) {
1027 cmd->client->ops->say(cmd->client, conn,
1028 "%s", silc_client_command_status_message(status));
1029 COMMAND_REPLY_ERROR;
1033 /* Get channel mode */
1034 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1036 COMMAND_REPLY_ERROR;
1040 /* Notify application */
1041 COMMAND_REPLY((ARGS, tmp));
1043 /* Execute any pending command callbacks */
1044 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1047 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1048 silc_client_command_reply_free(cmd);
1051 /* Received reply for CUMODE command */
1053 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1055 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1056 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1057 SilcCommandStatus status;
1058 SilcIDCacheEntry id_cache = NULL;
1059 SilcClientID *client_id;
1060 unsigned char *tmp, *id;
1063 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1064 if (status != SILC_STATUS_OK) {
1065 cmd->client->ops->say(cmd->client, conn,
1066 "%s", silc_client_command_status_message(status));
1067 COMMAND_REPLY_ERROR;
1071 /* Get channel mode */
1072 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1074 COMMAND_REPLY_ERROR;
1079 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1081 COMMAND_REPLY_ERROR;
1084 client_id = silc_id_payload_parse_id(id, len);
1086 COMMAND_REPLY_ERROR;
1090 /* Get client entry */
1091 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1092 SILC_ID_CLIENT, &id_cache)) {
1093 COMMAND_REPLY_ERROR;
1097 /* Notify application */
1098 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1099 silc_free(client_id);
1101 /* Execute any pending command callbacks */
1102 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1105 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1106 silc_client_command_reply_free(cmd);
1109 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1111 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1112 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1113 SilcCommandStatus status;
1116 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1117 SILC_GET16_MSB(status, tmp);
1118 if (status != SILC_STATUS_OK) {
1119 cmd->client->ops->say(cmd->client, conn,
1120 "%s", silc_client_command_status_message(status));
1121 COMMAND_REPLY_ERROR;
1125 /* Notify application */
1126 COMMAND_REPLY((ARGS));
1128 /* Execute any pending command callbacks */
1129 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1132 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1133 silc_client_command_reply_free(cmd);
1136 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1140 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1144 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1146 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1147 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1148 SilcCommandStatus status;
1151 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1152 SILC_GET16_MSB(status, tmp);
1153 if (status != SILC_STATUS_OK) {
1154 cmd->client->ops->say(cmd->client, conn,
1155 "%s", silc_client_command_status_message(status));
1156 COMMAND_REPLY_ERROR;
1160 /* Notify application */
1161 COMMAND_REPLY((ARGS));
1163 /* Execute any pending command callbacks */
1164 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1167 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1168 silc_client_command_reply_free(cmd);
1171 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1173 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1174 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1175 SilcCommandStatus status;
1178 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1179 SILC_GET16_MSB(status, tmp);
1180 if (status != SILC_STATUS_OK) {
1181 cmd->client->ops->say(cmd->client, conn,
1182 "%s", silc_client_command_status_message(status));
1183 COMMAND_REPLY_ERROR;
1187 /* Notify application */
1188 COMMAND_REPLY((ARGS));
1190 /* Execute any pending command callbacks */
1191 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1194 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1195 silc_client_command_reply_free(cmd);
1198 SILC_CLIENT_CMD_REPLY_FUNC(close)
1200 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1201 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1202 SilcCommandStatus status;
1205 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1206 SILC_GET16_MSB(status, tmp);
1207 if (status != SILC_STATUS_OK) {
1208 cmd->client->ops->say(cmd->client, conn,
1209 "%s", silc_client_command_status_message(status));
1210 COMMAND_REPLY_ERROR;
1214 /* Notify application */
1215 COMMAND_REPLY((ARGS));
1217 /* Execute any pending command callbacks */
1218 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1221 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1222 silc_client_command_reply_free(cmd);
1225 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1227 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1228 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1229 SilcCommandStatus status;
1232 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1233 SILC_GET16_MSB(status, tmp);
1234 if (status != SILC_STATUS_OK) {
1235 cmd->client->ops->say(cmd->client, conn,
1236 "%s", silc_client_command_status_message(status));
1237 COMMAND_REPLY_ERROR;
1241 /* Notify application */
1242 COMMAND_REPLY((ARGS));
1244 /* Execute any pending command callbacks */
1245 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1248 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1249 silc_client_command_reply_free(cmd);
1252 /* Reply to LEAVE command. */
1254 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1256 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1257 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1258 SilcCommandStatus status;
1261 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1262 SILC_GET16_MSB(status, tmp);
1263 if (status != SILC_STATUS_OK) {
1264 cmd->client->ops->say(cmd->client, conn,
1265 "%s", silc_client_command_status_message(status));
1266 COMMAND_REPLY_ERROR;
1270 /* Notify application */
1271 COMMAND_REPLY((ARGS));
1273 /* Execute any pending command callbacks */
1274 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1277 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1278 silc_client_command_reply_free(cmd);
1281 /* Reply to USERS command. Received list of client ID's and theirs modes
1282 on the channel we requested. */
1284 SILC_CLIENT_CMD_REPLY_FUNC(users)
1286 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1287 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1288 SilcCommandStatus status;
1289 SilcIDCacheEntry id_cache = NULL;
1290 SilcChannelEntry channel;
1291 SilcChannelUser chu;
1292 SilcChannelID *channel_id = NULL;
1293 SilcBuffer client_id_list;
1294 SilcBuffer client_mode_list;
1296 unsigned int tmp_len, list_count;
1298 unsigned char **res_argv = NULL;
1299 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1301 SILC_LOG_DEBUG(("Start"));
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 /* Get channel ID */
1313 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1316 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1320 /* Get the list count */
1321 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1324 SILC_GET32_MSB(list_count, tmp);
1326 /* Get Client ID list */
1327 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1331 client_id_list = silc_buffer_alloc(tmp_len);
1332 silc_buffer_pull_tail(client_id_list, tmp_len);
1333 silc_buffer_put(client_id_list, tmp, tmp_len);
1335 /* Get client mode list */
1336 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1340 client_mode_list = silc_buffer_alloc(tmp_len);
1341 silc_buffer_pull_tail(client_mode_list, tmp_len);
1342 silc_buffer_put(client_mode_list, tmp, tmp_len);
1344 /* Get channel entry */
1345 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1346 SILC_ID_CHANNEL, &id_cache)) {
1347 COMMAND_REPLY_ERROR;
1350 channel = (SilcChannelEntry)id_cache->context;
1352 /* Remove old client list from channel. */
1353 silc_list_start(channel->clients);
1354 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1355 silc_list_del(channel->clients, chu);
1359 /* Cache the received Client ID's and modes. This cache expires
1360 whenever server sends notify message to channel. It means two things;
1361 some user has joined or leaved the channel. XXX! */
1362 for (i = 0; i < list_count; i++) {
1363 unsigned short idp_len;
1365 SilcClientID *client_id;
1366 SilcClientEntry client;
1369 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1371 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1376 SILC_GET32_MSB(mode, client_mode_list->data);
1378 /* Check if we have this client cached already. */
1379 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1380 SILC_ID_CLIENT, &id_cache)) {
1381 /* No we don't have it, query it from the server. Assemble argument
1382 table that will be sent fr the IDENTIFY command later. */
1383 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1385 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1387 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1389 res_argv[res_argc] = client_id_list->data;
1390 res_argv_lens[res_argc] = idp_len;
1391 res_argv_types[res_argc] = res_argc + 3;
1394 /* Found the client, join it to the channel */
1395 client = (SilcClientEntry)id_cache->context;
1396 chu = silc_calloc(1, sizeof(*chu));
1397 chu->client = client;
1399 silc_list_add(channel->clients, chu);
1401 silc_free(client_id);
1405 silc_buffer_pull(client_id_list, idp_len);
1406 silc_buffer_pull(client_mode_list, 4);
1409 /* Query the client information from server if the list included clients
1410 that we don't know about. */
1414 /* Send the IDENTIFY command to server */
1415 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1416 res_argc, res_argv, res_argv_lens,
1417 res_argv_types, ++conn->cmd_ident);
1418 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1419 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1422 /* Register pending command callback. After we've received the IDENTIFY
1423 command reply we will reprocess this command reply by re-calling this
1424 USERS command reply callback. */
1425 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1426 NULL, silc_client_command_reply_users, cmd);
1428 silc_buffer_free(res_cmd);
1430 silc_free(channel_id);
1432 silc_free(res_argv);
1433 silc_free(res_argv_lens);
1434 silc_free(res_argv_types);
1438 /* Notify application */
1439 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1441 /* Execute any pending command callbacks */
1442 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1444 silc_buffer_free(client_id_list);
1445 silc_buffer_free(client_mode_list);
1449 silc_free(channel_id);
1450 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1451 silc_client_command_reply_free(cmd);