5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 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"
38 /* Client command reply list. */
39 SilcClientCommandReply silc_command_reply_list[] =
41 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
42 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
43 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
44 SILC_CLIENT_CMD_REPLY(nick, NICK),
45 SILC_CLIENT_CMD_REPLY(list, LIST),
46 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
47 SILC_CLIENT_CMD_REPLY(invite, INVITE),
48 SILC_CLIENT_CMD_REPLY(quit, QUIT),
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(die, DIE),
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_SERVER_PRIV), "Permission denied. You are not server operator" },
111 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
112 { STAT(BAD_NICKNAME), "Bad nickname" },
113 { STAT(BAD_CHANNEL), "Bad channel name" },
114 { STAT(AUTH_FAILED), "Authentication failed" },
119 /* Command reply operation that is called at the end of all command replys.
120 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
121 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
122 #define ARGS cmd->client, cmd->sock->user_data, \
123 cmd->payload, TRUE, silc_command_get(cmd->payload), status
125 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
126 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
127 cmd->sock->user_data, cmd->payload, FALSE, \
128 silc_command_get(cmd->payload), status)
130 /* Process received command reply. */
132 void silc_client_command_reply_process(SilcClient client,
133 SilcSocketConnection sock,
134 SilcPacketContext *packet)
136 SilcBuffer buffer = packet->buffer;
137 SilcClientCommandReply *cmd;
138 SilcClientCommandReplyContext ctx;
139 SilcCommandPayload payload;
141 unsigned short ident;
143 /* Get command reply payload from packet */
144 payload = silc_command_payload_parse(buffer);
146 /* Silently ignore bad reply packet */
147 SILC_LOG_DEBUG(("Bad command reply packet"));
151 /* Allocate command reply context. This must be free'd by the
152 command reply routine receiving it. */
153 ctx = silc_calloc(1, sizeof(*ctx));
154 ctx->client = client;
156 ctx->payload = payload;
157 ctx->args = silc_command_get_args(ctx->payload);
158 ctx->packet = packet;
159 ident = silc_command_get_ident(ctx->payload);
161 /* Check for pending commands and mark to be exeucted */
162 silc_client_command_pending_check(sock->user_data, ctx,
163 silc_command_get(ctx->payload), ident);
165 /* Execute command reply */
166 command = silc_command_get(ctx->payload);
167 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
168 if (cmd->cmd == command)
171 if (cmd == NULL || !cmd->cb) {
179 /* Returns status message string */
182 silc_client_command_status_message(SilcCommandStatus status)
186 for (i = 0; silc_command_status_messages[i].message; i++) {
187 if (silc_command_status_messages[i].status == status)
191 if (silc_command_status_messages[i].message == NULL)
194 return silc_command_status_messages[i].message;
197 /* Free command reply context and its internals. */
199 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
202 silc_command_free_payload(cmd->payload);
208 silc_client_command_reply_whois_print(SilcClientCommandReplyContext cmd,
209 SilcCommandStatus status)
213 unsigned char *id_data;
214 char *nickname = NULL, *username = NULL;
215 char *realname = NULL;
216 SilcClientID *client_id;
217 SilcIDCacheEntry id_cache = NULL;
218 SilcClientEntry client_entry = NULL;
219 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
221 memset(buf, 0, sizeof(buf));
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);
233 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
235 strncat(buf, nickname, len);
236 strncat(buf, " is ", 4);
239 username = silc_argument_get_arg_type(cmd->args, 4, &len);
241 strncat(buf, username, len);
244 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
246 strncat(buf, " (", 2);
247 strncat(buf, realname, len);
248 strncat(buf, ")", 1);
251 /* Check if we have this client cached already. */
252 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
253 SILC_ID_CLIENT, &id_cache)) {
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_parse_nickname(nickname, &client_entry->nickname,
277 &client_entry->server, &client_entry->num);
278 client_entry->username = strdup(username);
280 client_entry->realname = strdup(realname);
282 id_cache->data = client_entry->nickname;
284 silc_free(client_id);
288 cmd->client->ops->say(cmd->client, conn, "%s", buf);
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_print(cmd, status);
337 /* XXX list should not be displayed untill all items has been received. */
338 if (status == SILC_STATUS_LIST_START) {
339 silc_client_command_reply_whois_print(cmd, status);
342 if (status == SILC_STATUS_LIST_ITEM) {
343 silc_client_command_reply_whois_print(cmd, status);
346 if (status == SILC_STATUS_LIST_END) {
347 silc_client_command_reply_whois_print(cmd, status);
350 /* Execute any pending command callbacks */
351 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
354 silc_client_command_reply_free(cmd);
357 /* Received reply for WHOWAS command. */
359 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
364 /* Received reply for IDENTIFY command. This maybe called several times
365 for one IDENTIFY command as server may reply with list of results.
366 This is totally silent and does not print anything on screen. */
368 SILC_CLIENT_CMD_REPLY_FUNC(identify)
370 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
371 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
372 SilcClientEntry client_entry;
373 SilcIDCacheEntry id_cache = NULL;
374 SilcCommandStatus status;
377 SILC_LOG_DEBUG(("Start"));
379 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
380 SILC_GET16_MSB(status, tmp);
381 if (status != SILC_STATUS_OK) {
382 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
383 /* Take nickname which may be provided */
384 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
386 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
387 silc_client_command_status_message(status));
389 cmd->client->ops->say(cmd->client, conn, "%s",
390 silc_client_command_status_message(status));
394 cmd->client->ops->say(cmd->client, conn,
395 "%s", silc_client_command_status_message(status));
401 /* Display one whois reply */
402 if (status == SILC_STATUS_OK) {
404 unsigned char *id_data;
407 SilcClientID *client_id;
409 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
412 client_id = silc_id_payload_parse_id(id_data, len);
414 nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
415 username = silc_argument_get_arg_type(cmd->args, 4, NULL);
417 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
418 SILC_ID_CLIENT, &id_cache)) {
419 client_entry = silc_calloc(1, sizeof(*client_entry));
420 client_entry->id = client_id;
421 silc_parse_nickname(nickname, &client_entry->nickname,
422 &client_entry->server, &client_entry->num);
424 client_entry->username = strdup(username);
426 /* Add client to cache */
427 silc_idcache_add(conn->client_cache, client_entry->nickname,
428 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
430 client_entry = (SilcClientEntry)id_cache->context;
431 if (client_entry->nickname)
432 silc_free(client_entry->nickname);
433 if (client_entry->server)
434 silc_free(client_entry->server);
435 if (username && client_entry->username)
436 silc_free(client_entry->username);
438 silc_parse_nickname(nickname, &client_entry->nickname,
439 &client_entry->server, &client_entry->num);
442 client_entry->username = strdup(username);
444 id_cache->data = client_entry->nickname;
446 silc_free(client_id);
450 if (status == SILC_STATUS_LIST_START) {
454 if (status == SILC_STATUS_LIST_END) {
458 /* Execute any pending command callbacks */
459 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
462 silc_client_command_reply_free(cmd);
465 /* Received reply for command NICK. If everything went without errors
466 we just received our new Client ID. */
468 SILC_CLIENT_CMD_REPLY_FUNC(nick)
470 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
471 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
472 SilcCommandStatus status;
475 unsigned int argc, len;
477 SILC_LOG_DEBUG(("Start"));
479 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
480 if (status != SILC_STATUS_OK) {
481 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
482 silc_client_command_status_message(status));
487 argc = silc_argument_get_arg_num(cmd->args);
488 if (argc < 2 || argc > 2) {
489 cmd->client->ops->say(cmd->client, conn,
490 "Cannot set nickname: bad reply to command");
495 /* Take received Client ID */
496 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
497 idp = silc_id_payload_parse_data(tmp, len);
498 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
500 /* Notify application */
501 COMMAND_REPLY((ARGS, conn->local_entry));
503 /* Execute any pending command callbacks */
504 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_NICK);
507 silc_client_command_reply_free(cmd);
510 SILC_CLIENT_CMD_REPLY_FUNC(list)
514 /* Received reply to topic command. */
516 SILC_CLIENT_CMD_REPLY_FUNC(topic)
518 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
519 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
520 SilcCommandStatus status;
521 SilcChannelEntry channel;
522 SilcChannelID *channel_id = NULL;
523 SilcIDCacheEntry id_cache = NULL;
526 unsigned int argc, len;
528 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
529 if (status != SILC_STATUS_OK) {
530 cmd->client->ops->say(cmd->client, conn,
531 "%s", silc_client_command_status_message(status));
533 silc_client_command_reply_free(cmd);
537 argc = silc_argument_get_arg_num(cmd->args);
538 if (argc < 1 || argc > 3) {
543 /* Take Channel ID */
544 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
549 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
553 channel_id = silc_id_payload_parse_id(tmp, len);
555 /* Get the channel name */
556 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
557 SILC_ID_CHANNEL, &id_cache)) {
558 silc_free(channel_id);
563 channel = (SilcChannelEntry)id_cache->context;
565 cmd->client->ops->say(cmd->client, conn,
566 "Topic on channel %s: %s", channel->channel_name,
569 /* Notify application */
570 COMMAND_REPLY((ARGS, channel, topic));
572 /* Execute any pending command callbacks */
573 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_TOPIC);
576 silc_client_command_reply_free(cmd);
579 /* Received reply to invite command. */
581 SILC_CLIENT_CMD_REPLY_FUNC(invite)
583 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
584 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
585 SilcCommandStatus status;
588 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
589 SILC_GET16_MSB(status, tmp);
590 if (status != SILC_STATUS_OK) {
591 cmd->client->ops->say(cmd->client, conn,
592 "%s", silc_client_command_status_message(status));
594 silc_client_command_reply_free(cmd);
598 /* Notify application */
599 COMMAND_REPLY((ARGS));
601 /* Execute any pending command callbacks */
602 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_INVITE);
604 silc_client_command_reply_free(cmd);
607 SILC_CLIENT_CMD_REPLY_FUNC(quit)
611 SILC_CLIENT_CMD_REPLY_FUNC(kill)
615 /* Received reply to INFO command. We receive the server ID and some
616 information about the server user requested. */
618 SILC_CLIENT_CMD_REPLY_FUNC(info)
620 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
621 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
622 SilcClient client = cmd->client;
623 SilcCommandStatus status;
626 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
627 SILC_GET16_MSB(status, tmp);
628 if (status != SILC_STATUS_OK) {
629 cmd->client->ops->say(cmd->client, conn,
630 "%s", silc_client_command_status_message(status));
632 silc_client_command_reply_free(cmd);
637 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
641 /* XXX save server id */
643 /* Get server info */
644 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
648 client->ops->say(cmd->client, conn, "Info: %s", tmp);
650 /* Notify application */
651 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
653 /* Execute any pending command callbacks */
654 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_INFO);
657 silc_client_command_reply_free(cmd);
660 SILC_CLIENT_CMD_REPLY_FUNC(connect)
664 /* Received reply to PING command. The reply time is shown to user. */
666 SILC_CLIENT_CMD_REPLY_FUNC(ping)
668 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
669 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
670 SilcCommandStatus status;
673 time_t diff, curtime;
675 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
676 if (status != SILC_STATUS_OK) {
677 cmd->client->ops->say(cmd->client, conn,
678 "%s", silc_client_command_status_message(status));
683 curtime = time(NULL);
684 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
686 for (i = 0; i < conn->ping_count; i++) {
687 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
688 diff = curtime - conn->ping[i].start_time;
689 cmd->client->ops->say(cmd->client, conn,
690 "Ping reply from %s: %d second%s",
691 conn->ping[i].dest_name, diff,
692 diff == 1 ? "" : "s");
694 conn->ping[i].start_time = 0;
695 silc_free(conn->ping[i].dest_id);
696 conn->ping[i].dest_id = NULL;
697 silc_free(conn->ping[i].dest_name);
698 conn->ping[i].dest_name = NULL;
700 /* Notify application */
701 COMMAND_REPLY((ARGS));
708 /* Execute any pending command callbacks */
709 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_PING);
712 silc_client_command_reply_free(cmd);
715 SILC_CLIENT_CMD_REPLY_FUNC(oper)
719 /* Received reply for JOIN command. */
721 SILC_CLIENT_CMD_REPLY_FUNC(join)
723 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
724 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
725 SilcClient client = cmd->client;
726 SilcCommandStatus status;
727 SilcIDPayload idp = NULL;
728 unsigned int argc, mode, len;
729 char *topic, *tmp, *channel_name = NULL;
732 SILC_LOG_DEBUG(("Start"));
734 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
735 if (status != SILC_STATUS_OK) {
736 cmd->client->ops->say(cmd->client, conn,
737 "%s", silc_client_command_status_message(status));
742 argc = silc_argument_get_arg_num(cmd->args);
743 if (argc < 3 || argc > 9) {
744 cmd->client->ops->say(cmd->client, conn,
745 "Cannot join channel: Bad reply packet");
750 /* Get channel name */
751 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
753 cmd->client->ops->say(cmd->client, conn,
754 "Cannot join channel: Bad reply packet");
758 channel_name = strdup(tmp);
761 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
763 cmd->client->ops->say(cmd->client, conn,
764 "Cannot join channel: Bad reply packet");
766 silc_free(channel_name);
769 idp = silc_id_payload_parse_data(tmp, len);
771 /* Get channel mode */
772 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
774 SILC_GET32_MSB(mode, tmp);
778 /* Get channel key */
779 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
781 silc_id_payload_free(idp);
782 silc_free(channel_name);
785 keyp = silc_buffer_alloc(len);
786 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
787 silc_buffer_put(keyp, tmp, len);
790 topic = silc_argument_get_arg_type(cmd->args, 8, NULL);
792 /* Save received Channel ID */
793 silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
795 silc_id_payload_free(idp);
797 /* Save channel key */
798 silc_client_save_channel_key(conn, keyp, conn->current_channel);
799 silc_buffer_free(keyp);
802 client->ops->say(cmd->client, conn,
803 "Topic for %s: %s", channel_name, topic);
805 /* Notify application */
806 COMMAND_REPLY((ARGS, channel_name, conn->current_channel, mode,
809 /* Execute any pending command callbacks */
810 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_JOIN);
813 silc_client_command_reply_free(cmd);
816 /* Received reply for MOTD command */
818 SILC_CLIENT_CMD_REPLY_FUNC(motd)
820 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
821 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
822 SilcCommandStatus status;
823 unsigned int argc, i;
825 char *motd = NULL, *cp, line[256];
827 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
828 SILC_GET16_MSB(status, tmp);
829 if (status != SILC_STATUS_OK) {
830 cmd->client->ops->say(cmd->client, conn,
831 "%s", silc_client_command_status_message(status));
836 argc = silc_argument_get_arg_num(cmd->args);
843 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
852 if (cp[i++] == '\n') {
853 memset(line, 0, sizeof(line));
854 strncat(line, cp, i - 1);
860 cmd->client->ops->say(cmd->client, conn, "%s", line);
869 /* Notify application */
870 COMMAND_REPLY((ARGS, motd));
872 /* Execute any pending command callbacks */
873 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_MOTD);
876 silc_client_command_reply_free(cmd);
879 SILC_CLIENT_CMD_REPLY_FUNC(umode)
883 /* Received reply for CMODE command. */
885 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
887 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
888 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
889 SilcCommandStatus status;
892 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
893 if (status != SILC_STATUS_OK) {
894 cmd->client->ops->say(cmd->client, conn,
895 "%s", silc_client_command_status_message(status));
900 /* Get channel mode */
901 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
907 /* Notify application */
908 COMMAND_REPLY((ARGS, tmp));
910 /* Execute any pending command callbacks */
911 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_CMODE);
914 silc_client_command_reply_free(cmd);
917 /* Received reply for CUMODE command */
919 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
921 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
922 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
923 SilcCommandStatus status;
924 SilcIDCacheEntry id_cache = NULL;
925 SilcClientID *client_id;
926 unsigned char *tmp, *id;
929 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
930 if (status != SILC_STATUS_OK) {
931 cmd->client->ops->say(cmd->client, conn,
932 "%s", silc_client_command_status_message(status));
937 /* Get channel mode */
938 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
945 id = silc_argument_get_arg_type(cmd->args, 3, &len);
950 client_id = silc_id_payload_parse_id(id, len);
952 /* Get client entry */
953 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
954 SILC_ID_CLIENT, &id_cache)) {
959 /* Notify application */
960 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
961 silc_free(client_id);
963 /* Execute any pending command callbacks */
964 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_CUMODE);
967 silc_client_command_reply_free(cmd);
970 SILC_CLIENT_CMD_REPLY_FUNC(kick)
974 SILC_CLIENT_CMD_REPLY_FUNC(restart)
978 SILC_CLIENT_CMD_REPLY_FUNC(close)
982 SILC_CLIENT_CMD_REPLY_FUNC(die)
986 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
990 /* Reply to LEAVE command. */
992 SILC_CLIENT_CMD_REPLY_FUNC(leave)
994 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
995 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
996 SilcCommandStatus status;
999 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1000 SILC_GET16_MSB(status, tmp);
1001 if (status != SILC_STATUS_OK) {
1002 cmd->client->ops->say(cmd->client, conn,
1003 "%s", silc_client_command_status_message(status));
1004 COMMAND_REPLY_ERROR;
1008 /* Notify application */
1009 COMMAND_REPLY((ARGS));
1011 /* Execute any pending command callbacks */
1012 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_LEAVE);
1014 silc_client_command_reply_free(cmd);
1017 /* Reply to USERS command. Received list of client ID's and theirs modes
1018 on the channel we requested. */
1020 SILC_CLIENT_CMD_REPLY_FUNC(users)
1022 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1023 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1024 SilcCommandStatus status;
1025 SilcIDCacheEntry id_cache = NULL;
1026 SilcChannelEntry channel;
1027 SilcChannelUser chu;
1028 SilcChannelID *channel_id = NULL;
1029 SilcBuffer client_id_list;
1030 SilcBuffer client_mode_list;
1032 unsigned int tmp_len, list_count;
1034 unsigned char **res_argv = NULL;
1035 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1037 SILC_LOG_DEBUG(("Start"));
1039 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1040 SILC_GET16_MSB(status, tmp);
1041 if (status != SILC_STATUS_OK) {
1042 cmd->client->ops->say(cmd->client, conn,
1043 "%s", silc_client_command_status_message(status));
1044 COMMAND_REPLY_ERROR;
1048 /* Get channel ID */
1049 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1052 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1054 /* Get the list count */
1055 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1058 SILC_GET32_MSB(list_count, tmp);
1060 /* Get Client ID list */
1061 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1065 client_id_list = silc_buffer_alloc(tmp_len);
1066 silc_buffer_pull_tail(client_id_list, tmp_len);
1067 silc_buffer_put(client_id_list, tmp, tmp_len);
1069 /* Get client mode list */
1070 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1074 client_mode_list = silc_buffer_alloc(tmp_len);
1075 silc_buffer_pull_tail(client_mode_list, tmp_len);
1076 silc_buffer_put(client_mode_list, tmp, tmp_len);
1078 /* Get channel entry */
1079 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1080 SILC_ID_CHANNEL, &id_cache)) {
1081 COMMAND_REPLY_ERROR;
1084 channel = (SilcChannelEntry)id_cache->context;
1086 /* Remove old client list from channel. */
1087 silc_list_start(channel->clients);
1088 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1089 silc_list_del(channel->clients, chu);
1093 /* Cache the received Client ID's and modes. This cache expires
1094 whenever server sends notify message to channel. It means two things;
1095 some user has joined or leaved the channel. XXX! */
1096 for (i = 0; i < list_count; i++) {
1097 unsigned short idp_len;
1099 SilcClientID *client_id;
1100 SilcClientEntry client;
1103 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1105 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1106 silc_buffer_pull(client_id_list, idp_len);
1109 SILC_GET32_MSB(mode, client_mode_list->data);
1110 silc_buffer_pull(client_mode_list, 4);
1112 /* Check if we have this client cached already. */
1113 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1114 SILC_ID_CLIENT, &id_cache)) {
1115 /* No we don't have it, query it from the server. Assemble argument
1116 table that will be sent fr the IDENTIFY command later. */
1117 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1119 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1121 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1123 res_argv[res_argc] = client_id_list->data;
1124 res_argv_lens[res_argc] = idp_len;
1125 res_argv_types[res_argc] = res_argc + 3;
1128 /* Found the client, join it to the channel */
1129 client = (SilcClientEntry)id_cache->context;
1130 chu = silc_calloc(1, sizeof(*chu));
1131 chu->client = client;
1133 silc_list_add(channel->clients, chu);
1135 silc_free(client_id);
1140 /* Query the client information from server if the list included clients
1141 that we don't know about. */
1145 /* Send the IDENTIFY command to server */
1146 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1147 res_argc, res_argv, res_argv_lens,
1148 res_argv_types, ++conn->cmd_ident);
1149 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1150 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1153 /* Register pending command callback. After we've received the IDENTIFY
1154 command reply we will reprocess this command reply by re-calling this
1155 USERS command reply callback. */
1156 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1157 silc_client_command_reply_users, cmd);
1159 silc_buffer_free(res_cmd);
1161 silc_free(channel_id);
1163 for (i = 0; i < res_argc; i++)
1164 silc_free(res_argv[i]);
1165 silc_free(res_argv);
1166 silc_free(res_argv_lens);
1167 silc_free(res_argv_types);
1171 /* We have all the clients on the channel cached now. Create a nice
1172 output for user interface and notify application. */
1174 if (cmd->callback) {
1175 /* User has called USERS command on user interface. */
1176 cmd->client->ops->say(cmd->client, conn, "Users on %s",
1177 channel->channel_name);
1179 silc_list_start(channel->clients);
1180 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1181 SilcClientEntry e = chu->client;
1182 char *m, tmp[80], line[80], len1;
1184 memset(line, 0, sizeof(line));
1185 memset(tmp, 0, sizeof(tmp));
1186 m = silc_client_chumode_char(chu->mode);
1189 strcat(line, e->nickname);
1190 strcat(line, e->server ? "@" : "");
1194 len1 = strlen(e->server);
1195 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1197 len1 = strlen(line);
1199 memset(&line[29], 0, len1 - 29);
1201 for (i = 0; i < 30 - len1 - 1; i++)
1206 strcat(tmp, m ? m : "");
1209 if (strlen(tmp) < 5)
1210 for (i = 0; i < 5 - strlen(tmp); i++)
1213 strcat(line, e->username ? e->username : "");
1215 cmd->client->ops->say(cmd->client, conn, "%s", line);
1222 /* Server has sent us USERS reply even when we haven't actually sent
1223 USERS command. This is normal behaviour when joining to a channel.
1224 Display some nice information on the user interface. */
1225 int k = 0, len1 = 0, len2 = 0;
1226 char *name_list = NULL;
1228 silc_list_start(channel->clients);
1229 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1230 char *m, *n = chu->client->nickname;
1234 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
1236 m = silc_client_chumode_char(chu->mode);
1238 memcpy(name_list + (len1 - len2), m, strlen(m));
1243 memcpy(name_list + (len1 - len2), n, len2);
1244 name_list[len1] = 0;
1246 if (k == silc_list_count(channel->clients) - 1)
1248 memcpy(name_list + len1, " ", 1);
1253 cmd->client->ops->say(cmd->client, conn, "Users on %s: %s",
1254 channel->channel_name, name_list);
1255 silc_free(name_list);
1258 /* Notify application */
1259 COMMAND_REPLY((ARGS, channel, client_id_list->head,
1260 client_mode_list->head));
1262 /* Execute any pending command callbacks */
1263 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_USERS);
1265 silc_buffer_free(client_id_list);
1266 silc_buffer_free(client_mode_list);
1270 silc_free(channel_id);
1271 silc_client_command_reply_free(cmd);