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 SilcClientCommandReplyContext ctx;
138 SilcCommandPayload payload;
140 /* Get command reply payload from packet */
141 payload = silc_command_payload_parse(buffer);
143 /* Silently ignore bad reply packet */
144 SILC_LOG_DEBUG(("Bad command reply packet"));
148 /* Allocate command reply context. This must be free'd by the
149 command reply routine receiving it. */
150 ctx = silc_calloc(1, sizeof(*ctx));
151 ctx->client = client;
153 ctx->payload = payload;
154 ctx->args = silc_command_get_args(ctx->payload);
155 ctx->packet = packet;
157 /* Check for pending commands and mark to be exeucted */
158 SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
160 /* Execute command reply */
161 SILC_CLIENT_COMMAND_REPLY_EXEC(ctx);
164 /* Returns status message string */
167 silc_client_command_status_message(SilcCommandStatus status)
171 for (i = 0; silc_command_status_messages[i].message; i++) {
172 if (silc_command_status_messages[i].status == status)
176 if (silc_command_status_messages[i].message == NULL)
179 return silc_command_status_messages[i].message;
182 /* Free command reply context and its internals. */
184 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
187 silc_command_free_payload(cmd->payload);
193 silc_client_command_reply_whois_print(SilcClientCommandReplyContext cmd,
194 SilcCommandStatus status)
198 unsigned char *id_data;
199 char *nickname = NULL, *username = NULL;
200 char *realname = NULL;
201 SilcClientID *client_id;
202 SilcIDCacheEntry id_cache = NULL;
203 SilcClientEntry client_entry = NULL;
204 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
206 memset(buf, 0, sizeof(buf));
208 argc = silc_argument_get_arg_num(cmd->args);
210 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
216 client_id = silc_id_payload_parse_id(id_data, len);
218 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
220 strncat(buf, nickname, len);
221 strncat(buf, " is ", 4);
224 username = silc_argument_get_arg_type(cmd->args, 4, &len);
226 strncat(buf, username, len);
229 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
231 strncat(buf, " (", 2);
232 strncat(buf, realname, len);
233 strncat(buf, ")", 1);
236 /* Check if we have this client cached already. */
237 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
238 SILC_ID_CLIENT, &id_cache)) {
239 client_entry = silc_calloc(1, sizeof(*client_entry));
240 client_entry->id = client_id;
241 silc_parse_nickname(nickname, &client_entry->nickname,
242 &client_entry->server, &client_entry->num);
243 client_entry->username = strdup(username);
245 client_entry->realname = strdup(realname);
247 /* Add client to cache */
248 silc_idcache_add(conn->client_cache, client_entry->nickname,
249 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
251 client_entry = (SilcClientEntry)id_cache->context;
252 if (client_entry->nickname)
253 silc_free(client_entry->nickname);
254 if (client_entry->server)
255 silc_free(client_entry->server);
256 if (client_entry->username)
257 silc_free(client_entry->username);
258 if (client_entry->realname)
259 silc_free(client_entry->realname);
261 silc_parse_nickname(nickname, &client_entry->nickname,
262 &client_entry->server, &client_entry->num);
263 client_entry->username = strdup(username);
265 client_entry->realname = strdup(realname);
267 id_cache->data = client_entry->nickname;
269 silc_free(client_id);
273 cmd->client->ops->say(cmd->client, conn, "%s", buf);
275 /* Notify application */
276 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
280 /* Received reply for WHOIS command. This maybe called several times
281 for one WHOIS command as server may reply with list of results. */
283 SILC_CLIENT_CMD_REPLY_FUNC(whois)
285 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
286 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
287 SilcCommandStatus status;
290 SILC_LOG_DEBUG(("Start"));
292 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
293 SILC_GET16_MSB(status, tmp);
294 if (status != SILC_STATUS_OK &&
295 status != SILC_STATUS_LIST_START &&
296 status != SILC_STATUS_LIST_ITEM &&
297 status != SILC_STATUS_LIST_END) {
298 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
299 /* Take nickname which may be provided */
300 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
302 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
303 silc_client_command_status_message(status));
305 cmd->client->ops->say(cmd->client, conn, "%s",
306 silc_client_command_status_message(status));
310 cmd->client->ops->say(cmd->client, conn,
311 "%s", silc_client_command_status_message(status));
317 /* Display one whois reply */
318 if (status == SILC_STATUS_OK) {
319 silc_client_command_reply_whois_print(cmd, status);
322 /* XXX list should not be displayed untill all items has been received. */
323 if (status == SILC_STATUS_LIST_START) {
324 silc_client_command_reply_whois_print(cmd, status);
327 if (status == SILC_STATUS_LIST_ITEM) {
328 silc_client_command_reply_whois_print(cmd, status);
331 if (status == SILC_STATUS_LIST_END) {
332 silc_client_command_reply_whois_print(cmd, status);
335 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
338 silc_client_command_reply_free(cmd);
341 /* Received reply for WHOWAS command. */
343 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
348 /* Received reply for IDENTIFY command. This maybe called several times
349 for one IDENTIFY command as server may reply with list of results.
350 This is totally silent and does not print anything on screen. */
352 SILC_CLIENT_CMD_REPLY_FUNC(identify)
354 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
355 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
356 SilcClientEntry client_entry;
357 SilcIDCacheEntry id_cache = NULL;
358 SilcCommandStatus status;
361 SILC_LOG_DEBUG(("Start"));
363 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
364 SILC_GET16_MSB(status, tmp);
365 if (status != SILC_STATUS_OK) {
366 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
367 /* Take nickname which may be provided */
368 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
370 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
371 silc_client_command_status_message(status));
373 cmd->client->ops->say(cmd->client, conn, "%s",
374 silc_client_command_status_message(status));
378 cmd->client->ops->say(cmd->client, conn,
379 "%s", silc_client_command_status_message(status));
385 /* Display one whois reply */
386 if (status == SILC_STATUS_OK) {
388 unsigned char *id_data;
391 SilcClientID *client_id;
393 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
396 client_id = silc_id_payload_parse_id(id_data, len);
398 nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
399 username = silc_argument_get_arg_type(cmd->args, 4, NULL);
401 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
402 SILC_ID_CLIENT, &id_cache)) {
403 client_entry = silc_calloc(1, sizeof(*client_entry));
404 client_entry->id = client_id;
405 silc_parse_nickname(nickname, &client_entry->nickname,
406 &client_entry->server, &client_entry->num);
408 client_entry->username = strdup(username);
410 /* Add client to cache */
411 silc_idcache_add(conn->client_cache, client_entry->nickname,
412 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
414 client_entry = (SilcClientEntry)id_cache->context;
415 if (client_entry->nickname)
416 silc_free(client_entry->nickname);
417 if (client_entry->server)
418 silc_free(client_entry->server);
419 if (username && client_entry->username)
420 silc_free(client_entry->username);
422 silc_parse_nickname(nickname, &client_entry->nickname,
423 &client_entry->server, &client_entry->num);
426 client_entry->username = strdup(username);
428 id_cache->data = client_entry->nickname;
430 silc_free(client_id);
434 if (status == SILC_STATUS_LIST_START) {
438 if (status == SILC_STATUS_LIST_END) {
442 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
445 silc_client_command_reply_free(cmd);
448 /* Received reply for command NICK. If everything went without errors
449 we just received our new Client ID. */
451 SILC_CLIENT_CMD_REPLY_FUNC(nick)
453 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
454 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
455 SilcCommandStatus status;
458 unsigned int argc, len;
460 SILC_LOG_DEBUG(("Start"));
462 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
463 if (status != SILC_STATUS_OK) {
464 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
465 silc_client_command_status_message(status));
470 argc = silc_argument_get_arg_num(cmd->args);
471 if (argc < 2 || argc > 2) {
472 cmd->client->ops->say(cmd->client, conn,
473 "Cannot set nickname: bad reply to command");
478 /* Take received Client ID */
479 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
480 idp = silc_id_payload_parse_data(tmp, len);
481 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
483 /* Notify application */
484 COMMAND_REPLY((ARGS, conn->local_entry));
487 silc_client_command_reply_free(cmd);
490 SILC_CLIENT_CMD_REPLY_FUNC(list)
494 /* Received reply to topic command. */
496 SILC_CLIENT_CMD_REPLY_FUNC(topic)
498 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
499 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
500 SilcCommandStatus status;
501 SilcChannelEntry channel;
502 SilcChannelID *channel_id = NULL;
503 SilcIDCacheEntry id_cache = NULL;
506 unsigned int argc, len;
508 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
509 if (status != SILC_STATUS_OK) {
510 cmd->client->ops->say(cmd->client, conn,
511 "%s", silc_client_command_status_message(status));
513 silc_client_command_reply_free(cmd);
517 argc = silc_argument_get_arg_num(cmd->args);
518 if (argc < 1 || argc > 3) {
523 /* Take Channel ID */
524 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
529 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
533 channel_id = silc_id_payload_parse_id(tmp, len);
535 /* Get the channel name */
536 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
537 SILC_ID_CHANNEL, &id_cache)) {
538 silc_free(channel_id);
543 channel = (SilcChannelEntry)id_cache->context;
545 cmd->client->ops->say(cmd->client, conn,
546 "Topic on channel %s: %s", channel->channel_name,
549 /* Notify application */
550 COMMAND_REPLY((ARGS, channel, topic));
553 silc_client_command_reply_free(cmd);
556 /* Received reply to invite command. */
558 SILC_CLIENT_CMD_REPLY_FUNC(invite)
560 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
561 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
562 SilcCommandStatus status;
565 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
566 SILC_GET16_MSB(status, tmp);
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_command_reply_free(cmd);
575 /* Notify application */
576 COMMAND_REPLY((ARGS));
578 silc_client_command_reply_free(cmd);
581 SILC_CLIENT_CMD_REPLY_FUNC(quit)
585 SILC_CLIENT_CMD_REPLY_FUNC(kill)
589 /* Received reply to INFO command. We receive the server ID and some
590 information about the server user requested. */
592 SILC_CLIENT_CMD_REPLY_FUNC(info)
594 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
595 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
596 SilcClient client = cmd->client;
597 SilcCommandStatus status;
600 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
601 SILC_GET16_MSB(status, tmp);
602 if (status != SILC_STATUS_OK) {
603 cmd->client->ops->say(cmd->client, conn,
604 "%s", silc_client_command_status_message(status));
606 silc_client_command_reply_free(cmd);
611 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
615 /* XXX save server id */
617 /* Get server info */
618 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
622 client->ops->say(cmd->client, conn, "Info: %s", tmp);
624 /* Notify application */
625 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
628 silc_client_command_reply_free(cmd);
631 SILC_CLIENT_CMD_REPLY_FUNC(connect)
635 /* Received reply to PING command. The reply time is shown to user. */
637 SILC_CLIENT_CMD_REPLY_FUNC(ping)
639 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
640 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
641 SilcCommandStatus status;
644 time_t diff, curtime;
646 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
647 if (status != SILC_STATUS_OK) {
648 cmd->client->ops->say(cmd->client, conn,
649 "%s", silc_client_command_status_message(status));
654 curtime = time(NULL);
655 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
657 for (i = 0; i < conn->ping_count; i++) {
658 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
659 diff = curtime - conn->ping[i].start_time;
660 cmd->client->ops->say(cmd->client, conn,
661 "Ping reply from %s: %d second%s",
662 conn->ping[i].dest_name, diff,
663 diff == 1 ? "" : "s");
665 conn->ping[i].start_time = 0;
666 silc_free(conn->ping[i].dest_id);
667 conn->ping[i].dest_id = NULL;
668 silc_free(conn->ping[i].dest_name);
669 conn->ping[i].dest_name = NULL;
671 /* Notify application */
672 COMMAND_REPLY((ARGS));
680 silc_client_command_reply_free(cmd);
683 SILC_CLIENT_CMD_REPLY_FUNC(oper)
687 /* Received reply for JOIN command. */
689 SILC_CLIENT_CMD_REPLY_FUNC(join)
691 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
692 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
693 SilcClient client = cmd->client;
694 SilcCommandStatus status;
695 SilcIDPayload idp = NULL;
696 unsigned int argc, mode, len;
697 char *topic, *tmp, *channel_name = NULL;
700 SILC_LOG_DEBUG(("Start"));
702 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
703 if (status != SILC_STATUS_OK) {
704 cmd->client->ops->say(cmd->client, conn,
705 "%s", silc_client_command_status_message(status));
710 argc = silc_argument_get_arg_num(cmd->args);
711 if (argc < 3 || argc > 9) {
712 cmd->client->ops->say(cmd->client, conn,
713 "Cannot join channel: Bad reply packet");
718 /* Get channel name */
719 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
721 cmd->client->ops->say(cmd->client, conn,
722 "Cannot join channel: Bad reply packet");
726 channel_name = strdup(tmp);
729 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
731 cmd->client->ops->say(cmd->client, conn,
732 "Cannot join channel: Bad reply packet");
734 silc_free(channel_name);
737 idp = silc_id_payload_parse_data(tmp, len);
739 /* Get channel mode */
740 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
742 SILC_GET32_MSB(mode, tmp);
746 /* Get channel key */
747 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
749 silc_id_payload_free(idp);
750 silc_free(channel_name);
753 keyp = silc_buffer_alloc(len);
754 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
755 silc_buffer_put(keyp, tmp, len);
758 topic = silc_argument_get_arg_type(cmd->args, 8, NULL);
760 /* Save received Channel ID */
761 silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
763 silc_id_payload_free(idp);
765 /* Save channel key */
766 silc_client_save_channel_key(conn, keyp, conn->current_channel);
767 silc_buffer_free(keyp);
770 client->ops->say(cmd->client, conn,
771 "Topic for %s: %s", channel_name, topic);
773 /* Notify application */
774 COMMAND_REPLY((ARGS, channel_name, conn->current_channel, mode,
778 silc_client_command_reply_free(cmd);
781 /* Received reply for MOTD command */
783 SILC_CLIENT_CMD_REPLY_FUNC(motd)
785 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
786 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
787 SilcCommandStatus status;
788 unsigned int argc, i;
790 char *motd = NULL, *cp, line[256];
792 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
793 SILC_GET16_MSB(status, tmp);
794 if (status != SILC_STATUS_OK) {
795 cmd->client->ops->say(cmd->client, conn,
796 "%s", silc_client_command_status_message(status));
801 argc = silc_argument_get_arg_num(cmd->args);
808 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
817 if (cp[i++] == '\n') {
818 memset(line, 0, sizeof(line));
819 strncat(line, cp, i - 1);
825 cmd->client->ops->say(cmd->client, conn, "%s", line);
834 /* Notify application */
835 COMMAND_REPLY((ARGS, motd));
838 silc_client_command_reply_free(cmd);
841 SILC_CLIENT_CMD_REPLY_FUNC(umode)
845 /* Received reply for CMODE command. */
847 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
849 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
850 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
851 SilcCommandStatus status;
854 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
855 if (status != SILC_STATUS_OK) {
856 cmd->client->ops->say(cmd->client, conn,
857 "%s", silc_client_command_status_message(status));
862 /* Get channel mode */
863 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
869 /* Notify application */
870 COMMAND_REPLY((ARGS, tmp));
873 silc_client_command_reply_free(cmd);
876 /* Received reply for CUMODE command */
878 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
880 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
881 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
882 SilcCommandStatus status;
883 SilcIDCacheEntry id_cache = NULL;
884 SilcClientID *client_id;
885 unsigned char *tmp, *id;
888 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
889 if (status != SILC_STATUS_OK) {
890 cmd->client->ops->say(cmd->client, conn,
891 "%s", silc_client_command_status_message(status));
896 /* Get channel mode */
897 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
904 id = silc_argument_get_arg_type(cmd->args, 3, &len);
909 client_id = silc_id_payload_parse_id(id, len);
911 /* Get client entry */
912 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
913 SILC_ID_CLIENT, &id_cache)) {
918 /* Notify application */
919 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
920 silc_free(client_id);
923 silc_client_command_reply_free(cmd);
926 SILC_CLIENT_CMD_REPLY_FUNC(kick)
930 SILC_CLIENT_CMD_REPLY_FUNC(restart)
934 SILC_CLIENT_CMD_REPLY_FUNC(close)
938 SILC_CLIENT_CMD_REPLY_FUNC(die)
942 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
946 /* Reply to LEAVE command. */
948 SILC_CLIENT_CMD_REPLY_FUNC(leave)
950 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
951 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
952 SilcCommandStatus status;
955 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
956 SILC_GET16_MSB(status, tmp);
957 if (status != SILC_STATUS_OK) {
958 cmd->client->ops->say(cmd->client, conn,
959 "%s", silc_client_command_status_message(status));
964 /* Notify application */
965 COMMAND_REPLY((ARGS));
967 silc_client_command_reply_free(cmd);
970 /* Reply to USERS command. Received list of client ID's and theirs modes
971 on the channel we requested. */
973 SILC_CLIENT_CMD_REPLY_FUNC(users)
975 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
976 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
977 SilcCommandStatus status;
978 SilcIDCacheEntry id_cache = NULL;
979 SilcChannelEntry channel;
981 SilcChannelID *channel_id = NULL;
982 SilcBuffer client_id_list;
983 SilcBuffer client_mode_list;
985 unsigned int tmp_len;
986 int i, k, len1, len2, list_count;
987 unsigned char **res_argv = NULL;
988 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
989 char *name_list, *cp;
991 SILC_LOG_DEBUG(("Start"));
993 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
994 SILC_GET16_MSB(status, tmp);
995 if (status != SILC_STATUS_OK) {
996 cmd->client->ops->say(cmd->client, conn,
997 "%s", silc_client_command_status_message(status));
1002 /* Get channel ID */
1003 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1006 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1008 /* Get the list count */
1009 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1012 SILC_GET32_MSB(list_count, tmp);
1014 /* Get Client ID list */
1015 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1019 client_id_list = silc_buffer_alloc(tmp_len);
1020 silc_buffer_pull_tail(client_id_list, tmp_len);
1021 silc_buffer_put(client_id_list, tmp, tmp_len);
1023 /* Get client mode list */
1024 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1028 client_mode_list = silc_buffer_alloc(tmp_len);
1029 silc_buffer_pull_tail(client_mode_list, tmp_len);
1030 silc_buffer_put(client_mode_list, tmp, tmp_len);
1032 /* Get channel entry */
1033 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1034 SILC_ID_CHANNEL, &id_cache)) {
1035 COMMAND_REPLY_ERROR;
1038 channel = (SilcChannelEntry)id_cache->context;
1040 /* Remove old client list from channel. */
1041 silc_list_start(channel->clients);
1042 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1043 silc_list_del(channel->clients, chu);
1047 /* Cache the received Client ID's and modes. This cache expires
1048 whenever server sends notify message to channel. It means two things;
1049 some user has joined or leaved the channel. XXX! */
1050 for (i = 0; i < list_count; i++) {
1051 unsigned short idp_len;
1053 SilcClientID *client_id;
1054 SilcClientEntry client;
1057 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1059 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1060 silc_buffer_pull(client_id_list, idp_len);
1063 SILC_GET32_MSB(mode, client_mode_list->data);
1064 silc_buffer_pull(client_mode_list, 4);
1066 /* Check if we have this client cached already. */
1067 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1068 SILC_ID_CLIENT, &id_cache)) {
1069 /* No we don't have it, query it from the server. Assemble argument
1070 table that will be sent fr the IDENTIFY command later. */
1071 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1073 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1075 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1077 res_argv[res_argc] = client_id_list->data;
1078 res_argv_lens[res_argc] = idp_len;
1079 res_argv_types[res_argc] = res_argc + 3;
1082 /* Found the client, join it to the channel */
1083 client = (SilcClientEntry)id_cache->context;
1084 chu = silc_calloc(1, sizeof(*chu));
1085 chu->client = client;
1087 silc_list_add(channel->clients, chu);
1089 silc_free(client_id);
1094 /* Query the client information from server if the list included clients
1095 that we don't know about. */
1100 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1101 res_argc, res_argv, res_argv_lens,
1103 silc_client_packet_send(cmd->client, cmd->conn->sock,
1104 SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
1105 buffer->data, buffer->len, TRUE);
1111 for (i = 0; i < list_count; i++) {
1113 int nick_len = strcspn(name_list, " ");
1114 char *nickname = silc_calloc(nick_len + 1, sizeof(*nickname));
1115 memcpy(nickname, name_list, nick_len);
1117 silc_list_start(channel->clients);
1118 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1119 if (!strncmp(chu->client->nickname, nickname,
1120 strlen(chu->client->nickname))) {
1128 memset(t, 0, sizeof(t));
1129 chu->client->nickname = silc_calloc(strlen(nickname) + 8, 1);
1130 snprintf(t, sizeof(t), "[%d]", c++);
1131 strncat(chu->client->nickname, t, strlen(t));
1132 strncat(chu->client->nickname, nickname, strlen(nickname));
1136 silc_free(nickname);
1139 /* XXX hmm... actually it is applications business to display this
1140 information. We should just pass (as we do) the data to application and
1141 let it to parse it and display it the way it wants. */
1142 if (cmd->callback) {
1143 cmd->client->ops->say(cmd->client, conn, "Users on %s",
1144 channel->channel_name);
1146 silc_list_start(channel->clients);
1147 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1148 SilcClientEntry e = chu->client;
1149 char *m, tmp[80], line[80];
1151 memset(line, 0, sizeof(line));
1152 memset(tmp, 0, sizeof(tmp));
1153 m = silc_client_chumode_char(chu->mode);
1156 strcat(line, e->nickname);
1157 strcat(line, e->server ? "@" : "");
1161 len1 = strlen(e->server);
1162 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1164 len1 = strlen(line);
1166 memset(&line[29], 0, len1 - 29);
1168 for (i = 0; i < 30 - len1 - 1; i++)
1173 strcat(tmp, m ? m : "");
1176 if (strlen(tmp) < 5)
1177 for (i = 0; i < 5 - strlen(tmp); i++)
1180 strcat(line, e->username ? e->username : "");
1182 cmd->client->ops->say(cmd->client, conn, "%s", line);
1193 silc_list_start(channel->clients);
1194 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1195 char *m, *n = chu->client->nickname;
1199 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
1201 m = silc_client_chumode_char(chu->mode);
1203 memcpy(name_list + (len1 - len2), m, strlen(m));
1208 memcpy(name_list + (len1 - len2), n, len2);
1209 name_list[len1] = 0;
1211 if (k == silc_list_count(channel->clients) - 1)
1213 memcpy(name_list + len1, " ", 1);
1218 cmd->client->ops->say(cmd->client, conn, "Users on %s: %s",
1219 channel->channel_name, name_list);
1220 silc_free(name_list);
1223 name_list = silc_argument_get_arg_type(cmd->args, 3, &len1);
1225 /* Notify application */
1226 COMMAND_REPLY((ARGS, channel, name_list, client_id_list->head,
1227 client_mode_list->head));
1229 silc_buffer_free(client_id_list);
1230 silc_buffer_free(client_mode_list);
1234 silc_free(channel_id);
1235 silc_client_command_reply_free(cmd);