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(names, NAMES),
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 silc_free(client_id);
271 cmd->client->ops->say(cmd->client, conn, "%s", buf);
273 /* Notify application */
274 COMMAND_REPLY((ARGS, client_entry, nickname,
275 username, realname, NULL, NULL));
278 /* Received reply for WHOIS command. This maybe called several times
279 for one WHOIS command as server may reply with list of results. */
281 SILC_CLIENT_CMD_REPLY_FUNC(whois)
283 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
284 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
285 SilcCommandStatus status;
288 SILC_LOG_DEBUG(("Start"));
290 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
291 SILC_GET16_MSB(status, tmp);
292 if (status != SILC_STATUS_OK &&
293 status != SILC_STATUS_LIST_START &&
294 status != SILC_STATUS_LIST_ITEM &&
295 status != SILC_STATUS_LIST_END) {
296 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
297 /* Take nickname which may be provided */
298 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
300 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
301 silc_client_command_status_message(status));
303 cmd->client->ops->say(cmd->client, conn, "%s",
304 silc_client_command_status_message(status));
308 cmd->client->ops->say(cmd->client, conn,
309 "%s", silc_client_command_status_message(status));
315 /* Display one whois reply */
316 if (status == SILC_STATUS_OK) {
317 silc_client_command_reply_whois_print(cmd, status);
320 /* XXX list should not be displayed untill all items has been received. */
321 if (status == SILC_STATUS_LIST_START) {
322 silc_client_command_reply_whois_print(cmd, status);
325 if (status == SILC_STATUS_LIST_ITEM) {
326 silc_client_command_reply_whois_print(cmd, status);
329 if (status == SILC_STATUS_LIST_END) {
330 silc_client_command_reply_whois_print(cmd, status);
333 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
336 silc_client_command_reply_free(cmd);
339 /* Received reply for WHOWAS command. */
341 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
346 /* Received reply for IDENTIFY command. This maybe called several times
347 for one IDENTIFY command as server may reply with list of results.
348 This is totally silent and does not print anything on screen. */
350 SILC_CLIENT_CMD_REPLY_FUNC(identify)
352 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
353 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
354 SilcClientEntry client_entry;
355 SilcIDCacheEntry id_cache = NULL;
356 SilcCommandStatus status;
359 SILC_LOG_DEBUG(("Start"));
361 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
362 SILC_GET16_MSB(status, tmp);
363 if (status != SILC_STATUS_OK) {
364 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
365 /* Take nickname which may be provided */
366 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
368 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
369 silc_client_command_status_message(status));
371 cmd->client->ops->say(cmd->client, conn, "%s",
372 silc_client_command_status_message(status));
376 cmd->client->ops->say(cmd->client, conn,
377 "%s", silc_client_command_status_message(status));
383 /* Display one whois reply */
384 if (status == SILC_STATUS_OK) {
386 unsigned char *id_data;
389 SilcClientID *client_id;
391 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
394 client_id = silc_id_payload_parse_id(id_data, len);
396 nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
397 username = silc_argument_get_arg_type(cmd->args, 4, NULL);
399 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
400 SILC_ID_CLIENT, &id_cache)) {
401 client_entry = silc_calloc(1, sizeof(*client_entry));
402 client_entry->id = client_id;
403 silc_parse_nickname(nickname, &client_entry->nickname,
404 &client_entry->server, &client_entry->num);
406 client_entry->username = strdup(username);
408 /* Add client to cache */
409 silc_idcache_add(conn->client_cache, client_entry->nickname,
410 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
412 client_entry = (SilcClientEntry)id_cache->context;
413 if (client_entry->nickname)
414 silc_free(client_entry->nickname);
415 if (client_entry->server)
416 silc_free(client_entry->server);
417 if (username && client_entry->username)
418 silc_free(client_entry->username);
420 silc_parse_nickname(nickname, &client_entry->nickname,
421 &client_entry->server, &client_entry->num);
424 client_entry->username = strdup(username);
425 silc_free(client_id);
429 if (status == SILC_STATUS_LIST_START) {
433 if (status == SILC_STATUS_LIST_END) {
437 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
440 silc_client_command_reply_free(cmd);
443 /* Received reply for command NICK. If everything went without errors
444 we just received our new Client ID. */
446 SILC_CLIENT_CMD_REPLY_FUNC(nick)
448 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
449 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
450 SilcCommandStatus status;
453 unsigned int argc, len;
455 SILC_LOG_DEBUG(("Start"));
457 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
458 if (status != SILC_STATUS_OK) {
459 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
460 silc_client_command_status_message(status));
465 argc = silc_argument_get_arg_num(cmd->args);
466 if (argc < 2 || argc > 2) {
467 cmd->client->ops->say(cmd->client, conn,
468 "Cannot set nickname: bad reply to command");
473 /* Take received Client ID */
474 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
475 idp = silc_id_payload_parse_data(tmp, len);
476 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
478 /* Notify application */
479 COMMAND_REPLY((ARGS, conn->local_entry));
482 silc_client_command_reply_free(cmd);
485 SILC_CLIENT_CMD_REPLY_FUNC(list)
489 /* Received reply to topic command. */
491 SILC_CLIENT_CMD_REPLY_FUNC(topic)
493 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
494 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
495 SilcCommandStatus status;
496 SilcChannelEntry channel;
497 SilcChannelID *channel_id = NULL;
498 SilcIDCacheEntry id_cache = NULL;
501 unsigned int argc, len;
503 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
504 if (status != SILC_STATUS_OK) {
505 cmd->client->ops->say(cmd->client, conn,
506 "%s", silc_client_command_status_message(status));
508 silc_client_command_reply_free(cmd);
512 argc = silc_argument_get_arg_num(cmd->args);
513 if (argc < 1 || argc > 3) {
518 /* Take Channel ID */
519 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
524 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
528 channel_id = silc_id_payload_parse_id(tmp, len);
530 /* Get the channel name */
531 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
532 SILC_ID_CHANNEL, &id_cache)) {
533 silc_free(channel_id);
538 channel = (SilcChannelEntry)id_cache->context;
540 cmd->client->ops->say(cmd->client, conn,
541 "Topic on channel %s: %s", channel->channel_name,
544 /* Notify application */
545 COMMAND_REPLY((ARGS, channel, topic));
548 silc_client_command_reply_free(cmd);
551 /* Received reply to invite command. */
553 SILC_CLIENT_CMD_REPLY_FUNC(invite)
555 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
556 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
557 SilcCommandStatus status;
560 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
561 SILC_GET16_MSB(status, tmp);
562 if (status != SILC_STATUS_OK) {
563 cmd->client->ops->say(cmd->client, conn,
564 "%s", silc_client_command_status_message(status));
566 silc_client_command_reply_free(cmd);
570 /* Notify application */
571 COMMAND_REPLY((ARGS));
573 silc_client_command_reply_free(cmd);
576 SILC_CLIENT_CMD_REPLY_FUNC(quit)
580 SILC_CLIENT_CMD_REPLY_FUNC(kill)
584 /* Received reply to INFO command. We receive the server ID and some
585 information about the server user requested. */
587 SILC_CLIENT_CMD_REPLY_FUNC(info)
589 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
590 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
591 SilcClient client = cmd->client;
592 SilcCommandStatus status;
595 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
596 SILC_GET16_MSB(status, tmp);
597 if (status != SILC_STATUS_OK) {
598 cmd->client->ops->say(cmd->client, conn,
599 "%s", silc_client_command_status_message(status));
601 silc_client_command_reply_free(cmd);
606 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
610 /* XXX save server id */
612 /* Get server info */
613 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
617 client->ops->say(cmd->client, conn, "Info: %s", tmp);
619 /* Notify application */
620 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
623 silc_client_command_reply_free(cmd);
626 SILC_CLIENT_CMD_REPLY_FUNC(connect)
630 /* Received reply to PING command. The reply time is shown to user. */
632 SILC_CLIENT_CMD_REPLY_FUNC(ping)
634 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
635 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
636 SilcCommandStatus status;
639 time_t diff, curtime;
641 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
642 if (status != SILC_STATUS_OK) {
643 cmd->client->ops->say(cmd->client, conn,
644 "%s", silc_client_command_status_message(status));
649 curtime = time(NULL);
650 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
652 for (i = 0; i < conn->ping_count; i++) {
653 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
654 diff = curtime - conn->ping[i].start_time;
655 cmd->client->ops->say(cmd->client, conn,
656 "Ping reply from %s: %d second%s",
657 conn->ping[i].dest_name, diff,
658 diff == 1 ? "" : "s");
660 conn->ping[i].start_time = 0;
661 silc_free(conn->ping[i].dest_id);
662 conn->ping[i].dest_id = NULL;
663 silc_free(conn->ping[i].dest_name);
664 conn->ping[i].dest_name = NULL;
666 /* Notify application */
667 COMMAND_REPLY((ARGS));
675 silc_client_command_reply_free(cmd);
678 SILC_CLIENT_CMD_REPLY_FUNC(oper)
682 /* Received reply for JOIN command. */
684 SILC_CLIENT_CMD_REPLY_FUNC(join)
686 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
687 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
688 SilcClient client = cmd->client;
689 SilcCommandStatus status;
691 unsigned int argc, mode, len;
692 char *topic, *tmp, *channel_name;
694 SILC_LOG_DEBUG(("Start"));
696 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
697 if (status != SILC_STATUS_OK) {
698 cmd->client->ops->say(cmd->client, conn,
699 "%s", silc_client_command_status_message(status));
704 argc = silc_argument_get_arg_num(cmd->args);
705 if (argc < 3 || argc > 5) {
706 cmd->client->ops->say(cmd->client, conn,
707 "Cannot join channel: Bad reply packet");
712 /* Get channel name */
713 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
715 cmd->client->ops->say(cmd->client, conn,
716 "Cannot join channel: Bad reply packet");
720 channel_name = strdup(tmp);
723 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
725 cmd->client->ops->say(cmd->client, conn,
726 "Cannot join channel: Bad reply packet");
730 idp = silc_id_payload_parse_data(tmp, len);
732 /* Get channel mode */
733 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
735 SILC_GET32_MSB(mode, tmp);
740 topic = silc_argument_get_arg_type(cmd->args, 5, NULL);
742 /* Save received Channel ID */
743 silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
745 silc_id_payload_free(idp);
748 client->ops->say(cmd->client, conn,
749 "Topic for %s: %s", channel_name, topic);
751 /* Notify application */
752 COMMAND_REPLY((ARGS, channel_name, conn->current_channel, mode,
756 silc_client_command_reply_free(cmd);
759 /* Received reply for MOTD command */
761 SILC_CLIENT_CMD_REPLY_FUNC(motd)
763 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
764 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
765 SilcCommandStatus status;
766 unsigned int argc, i;
768 char *motd = NULL, *cp, line[256];
770 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
771 SILC_GET16_MSB(status, tmp);
772 if (status != SILC_STATUS_OK) {
773 cmd->client->ops->say(cmd->client, conn,
774 "%s", silc_client_command_status_message(status));
779 argc = silc_argument_get_arg_num(cmd->args);
786 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
795 if (cp[i++] == '\n') {
796 memset(line, 0, sizeof(line));
797 strncat(line, cp, i - 1);
803 cmd->client->ops->say(cmd->client, conn, "%s", line);
812 /* Notify application */
813 COMMAND_REPLY((ARGS, motd));
816 silc_client_command_reply_free(cmd);
819 SILC_CLIENT_CMD_REPLY_FUNC(umode)
823 /* Received reply for CMODE command. */
825 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
827 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
828 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
829 SilcCommandStatus status;
832 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
833 if (status != SILC_STATUS_OK) {
834 cmd->client->ops->say(cmd->client, conn,
835 "%s", silc_client_command_status_message(status));
840 /* Get channel mode */
841 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
847 /* Notify application */
848 COMMAND_REPLY((ARGS, tmp));
851 silc_client_command_reply_free(cmd);
854 /* Received reply for CUMODE command */
856 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
858 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
859 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
860 SilcCommandStatus status;
861 SilcIDCacheEntry id_cache = NULL;
862 SilcClientID *client_id;
863 unsigned char *tmp, *id;
866 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
867 if (status != SILC_STATUS_OK) {
868 cmd->client->ops->say(cmd->client, conn,
869 "%s", silc_client_command_status_message(status));
874 /* Get channel mode */
875 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
882 id = silc_argument_get_arg_type(cmd->args, 3, &len);
887 client_id = silc_id_payload_parse_id(id, len);
889 /* Get client entry */
890 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
891 SILC_ID_CLIENT, &id_cache)) {
896 /* Notify application */
897 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
898 silc_free(client_id);
901 silc_client_command_reply_free(cmd);
904 SILC_CLIENT_CMD_REPLY_FUNC(kick)
908 SILC_CLIENT_CMD_REPLY_FUNC(restart)
912 SILC_CLIENT_CMD_REPLY_FUNC(close)
916 SILC_CLIENT_CMD_REPLY_FUNC(die)
920 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
924 /* Reply to LEAVE command. */
926 SILC_CLIENT_CMD_REPLY_FUNC(leave)
928 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
929 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
930 SilcCommandStatus status;
933 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
934 SILC_GET16_MSB(status, tmp);
935 if (status != SILC_STATUS_OK) {
936 cmd->client->ops->say(cmd->client, conn,
937 "%s", silc_client_command_status_message(status));
942 /* Notify application */
943 COMMAND_REPLY((ARGS));
945 silc_client_command_reply_free(cmd);
948 /* Reply to NAMES command. Received list of client names on the channel
951 SILC_CLIENT_CMD_REPLY_FUNC(names)
953 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
954 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
955 SilcCommandStatus status;
956 SilcIDCacheEntry id_cache = NULL;
957 SilcChannelEntry channel;
958 SilcChannelID *channel_id = NULL;
959 SilcBuffer client_id_list;
960 SilcBuffer client_mode_list;
962 char *name_list, *cp;
963 int i, k, len1, len2, list_count = 0;
965 SILC_LOG_DEBUG(("Start"));
967 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
968 SILC_GET16_MSB(status, tmp);
969 if (status != SILC_STATUS_OK) {
970 cmd->client->ops->say(cmd->client, conn,
971 "%s", silc_client_command_status_message(status));
977 tmp = silc_argument_get_arg_type(cmd->args, 2, &len1);
979 cmd->client->ops->say(cmd->client, conn,
980 "Cannot Channel ID: Bad reply packet");
984 channel_id = silc_id_payload_parse_id(tmp, len1);
986 /* Get the name list of the channel */
987 name_list = silc_argument_get_arg_type(cmd->args, 3, &len1);
989 cmd->client->ops->say(cmd->client, conn,
990 "Cannot get user list: Bad reply packet");
995 /* Get Client ID list */
996 tmp = silc_argument_get_arg_type(cmd->args, 4, &len2);
998 cmd->client->ops->say(cmd->client, conn,
999 "Cannot get user list: Bad reply packet");
1000 COMMAND_REPLY_ERROR;
1004 client_id_list = silc_buffer_alloc(len2);
1005 silc_buffer_pull_tail(client_id_list, len2);
1006 silc_buffer_put(client_id_list, tmp, len2);
1008 /* Get client mode list */
1009 tmp = silc_argument_get_arg_type(cmd->args, 5, &len2);
1011 cmd->client->ops->say(cmd->client, conn,
1012 "Cannot get user list: Bad reply packet");
1013 COMMAND_REPLY_ERROR;
1017 client_mode_list = silc_buffer_alloc(len2);
1018 silc_buffer_pull_tail(client_mode_list, len2);
1019 silc_buffer_put(client_mode_list, tmp, len2);
1021 /* Get the channel name */
1022 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1023 SILC_ID_CHANNEL, &id_cache)) {
1024 COMMAND_REPLY_ERROR;
1028 channel = (SilcChannelEntry)id_cache->context;
1030 /* Remove commas from list */
1031 for (i = 0; i < len1; i++)
1032 if (name_list[i] == ',') {
1038 /* Remove old client list from channel, if exists */
1039 if (channel->clients) {
1040 silc_free(channel->clients);
1041 channel->clients = NULL;
1042 channel->clients_count = 0;
1045 /* Allocate room for clients in the channel */
1046 channel->clients = silc_calloc(list_count, sizeof(*channel->clients));
1048 /* Cache the received name list, client ID's and modes. This cache expires
1049 whenever server sends notify message to channel. It means two things;
1050 some user has joined or leaved the channel. */
1052 for (i = 0; i < list_count; i++) {
1053 int nick_len = strcspn(name_list, " ");
1054 unsigned short idp_len;
1056 char *nickname = silc_calloc(nick_len + 1, sizeof(*nickname));
1057 SilcClientID *client_id;
1058 SilcClientEntry client;
1060 memcpy(nickname, name_list, nick_len);
1061 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1063 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1064 silc_buffer_pull(client_id_list, idp_len);
1066 SILC_GET32_MSB(mode, client_mode_list->data);
1067 silc_buffer_pull(client_mode_list, 4);
1069 /* Check if we have this client cached already. */
1070 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1071 SILC_ID_CLIENT, &id_cache)) {
1072 client = silc_calloc(1, sizeof(*client));
1073 client->id = client_id;
1074 silc_parse_nickname(nickname, &client->nickname, &client->server,
1076 silc_free(nickname);
1078 /* Add client to cache */
1079 silc_idcache_add(conn->client_cache, client->nickname, SILC_ID_CLIENT,
1080 client_id, (void *)client, TRUE);
1082 client = (SilcClientEntry)id_cache->context;
1083 silc_free(client_id);
1084 silc_free(nickname);
1088 channel->clients[channel->clients_count].client = client;
1089 channel->clients[channel->clients_count].mode = mode;
1090 channel->clients_count++;
1092 name_list += nick_len + 1;
1096 for (i = 0; i < list_count; i++) {
1098 int nick_len = strcspn(name_list, " ");
1099 char *nickname = silc_calloc(nick_len + 1, sizeof(*nickname));
1100 memcpy(nickname, name_list, nick_len);
1102 for (c = 0, k = 0; k < channel->clients_count; k++) {
1103 if (channel->clients[k].client &&
1104 !strncmp(channel->clients[k].client->nickname,
1105 nickname, strlen(channel->clients[k].client->nickname))) {
1113 memset(t, 0, sizeof(t));
1114 channel->clients[k].client->nickname =
1115 silc_calloc(strlen(nickname) + 8, sizeof(*channel->clients[k].
1117 snprintf(t, sizeof(t), "[%d]", c++);
1118 strncat(channel->clients[k].client->nickname, t, strlen(t));
1119 strncat(channel->clients[k].client->nickname, nickname,
1124 silc_free(nickname);
1127 /* XXX hmm... actually it is applications business to display this
1128 information. We should just pass (as we do) the data to application and
1129 let it to parse it and display it the way it wants. */
1130 if (cmd->callback) {
1131 cmd->client->ops->say(cmd->client, conn, "Users on %s",
1132 channel->channel_name);
1134 for (k = 0; k < channel->clients_count; k++) {
1135 SilcClientEntry e = channel->clients[k].client;
1136 char *m, tmp[80], line[80];
1138 memset(line, 0, sizeof(line));
1139 memset(tmp, 0, sizeof(tmp));
1140 m = silc_client_chumode_char(channel->clients[k].mode);
1143 strcat(line, e->nickname);
1144 strcat(line, e->server ? "@" : "");
1148 len1 = strlen(e->server);
1149 strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
1151 len1 = strlen(line);
1153 memset(&line[29], 0, len1 - 29);
1155 for (i = 0; i < 30 - len1 - 1; i++)
1160 strcat(tmp, m ? m : "");
1163 if (strlen(tmp) < 5)
1164 for (i = 0; i < 5 - strlen(tmp); i++)
1167 strcat(line, e->username ? e->username : "");
1169 cmd->client->ops->say(cmd->client, conn, "%s", line);
1178 for (k = 0; k < channel->clients_count; k++) {
1179 char *m, *n = channel->clients[k].client->nickname;
1183 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
1185 m = silc_client_chumode_char(channel->clients[k].mode);
1187 memcpy(name_list + (len1 - len2), m, strlen(m));
1192 memcpy(name_list + (len1 - len2), n, len2);
1193 name_list[len1] = 0;
1195 if (k == channel->clients_count - 1)
1197 memcpy(name_list + len1, " ", 1);
1201 cmd->client->ops->say(cmd->client, conn,
1202 "Users on %s: %s", channel->channel_name, name_list);
1203 silc_free(name_list);
1206 name_list = silc_argument_get_arg_type(cmd->args, 3, &len1);
1208 /* Notify application */
1209 COMMAND_REPLY((ARGS, channel, name_list, client_id_list->head,
1210 client_mode_list->head));
1212 silc_buffer_free(client_id_list);
1213 silc_buffer_free(client_mode_list);
1217 silc_free(channel_id);
1218 silc_client_command_reply_free(cmd);