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 */
291 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
295 /* Received reply for WHOIS command. This maybe called several times
296 for one WHOIS command as server may reply with list of results. */
298 SILC_CLIENT_CMD_REPLY_FUNC(whois)
300 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
301 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
302 SilcCommandStatus status;
305 SILC_LOG_DEBUG(("Start"));
307 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
308 SILC_GET16_MSB(status, tmp);
309 if (status != SILC_STATUS_OK &&
310 status != SILC_STATUS_LIST_START &&
311 status != SILC_STATUS_LIST_ITEM &&
312 status != SILC_STATUS_LIST_END) {
313 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
314 /* Take nickname which may be provided */
315 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
317 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
318 silc_client_command_status_message(status));
320 cmd->client->ops->say(cmd->client, conn, "%s",
321 silc_client_command_status_message(status));
325 cmd->client->ops->say(cmd->client, conn,
326 "%s", silc_client_command_status_message(status));
332 /* Display one whois reply */
333 if (status == SILC_STATUS_OK)
334 silc_client_command_reply_whois_save(cmd, status);
337 if (status == SILC_STATUS_LIST_START ||
338 status == SILC_STATUS_LIST_ITEM ||
339 status == SILC_STATUS_LIST_END)
340 silc_client_command_reply_whois_save(cmd, status);
342 /* Pending callbacks are not executed if this was an list entry */
343 if (status != SILC_STATUS_OK &&
344 status != SILC_STATUS_LIST_END) {
345 silc_client_command_reply_free(cmd);
349 /* Execute any pending command callbacks */
350 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
353 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
354 silc_client_command_reply_free(cmd);
357 /* Received reply for WHOWAS command. */
359 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
365 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
366 SilcCommandStatus status)
368 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
369 SilcClientID *client_id;
370 SilcIDCacheEntry id_cache = NULL;
371 SilcClientEntry client_entry = NULL;
373 unsigned char *id_data;
374 char *nickname = NULL, *username = NULL;
376 argc = silc_argument_get_arg_num(cmd->args);
378 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
384 client_id = silc_id_payload_parse_id(id_data, len);
390 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
391 username = silc_argument_get_arg_type(cmd->args, 4, &len);
393 /* Check if we have this client cached already. */
394 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
395 SILC_ID_CLIENT, &id_cache)) {
396 SILC_LOG_DEBUG(("Adding new client entry"));
398 client_entry = silc_calloc(1, sizeof(*client_entry));
399 client_entry->id = client_id;
400 silc_parse_nickname(nickname, &client_entry->nickname,
401 &client_entry->server, &client_entry->num);
403 client_entry->username = strdup(username);
405 /* Add client to cache */
406 silc_idcache_add(conn->client_cache, client_entry->nickname,
407 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
409 client_entry = (SilcClientEntry)id_cache->context;
410 if (client_entry->nickname)
411 silc_free(client_entry->nickname);
412 if (client_entry->server)
413 silc_free(client_entry->server);
414 if (username && client_entry->username)
415 silc_free(client_entry->username);
417 SILC_LOG_DEBUG(("Updating client entry"));
419 silc_parse_nickname(nickname, &client_entry->nickname,
420 &client_entry->server, &client_entry->num);
423 client_entry->username = strdup(username);
425 id_cache->data = client_entry->nickname;
426 silc_idcache_sort_by_data(conn->client_cache);
428 silc_free(client_id);
431 /* Notify application */
432 COMMAND_REPLY((ARGS, client_entry, nickname, username));
435 /* Received reply for IDENTIFY command. This maybe called several times
436 for one IDENTIFY command as server may reply with list of results.
437 This is totally silent and does not print anything on screen. */
439 SILC_CLIENT_CMD_REPLY_FUNC(identify)
441 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
442 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
443 SilcCommandStatus status;
446 SILC_LOG_DEBUG(("Start"));
448 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
449 SILC_GET16_MSB(status, tmp);
450 if (status != SILC_STATUS_OK &&
451 status != SILC_STATUS_LIST_START &&
452 status != SILC_STATUS_LIST_ITEM &&
453 status != SILC_STATUS_LIST_END) {
454 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
455 /* Take nickname which may be provided */
456 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
458 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
459 silc_client_command_status_message(status));
461 cmd->client->ops->say(cmd->client, conn, "%s",
462 silc_client_command_status_message(status));
466 cmd->client->ops->say(cmd->client, conn,
467 "%s", silc_client_command_status_message(status));
473 /* Save one IDENTIFY entry */
474 if (status == SILC_STATUS_OK)
475 silc_client_command_reply_identify_save(cmd, status);
478 if (status == SILC_STATUS_LIST_START ||
479 status == SILC_STATUS_LIST_ITEM ||
480 status == SILC_STATUS_LIST_END)
481 silc_client_command_reply_identify_save(cmd, status);
483 /* Pending callbacks are not executed if this was an list entry */
484 if (status != SILC_STATUS_OK &&
485 status != SILC_STATUS_LIST_END) {
486 silc_client_command_reply_free(cmd);
490 /* Execute any pending command callbacks */
491 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
494 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
495 silc_client_command_reply_free(cmd);
498 /* Received reply for command NICK. If everything went without errors
499 we just received our new Client ID. */
501 SILC_CLIENT_CMD_REPLY_FUNC(nick)
503 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
504 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
505 SilcCommandStatus status;
508 unsigned int argc, len;
510 SILC_LOG_DEBUG(("Start"));
512 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
513 if (status != SILC_STATUS_OK) {
514 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
515 silc_client_command_status_message(status));
520 argc = silc_argument_get_arg_num(cmd->args);
521 if (argc < 2 || argc > 2) {
522 cmd->client->ops->say(cmd->client, conn,
523 "Cannot set nickname: bad reply to command");
528 /* Take received Client ID */
529 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
530 idp = silc_id_payload_parse_data(tmp, len);
535 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
537 /* Notify application */
538 COMMAND_REPLY((ARGS, conn->local_entry));
540 /* Execute any pending command callbacks */
541 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
544 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
545 silc_client_command_reply_free(cmd);
548 SILC_CLIENT_CMD_REPLY_FUNC(list)
552 /* Received reply to topic command. */
554 SILC_CLIENT_CMD_REPLY_FUNC(topic)
556 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
557 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
558 SilcCommandStatus status;
559 SilcChannelEntry channel;
560 SilcChannelID *channel_id = NULL;
561 SilcIDCacheEntry id_cache = NULL;
564 unsigned int argc, len;
566 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
567 if (status != SILC_STATUS_OK) {
568 cmd->client->ops->say(cmd->client, conn,
569 "%s", silc_client_command_status_message(status));
571 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
572 silc_client_command_reply_free(cmd);
576 argc = silc_argument_get_arg_num(cmd->args);
577 if (argc < 1 || argc > 3) {
582 /* Take Channel ID */
583 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
588 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
592 channel_id = silc_id_payload_parse_id(tmp, len);
596 /* Get the channel name */
597 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
598 SILC_ID_CHANNEL, &id_cache)) {
599 silc_free(channel_id);
604 channel = (SilcChannelEntry)id_cache->context;
606 cmd->client->ops->say(cmd->client, conn,
607 "Topic on channel %s: %s", channel->channel_name,
610 /* Notify application */
611 COMMAND_REPLY((ARGS, channel, topic));
613 /* Execute any pending command callbacks */
614 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
617 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
618 silc_client_command_reply_free(cmd);
621 /* Received reply to invite command. */
623 SILC_CLIENT_CMD_REPLY_FUNC(invite)
625 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
626 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
627 SilcCommandStatus status;
630 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
631 SILC_GET16_MSB(status, tmp);
632 if (status != SILC_STATUS_OK) {
633 cmd->client->ops->say(cmd->client, conn,
634 "%s", silc_client_command_status_message(status));
636 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
637 silc_client_command_reply_free(cmd);
641 /* Notify application */
642 COMMAND_REPLY((ARGS));
644 /* Execute any pending command callbacks */
645 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
647 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
648 silc_client_command_reply_free(cmd);
651 SILC_CLIENT_CMD_REPLY_FUNC(kill)
655 /* Received reply to INFO command. We receive the server ID and some
656 information about the server user requested. */
658 SILC_CLIENT_CMD_REPLY_FUNC(info)
660 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
661 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
662 SilcClient client = cmd->client;
663 SilcCommandStatus status;
666 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
667 SILC_GET16_MSB(status, tmp);
668 if (status != SILC_STATUS_OK) {
669 cmd->client->ops->say(cmd->client, conn,
670 "%s", silc_client_command_status_message(status));
672 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
673 silc_client_command_reply_free(cmd);
678 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
682 /* XXX save server id */
684 /* Get server info */
685 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
689 client->ops->say(cmd->client, conn, "Info: %s", tmp);
691 /* Notify application */
692 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
694 /* Execute any pending command callbacks */
695 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
698 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
699 silc_client_command_reply_free(cmd);
702 /* Received reply to PING command. The reply time is shown to user. */
704 SILC_CLIENT_CMD_REPLY_FUNC(ping)
706 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
707 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
708 SilcCommandStatus status;
711 time_t diff, curtime;
713 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
714 if (status != SILC_STATUS_OK) {
715 cmd->client->ops->say(cmd->client, conn,
716 "%s", silc_client_command_status_message(status));
721 curtime = time(NULL);
722 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
723 cmd->packet->src_id_type);
729 for (i = 0; i < conn->ping_count; i++) {
730 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
731 diff = curtime - conn->ping[i].start_time;
732 cmd->client->ops->say(cmd->client, conn,
733 "Ping reply from %s: %d second%s",
734 conn->ping[i].dest_name, diff,
735 diff == 1 ? "" : "s");
737 conn->ping[i].start_time = 0;
738 silc_free(conn->ping[i].dest_id);
739 conn->ping[i].dest_id = NULL;
740 silc_free(conn->ping[i].dest_name);
741 conn->ping[i].dest_name = NULL;
748 /* Notify application */
749 COMMAND_REPLY((ARGS));
751 /* Execute any pending command callbacks */
752 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
755 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
756 silc_client_command_reply_free(cmd);
759 /* Received reply for JOIN command. */
761 SILC_CLIENT_CMD_REPLY_FUNC(join)
763 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
764 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
765 SilcCommandStatus status;
766 SilcIDPayload idp = NULL;
767 SilcChannelEntry channel;
768 SilcIDCacheEntry id_cache = NULL;
770 unsigned int argc, mode, len, list_count;
771 char *topic, *tmp, *channel_name = NULL, *hmac;
772 SilcBuffer keyp, client_id_list, client_mode_list;
775 SILC_LOG_DEBUG(("Start"));
777 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
778 if (status != SILC_STATUS_OK) {
779 cmd->client->ops->say(cmd->client, conn,
780 "%s", silc_client_command_status_message(status));
785 argc = silc_argument_get_arg_num(cmd->args);
786 if (argc < 7 || argc > 14) {
787 cmd->client->ops->say(cmd->client, conn,
788 "Cannot join channel: Bad reply packet");
793 /* Get channel name */
794 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
796 cmd->client->ops->say(cmd->client, conn,
797 "Cannot join channel: Bad reply packet");
801 channel_name = strdup(tmp);
804 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
806 cmd->client->ops->say(cmd->client, conn,
807 "Cannot join channel: Bad reply packet");
809 silc_free(channel_name);
812 idp = silc_id_payload_parse_data(tmp, len);
815 silc_free(channel_name);
819 /* Get channel mode */
820 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
822 SILC_GET32_MSB(mode, tmp);
826 /* Get channel key */
827 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
829 silc_id_payload_free(idp);
830 silc_free(channel_name);
833 keyp = silc_buffer_alloc(len);
834 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
835 silc_buffer_put(keyp, tmp, len);
838 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
840 /* Save received Channel ID. This actually creates the channel */
841 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
843 silc_id_payload_free(idp);
846 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
848 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
849 cmd->client->ops->say(cmd->client, conn,
850 "Cannot join channel: Unsupported HMAC `%s'",
853 silc_free(channel_name);
858 /* Get the list count */
859 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
862 SILC_GET32_MSB(list_count, tmp);
864 /* Get Client ID list */
865 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
869 client_id_list = silc_buffer_alloc(len);
870 silc_buffer_pull_tail(client_id_list, len);
871 silc_buffer_put(client_id_list, tmp, len);
873 /* Get client mode list */
874 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
878 client_mode_list = silc_buffer_alloc(len);
879 silc_buffer_pull_tail(client_mode_list, len);
880 silc_buffer_put(client_mode_list, tmp, len);
882 /* Add clients we received in the reply to the channel */
883 for (i = 0; i < list_count; i++) {
884 unsigned short idp_len;
886 SilcClientID *client_id;
887 SilcClientEntry client_entry;
890 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
892 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
897 SILC_GET32_MSB(mode, client_mode_list->data);
899 /* Check if we have this client cached already. */
900 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
901 SILC_ID_CLIENT, &id_cache)) {
902 /* No, we don't have it, add entry for it. */
903 client_entry = silc_calloc(1, sizeof(*client_entry));
904 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
905 silc_idcache_add(conn->client_cache, NULL, SILC_ID_CLIENT,
906 client_entry->id, (void *)client_entry, FALSE);
908 /* Yes, we have it already */
909 client_entry = (SilcClientEntry)id_cache->context;
912 /* Join the client to the channel */
913 chu = silc_calloc(1, sizeof(*chu));
914 chu->client = client_entry;
916 silc_list_add(channel->clients, chu);
917 silc_free(client_id);
919 silc_buffer_pull(client_id_list, idp_len);
920 silc_buffer_pull(client_mode_list, 4);
922 silc_buffer_push(client_id_list, client_id_list->data -
923 client_id_list->head);
924 silc_buffer_push(client_mode_list, client_mode_list->data -
925 client_mode_list->head);
927 /* Save channel key */
928 silc_client_save_channel_key(conn, keyp, channel);
930 /* Notify application */
931 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, keyp->head, NULL,
932 NULL, topic, hmac, list_count, client_id_list,
935 /* Execute any pending command callbacks */
936 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
938 silc_buffer_free(keyp);
939 silc_buffer_free(client_id_list);
940 silc_buffer_free(client_mode_list);
943 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
944 silc_client_command_reply_free(cmd);
947 /* Received reply for MOTD command */
949 SILC_CLIENT_CMD_REPLY_FUNC(motd)
951 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
952 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
953 SilcCommandStatus status;
954 unsigned int argc, i;
956 char *motd = NULL, *cp, line[256];
958 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
959 SILC_GET16_MSB(status, tmp);
960 if (status != SILC_STATUS_OK) {
961 cmd->client->ops->say(cmd->client, conn,
962 "%s", silc_client_command_status_message(status));
967 argc = silc_argument_get_arg_num(cmd->args);
974 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
983 if (cp[i++] == '\n') {
984 memset(line, 0, sizeof(line));
985 strncat(line, cp, i - 1);
991 cmd->client->ops->say(cmd->client, conn, "%s", line);
1000 /* Notify application */
1001 COMMAND_REPLY((ARGS, motd));
1003 /* Execute any pending command callbacks */
1004 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1007 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1008 silc_client_command_reply_free(cmd);
1011 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1015 /* Received reply for CMODE command. */
1017 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1019 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1020 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1021 SilcCommandStatus status;
1024 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1025 if (status != SILC_STATUS_OK) {
1026 cmd->client->ops->say(cmd->client, conn,
1027 "%s", silc_client_command_status_message(status));
1028 COMMAND_REPLY_ERROR;
1032 /* Get channel mode */
1033 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1035 COMMAND_REPLY_ERROR;
1039 /* Notify application */
1040 COMMAND_REPLY((ARGS, tmp));
1042 /* Execute any pending command callbacks */
1043 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1046 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1047 silc_client_command_reply_free(cmd);
1050 /* Received reply for CUMODE command */
1052 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1054 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1055 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1056 SilcCommandStatus status;
1057 SilcIDCacheEntry id_cache = NULL;
1058 SilcClientID *client_id;
1059 unsigned char *tmp, *id;
1062 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1063 if (status != SILC_STATUS_OK) {
1064 cmd->client->ops->say(cmd->client, conn,
1065 "%s", silc_client_command_status_message(status));
1066 COMMAND_REPLY_ERROR;
1070 /* Get channel mode */
1071 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1073 COMMAND_REPLY_ERROR;
1078 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1080 COMMAND_REPLY_ERROR;
1083 client_id = silc_id_payload_parse_id(id, len);
1085 COMMAND_REPLY_ERROR;
1089 /* Get client entry */
1090 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1091 SILC_ID_CLIENT, &id_cache)) {
1092 COMMAND_REPLY_ERROR;
1096 /* Notify application */
1097 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1098 silc_free(client_id);
1100 /* Execute any pending command callbacks */
1101 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1104 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1105 silc_client_command_reply_free(cmd);
1108 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1110 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1111 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1112 SilcCommandStatus status;
1115 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1116 SILC_GET16_MSB(status, tmp);
1117 if (status != SILC_STATUS_OK) {
1118 cmd->client->ops->say(cmd->client, conn,
1119 "%s", silc_client_command_status_message(status));
1120 COMMAND_REPLY_ERROR;
1124 /* Notify application */
1125 COMMAND_REPLY((ARGS));
1127 /* Execute any pending command callbacks */
1128 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1131 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1132 silc_client_command_reply_free(cmd);
1135 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1139 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1143 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1145 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1146 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1147 SilcCommandStatus status;
1150 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1151 SILC_GET16_MSB(status, tmp);
1152 if (status != SILC_STATUS_OK) {
1153 cmd->client->ops->say(cmd->client, conn,
1154 "%s", silc_client_command_status_message(status));
1155 COMMAND_REPLY_ERROR;
1159 /* Notify application */
1160 COMMAND_REPLY((ARGS));
1162 /* Execute any pending command callbacks */
1163 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1166 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1167 silc_client_command_reply_free(cmd);
1170 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1172 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1173 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1174 SilcCommandStatus status;
1177 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1178 SILC_GET16_MSB(status, tmp);
1179 if (status != SILC_STATUS_OK) {
1180 cmd->client->ops->say(cmd->client, conn,
1181 "%s", silc_client_command_status_message(status));
1182 COMMAND_REPLY_ERROR;
1186 /* Notify application */
1187 COMMAND_REPLY((ARGS));
1189 /* Execute any pending command callbacks */
1190 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1193 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1194 silc_client_command_reply_free(cmd);
1197 SILC_CLIENT_CMD_REPLY_FUNC(close)
1199 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1200 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1201 SilcCommandStatus status;
1204 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1205 SILC_GET16_MSB(status, tmp);
1206 if (status != SILC_STATUS_OK) {
1207 cmd->client->ops->say(cmd->client, conn,
1208 "%s", silc_client_command_status_message(status));
1209 COMMAND_REPLY_ERROR;
1213 /* Notify application */
1214 COMMAND_REPLY((ARGS));
1216 /* Execute any pending command callbacks */
1217 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1220 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1221 silc_client_command_reply_free(cmd);
1224 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1226 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1227 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1228 SilcCommandStatus status;
1231 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1232 SILC_GET16_MSB(status, tmp);
1233 if (status != SILC_STATUS_OK) {
1234 cmd->client->ops->say(cmd->client, conn,
1235 "%s", silc_client_command_status_message(status));
1236 COMMAND_REPLY_ERROR;
1240 /* Notify application */
1241 COMMAND_REPLY((ARGS));
1243 /* Execute any pending command callbacks */
1244 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1247 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1248 silc_client_command_reply_free(cmd);
1251 /* Reply to LEAVE command. */
1253 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1255 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1256 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1257 SilcCommandStatus status;
1260 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1261 SILC_GET16_MSB(status, tmp);
1262 if (status != SILC_STATUS_OK) {
1263 cmd->client->ops->say(cmd->client, conn,
1264 "%s", silc_client_command_status_message(status));
1265 COMMAND_REPLY_ERROR;
1269 /* Notify application */
1270 COMMAND_REPLY((ARGS));
1272 /* Execute any pending command callbacks */
1273 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1276 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1277 silc_client_command_reply_free(cmd);
1280 /* Reply to USERS command. Received list of client ID's and theirs modes
1281 on the channel we requested. */
1283 SILC_CLIENT_CMD_REPLY_FUNC(users)
1285 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1286 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1287 SilcCommandStatus status;
1288 SilcIDCacheEntry id_cache = NULL;
1289 SilcChannelEntry channel;
1290 SilcChannelUser chu;
1291 SilcChannelID *channel_id = NULL;
1292 SilcBuffer client_id_list;
1293 SilcBuffer client_mode_list;
1295 unsigned int tmp_len, list_count;
1297 unsigned char **res_argv = NULL;
1298 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1300 SILC_LOG_DEBUG(("Start"));
1302 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1303 SILC_GET16_MSB(status, tmp);
1304 if (status != SILC_STATUS_OK) {
1305 cmd->client->ops->say(cmd->client, conn,
1306 "%s", silc_client_command_status_message(status));
1307 COMMAND_REPLY_ERROR;
1311 /* Get channel ID */
1312 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1315 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1319 /* Get the list count */
1320 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1323 SILC_GET32_MSB(list_count, tmp);
1325 /* Get Client ID list */
1326 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1330 client_id_list = silc_buffer_alloc(tmp_len);
1331 silc_buffer_pull_tail(client_id_list, tmp_len);
1332 silc_buffer_put(client_id_list, tmp, tmp_len);
1334 /* Get client mode list */
1335 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1339 client_mode_list = silc_buffer_alloc(tmp_len);
1340 silc_buffer_pull_tail(client_mode_list, tmp_len);
1341 silc_buffer_put(client_mode_list, tmp, tmp_len);
1343 /* Get channel entry */
1344 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1345 SILC_ID_CHANNEL, &id_cache)) {
1346 COMMAND_REPLY_ERROR;
1349 channel = (SilcChannelEntry)id_cache->context;
1351 /* Remove old client list from channel. */
1352 silc_list_start(channel->clients);
1353 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1354 silc_list_del(channel->clients, chu);
1358 /* Cache the received Client ID's and modes. This cache expires
1359 whenever server sends notify message to channel. It means two things;
1360 some user has joined or leaved the channel. XXX! */
1361 for (i = 0; i < list_count; i++) {
1362 unsigned short idp_len;
1364 SilcClientID *client_id;
1365 SilcClientEntry client;
1368 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1370 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1375 SILC_GET32_MSB(mode, client_mode_list->data);
1377 /* Check if we have this client cached already. */
1378 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1379 SILC_ID_CLIENT, &id_cache)) {
1380 /* No we don't have it, query it from the server. Assemble argument
1381 table that will be sent fr the IDENTIFY command later. */
1382 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1384 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1386 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1388 res_argv[res_argc] = client_id_list->data;
1389 res_argv_lens[res_argc] = idp_len;
1390 res_argv_types[res_argc] = res_argc + 3;
1393 /* Found the client, join it to the channel */
1394 client = (SilcClientEntry)id_cache->context;
1395 chu = silc_calloc(1, sizeof(*chu));
1396 chu->client = client;
1398 silc_list_add(channel->clients, chu);
1400 silc_free(client_id);
1404 silc_buffer_pull(client_id_list, idp_len);
1405 silc_buffer_pull(client_mode_list, 4);
1408 /* Query the client information from server if the list included clients
1409 that we don't know about. */
1413 /* Send the IDENTIFY command to server */
1414 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1415 res_argc, res_argv, res_argv_lens,
1416 res_argv_types, ++conn->cmd_ident);
1417 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1418 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1421 /* Register pending command callback. After we've received the IDENTIFY
1422 command reply we will reprocess this command reply by re-calling this
1423 USERS command reply callback. */
1424 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1425 NULL, silc_client_command_reply_users, cmd);
1427 silc_buffer_free(res_cmd);
1429 silc_free(channel_id);
1431 silc_free(res_argv);
1432 silc_free(res_argv_lens);
1433 silc_free(res_argv_types);
1437 /* Notify application */
1438 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1440 /* Execute any pending command callbacks */
1441 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1443 silc_buffer_free(client_id_list);
1444 silc_buffer_free(client_mode_list);
1448 silc_free(channel_id);
1449 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1450 silc_client_command_reply_free(cmd);