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);
237 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
239 strncat(buf, nickname, len);
240 strncat(buf, " is ", 4);
243 username = silc_argument_get_arg_type(cmd->args, 4, &len);
245 strncat(buf, username, len);
248 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
250 strncat(buf, " (", 2);
251 strncat(buf, realname, len);
252 strncat(buf, ")", 1);
255 /* Check if we have this client cached already. */
256 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
257 SILC_ID_CLIENT, &id_cache)) {
258 client_entry = silc_calloc(1, sizeof(*client_entry));
259 client_entry->id = client_id;
260 silc_parse_nickname(nickname, &client_entry->nickname,
261 &client_entry->server, &client_entry->num);
262 client_entry->username = strdup(username);
264 client_entry->realname = strdup(realname);
266 /* Add client to cache */
267 silc_idcache_add(conn->client_cache, client_entry->nickname,
268 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
270 client_entry = (SilcClientEntry)id_cache->context;
271 if (client_entry->nickname)
272 silc_free(client_entry->nickname);
273 if (client_entry->server)
274 silc_free(client_entry->server);
275 if (client_entry->username)
276 silc_free(client_entry->username);
277 if (client_entry->realname)
278 silc_free(client_entry->realname);
280 silc_parse_nickname(nickname, &client_entry->nickname,
281 &client_entry->server, &client_entry->num);
282 client_entry->username = strdup(username);
284 client_entry->realname = strdup(realname);
286 id_cache->data = client_entry->nickname;
287 silc_idcache_sort_by_data(conn->client_cache);
289 silc_free(client_id);
293 cmd->client->ops->say(cmd->client, conn, "%s", buf);
295 /* Notify application */
296 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
300 /* Received reply for WHOIS command. This maybe called several times
301 for one WHOIS command as server may reply with list of results. */
303 SILC_CLIENT_CMD_REPLY_FUNC(whois)
305 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
306 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
307 SilcCommandStatus status;
310 SILC_LOG_DEBUG(("Start"));
312 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
313 SILC_GET16_MSB(status, tmp);
314 if (status != SILC_STATUS_OK &&
315 status != SILC_STATUS_LIST_START &&
316 status != SILC_STATUS_LIST_ITEM &&
317 status != SILC_STATUS_LIST_END) {
318 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
319 /* Take nickname which may be provided */
320 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
322 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
323 silc_client_command_status_message(status));
325 cmd->client->ops->say(cmd->client, conn, "%s",
326 silc_client_command_status_message(status));
330 cmd->client->ops->say(cmd->client, conn,
331 "%s", silc_client_command_status_message(status));
337 /* Display one whois reply */
338 if (status == SILC_STATUS_OK) {
339 silc_client_command_reply_whois_print(cmd, status);
342 /* XXX list should not be displayed untill all items has been received. */
343 if (status == SILC_STATUS_LIST_START) {
344 silc_client_command_reply_whois_print(cmd, status);
347 if (status == SILC_STATUS_LIST_ITEM) {
348 silc_client_command_reply_whois_print(cmd, status);
351 if (status == SILC_STATUS_LIST_END) {
352 silc_client_command_reply_whois_print(cmd, status);
355 /* Execute any pending command callbacks */
356 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
359 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
360 silc_client_command_reply_free(cmd);
363 /* Received reply for WHOWAS command. */
365 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
370 /* Received reply for IDENTIFY command. This maybe called several times
371 for one IDENTIFY command as server may reply with list of results.
372 This is totally silent and does not print anything on screen. */
374 SILC_CLIENT_CMD_REPLY_FUNC(identify)
376 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
377 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
378 SilcClientEntry client_entry;
379 SilcIDCacheEntry id_cache = NULL;
380 SilcCommandStatus status;
383 SILC_LOG_DEBUG(("Start"));
385 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
386 SILC_GET16_MSB(status, tmp);
387 if (status != SILC_STATUS_OK) {
388 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
389 /* Take nickname which may be provided */
390 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
392 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
393 silc_client_command_status_message(status));
395 cmd->client->ops->say(cmd->client, conn, "%s",
396 silc_client_command_status_message(status));
400 cmd->client->ops->say(cmd->client, conn,
401 "%s", silc_client_command_status_message(status));
407 /* Display one whois reply */
408 if (status == SILC_STATUS_OK) {
410 unsigned char *id_data;
413 SilcClientID *client_id;
415 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
418 client_id = silc_id_payload_parse_id(id_data, len);
422 nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
423 username = silc_argument_get_arg_type(cmd->args, 4, NULL);
425 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
426 SILC_ID_CLIENT, &id_cache)) {
427 client_entry = silc_calloc(1, sizeof(*client_entry));
428 client_entry->id = client_id;
429 silc_parse_nickname(nickname, &client_entry->nickname,
430 &client_entry->server, &client_entry->num);
432 client_entry->username = strdup(username);
434 /* Add client to cache */
435 silc_idcache_add(conn->client_cache, client_entry->nickname,
436 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
438 client_entry = (SilcClientEntry)id_cache->context;
439 if (client_entry->nickname)
440 silc_free(client_entry->nickname);
441 if (client_entry->server)
442 silc_free(client_entry->server);
443 if (username && client_entry->username)
444 silc_free(client_entry->username);
446 silc_parse_nickname(nickname, &client_entry->nickname,
447 &client_entry->server, &client_entry->num);
450 client_entry->username = strdup(username);
452 id_cache->data = client_entry->nickname;
453 silc_idcache_sort_by_data(conn->client_cache);
455 silc_free(client_id);
459 if (status == SILC_STATUS_LIST_START) {
463 if (status == SILC_STATUS_LIST_END) {
467 /* Execute any pending command callbacks */
468 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
471 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
472 silc_client_command_reply_free(cmd);
475 /* Received reply for command NICK. If everything went without errors
476 we just received our new Client ID. */
478 SILC_CLIENT_CMD_REPLY_FUNC(nick)
480 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
481 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
482 SilcCommandStatus status;
485 unsigned int argc, len;
487 SILC_LOG_DEBUG(("Start"));
489 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
490 if (status != SILC_STATUS_OK) {
491 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
492 silc_client_command_status_message(status));
497 argc = silc_argument_get_arg_num(cmd->args);
498 if (argc < 2 || argc > 2) {
499 cmd->client->ops->say(cmd->client, conn,
500 "Cannot set nickname: bad reply to command");
505 /* Take received Client ID */
506 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
507 idp = silc_id_payload_parse_data(tmp, len);
512 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
514 /* Notify application */
515 COMMAND_REPLY((ARGS, conn->local_entry));
517 /* Execute any pending command callbacks */
518 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
521 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
522 silc_client_command_reply_free(cmd);
525 SILC_CLIENT_CMD_REPLY_FUNC(list)
529 /* Received reply to topic command. */
531 SILC_CLIENT_CMD_REPLY_FUNC(topic)
533 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
534 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
535 SilcCommandStatus status;
536 SilcChannelEntry channel;
537 SilcChannelID *channel_id = NULL;
538 SilcIDCacheEntry id_cache = NULL;
541 unsigned int argc, len;
543 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
544 if (status != SILC_STATUS_OK) {
545 cmd->client->ops->say(cmd->client, conn,
546 "%s", silc_client_command_status_message(status));
548 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
549 silc_client_command_reply_free(cmd);
553 argc = silc_argument_get_arg_num(cmd->args);
554 if (argc < 1 || argc > 3) {
559 /* Take Channel ID */
560 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
565 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
569 channel_id = silc_id_payload_parse_id(tmp, len);
573 /* Get the channel name */
574 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
575 SILC_ID_CHANNEL, &id_cache)) {
576 silc_free(channel_id);
581 channel = (SilcChannelEntry)id_cache->context;
583 cmd->client->ops->say(cmd->client, conn,
584 "Topic on channel %s: %s", channel->channel_name,
587 /* Notify application */
588 COMMAND_REPLY((ARGS, channel, topic));
590 /* Execute any pending command callbacks */
591 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
594 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
595 silc_client_command_reply_free(cmd);
598 /* Received reply to invite command. */
600 SILC_CLIENT_CMD_REPLY_FUNC(invite)
602 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
603 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
604 SilcCommandStatus status;
607 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
608 SILC_GET16_MSB(status, tmp);
609 if (status != SILC_STATUS_OK) {
610 cmd->client->ops->say(cmd->client, conn,
611 "%s", silc_client_command_status_message(status));
613 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
614 silc_client_command_reply_free(cmd);
618 /* Notify application */
619 COMMAND_REPLY((ARGS));
621 /* Execute any pending command callbacks */
622 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
624 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
625 silc_client_command_reply_free(cmd);
628 SILC_CLIENT_CMD_REPLY_FUNC(quit)
632 SILC_CLIENT_CMD_REPLY_FUNC(kill)
636 /* Received reply to INFO command. We receive the server ID and some
637 information about the server user requested. */
639 SILC_CLIENT_CMD_REPLY_FUNC(info)
641 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
642 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
643 SilcClient client = cmd->client;
644 SilcCommandStatus status;
647 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
648 SILC_GET16_MSB(status, tmp);
649 if (status != SILC_STATUS_OK) {
650 cmd->client->ops->say(cmd->client, conn,
651 "%s", silc_client_command_status_message(status));
653 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
654 silc_client_command_reply_free(cmd);
659 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
663 /* XXX save server id */
665 /* Get server info */
666 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
670 client->ops->say(cmd->client, conn, "Info: %s", tmp);
672 /* Notify application */
673 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
675 /* Execute any pending command callbacks */
676 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
679 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
680 silc_client_command_reply_free(cmd);
683 SILC_CLIENT_CMD_REPLY_FUNC(connect)
687 /* Received reply to PING command. The reply time is shown to user. */
689 SILC_CLIENT_CMD_REPLY_FUNC(ping)
691 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
692 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
693 SilcCommandStatus status;
696 time_t diff, curtime;
698 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
699 if (status != SILC_STATUS_OK) {
700 cmd->client->ops->say(cmd->client, conn,
701 "%s", silc_client_command_status_message(status));
706 curtime = time(NULL);
707 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
708 cmd->packet->src_id_type);
714 for (i = 0; i < conn->ping_count; i++) {
715 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
716 diff = curtime - conn->ping[i].start_time;
717 cmd->client->ops->say(cmd->client, conn,
718 "Ping reply from %s: %d second%s",
719 conn->ping[i].dest_name, diff,
720 diff == 1 ? "" : "s");
722 conn->ping[i].start_time = 0;
723 silc_free(conn->ping[i].dest_id);
724 conn->ping[i].dest_id = NULL;
725 silc_free(conn->ping[i].dest_name);
726 conn->ping[i].dest_name = NULL;
733 /* Notify application */
734 COMMAND_REPLY((ARGS));
736 /* Execute any pending command callbacks */
737 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
740 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
741 silc_client_command_reply_free(cmd);
744 SILC_CLIENT_CMD_REPLY_FUNC(oper)
748 /* Received reply for JOIN command. */
750 SILC_CLIENT_CMD_REPLY_FUNC(join)
752 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
753 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
754 SilcClient client = cmd->client;
755 SilcCommandStatus status;
756 SilcIDPayload idp = NULL;
757 unsigned int argc, mode, len;
758 char *topic, *tmp, *channel_name = NULL;
761 SILC_LOG_DEBUG(("Start"));
763 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
764 if (status != SILC_STATUS_OK) {
765 cmd->client->ops->say(cmd->client, conn,
766 "%s", silc_client_command_status_message(status));
771 argc = silc_argument_get_arg_num(cmd->args);
772 if (argc < 3 || argc > 9) {
773 cmd->client->ops->say(cmd->client, conn,
774 "Cannot join channel: Bad reply packet");
779 /* Get channel name */
780 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
782 cmd->client->ops->say(cmd->client, conn,
783 "Cannot join channel: Bad reply packet");
787 channel_name = strdup(tmp);
790 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
792 cmd->client->ops->say(cmd->client, conn,
793 "Cannot join channel: Bad reply packet");
795 silc_free(channel_name);
798 idp = silc_id_payload_parse_data(tmp, len);
801 silc_free(channel_name);
805 /* Get channel mode */
806 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
808 SILC_GET32_MSB(mode, tmp);
812 /* Get channel key */
813 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
815 silc_id_payload_free(idp);
816 silc_free(channel_name);
819 keyp = silc_buffer_alloc(len);
820 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
821 silc_buffer_put(keyp, tmp, len);
824 topic = silc_argument_get_arg_type(cmd->args, 8, NULL);
826 /* Save received Channel ID */
827 silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
829 silc_id_payload_free(idp);
831 /* Save channel key */
832 silc_client_save_channel_key(conn, keyp, conn->current_channel);
833 silc_buffer_free(keyp);
836 client->ops->say(cmd->client, conn,
837 "Topic for %s: %s", channel_name, topic);
839 /* Notify application */
840 COMMAND_REPLY((ARGS, channel_name, conn->current_channel, mode,
843 /* Execute any pending command callbacks */
844 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
847 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
848 silc_client_command_reply_free(cmd);
851 /* Received reply for MOTD command */
853 SILC_CLIENT_CMD_REPLY_FUNC(motd)
855 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
856 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
857 SilcCommandStatus status;
858 unsigned int argc, i;
860 char *motd = NULL, *cp, line[256];
862 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
863 SILC_GET16_MSB(status, tmp);
864 if (status != SILC_STATUS_OK) {
865 cmd->client->ops->say(cmd->client, conn,
866 "%s", silc_client_command_status_message(status));
871 argc = silc_argument_get_arg_num(cmd->args);
878 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
887 if (cp[i++] == '\n') {
888 memset(line, 0, sizeof(line));
889 strncat(line, cp, i - 1);
895 cmd->client->ops->say(cmd->client, conn, "%s", line);
904 /* Notify application */
905 COMMAND_REPLY((ARGS, motd));
907 /* Execute any pending command callbacks */
908 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
911 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
912 silc_client_command_reply_free(cmd);
915 SILC_CLIENT_CMD_REPLY_FUNC(umode)
919 /* Received reply for CMODE command. */
921 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
923 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
924 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
925 SilcCommandStatus status;
928 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
929 if (status != SILC_STATUS_OK) {
930 cmd->client->ops->say(cmd->client, conn,
931 "%s", silc_client_command_status_message(status));
936 /* Get channel mode */
937 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
943 /* Notify application */
944 COMMAND_REPLY((ARGS, tmp));
946 /* Execute any pending command callbacks */
947 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
950 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
951 silc_client_command_reply_free(cmd);
954 /* Received reply for CUMODE command */
956 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
958 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
959 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
960 SilcCommandStatus status;
961 SilcIDCacheEntry id_cache = NULL;
962 SilcClientID *client_id;
963 unsigned char *tmp, *id;
966 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
967 if (status != SILC_STATUS_OK) {
968 cmd->client->ops->say(cmd->client, conn,
969 "%s", silc_client_command_status_message(status));
974 /* Get channel mode */
975 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
982 id = silc_argument_get_arg_type(cmd->args, 3, &len);
987 client_id = silc_id_payload_parse_id(id, len);
993 /* Get client entry */
994 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
995 SILC_ID_CLIENT, &id_cache)) {
1000 /* Notify application */
1001 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1002 silc_free(client_id);
1004 /* Execute any pending command callbacks */
1005 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1008 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1009 silc_client_command_reply_free(cmd);
1012 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1016 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1020 SILC_CLIENT_CMD_REPLY_FUNC(close)
1024 SILC_CLIENT_CMD_REPLY_FUNC(die)
1028 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1032 /* Reply to LEAVE command. */
1034 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1036 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1037 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1038 SilcCommandStatus status;
1041 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1042 SILC_GET16_MSB(status, tmp);
1043 if (status != SILC_STATUS_OK) {
1044 cmd->client->ops->say(cmd->client, conn,
1045 "%s", silc_client_command_status_message(status));
1046 COMMAND_REPLY_ERROR;
1050 /* Notify application */
1051 COMMAND_REPLY((ARGS));
1053 /* Execute any pending command callbacks */
1054 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1057 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1058 silc_client_command_reply_free(cmd);
1061 /* Reply to USERS command. Received list of client ID's and theirs modes
1062 on the channel we requested. */
1064 SILC_CLIENT_CMD_REPLY_FUNC(users)
1066 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1067 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1068 SilcCommandStatus status;
1069 SilcIDCacheEntry id_cache = NULL;
1070 SilcChannelEntry channel;
1071 SilcChannelUser chu;
1072 SilcChannelID *channel_id = NULL;
1073 SilcBuffer client_id_list;
1074 SilcBuffer client_mode_list;
1076 unsigned int tmp_len, list_count;
1078 unsigned char **res_argv = NULL;
1079 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1081 SILC_LOG_DEBUG(("Start"));
1083 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1084 SILC_GET16_MSB(status, tmp);
1085 if (status != SILC_STATUS_OK) {
1086 cmd->client->ops->say(cmd->client, conn,
1087 "%s", silc_client_command_status_message(status));
1088 COMMAND_REPLY_ERROR;
1092 /* Get channel ID */
1093 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1096 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1100 /* Get the list count */
1101 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1104 SILC_GET32_MSB(list_count, tmp);
1106 /* Get Client ID list */
1107 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1111 client_id_list = silc_buffer_alloc(tmp_len);
1112 silc_buffer_pull_tail(client_id_list, tmp_len);
1113 silc_buffer_put(client_id_list, tmp, tmp_len);
1115 /* Get client mode list */
1116 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1120 client_mode_list = silc_buffer_alloc(tmp_len);
1121 silc_buffer_pull_tail(client_mode_list, tmp_len);
1122 silc_buffer_put(client_mode_list, tmp, tmp_len);
1124 /* Get channel entry */
1125 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1126 SILC_ID_CHANNEL, &id_cache)) {
1127 COMMAND_REPLY_ERROR;
1130 channel = (SilcChannelEntry)id_cache->context;
1132 /* Remove old client list from channel. */
1133 silc_list_start(channel->clients);
1134 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1135 silc_list_del(channel->clients, chu);
1139 /* Cache the received Client ID's and modes. This cache expires
1140 whenever server sends notify message to channel. It means two things;
1141 some user has joined or leaved the channel. XXX! */
1142 for (i = 0; i < list_count; i++) {
1143 unsigned short idp_len;
1145 SilcClientID *client_id;
1146 SilcClientEntry client;
1149 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1151 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1156 SILC_GET32_MSB(mode, client_mode_list->data);
1158 /* Check if we have this client cached already. */
1159 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1160 SILC_ID_CLIENT, &id_cache)) {
1161 /* No we don't have it, query it from the server. Assemble argument
1162 table that will be sent fr the IDENTIFY command later. */
1163 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1165 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1167 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1169 res_argv[res_argc] = client_id_list->data;
1170 res_argv_lens[res_argc] = idp_len;
1171 res_argv_types[res_argc] = res_argc + 3;
1174 /* Found the client, join it to the channel */
1175 client = (SilcClientEntry)id_cache->context;
1176 chu = silc_calloc(1, sizeof(*chu));
1177 chu->client = client;
1179 silc_list_add(channel->clients, chu);
1181 silc_free(client_id);
1185 silc_buffer_pull(client_id_list, idp_len);
1186 silc_buffer_pull(client_mode_list, 4);
1189 /* Query the client information from server if the list included clients
1190 that we don't know about. */
1194 /* Send the IDENTIFY command to server */
1195 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1196 res_argc, res_argv, res_argv_lens,
1197 res_argv_types, ++conn->cmd_ident);
1198 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1199 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1202 /* Register pending command callback. After we've received the IDENTIFY
1203 command reply we will reprocess this command reply by re-calling this
1204 USERS command reply callback. */
1205 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1206 NULL, silc_client_command_reply_users, cmd);
1208 silc_buffer_free(res_cmd);
1210 silc_free(channel_id);
1212 silc_free(res_argv);
1213 silc_free(res_argv_lens);
1214 silc_free(res_argv_types);
1218 /* We have all the clients on the channel cached now. Create a nice
1219 output for user interface and notify application. */
1221 if (!cmd->callback) {
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_PENDING_EXEC(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_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1272 silc_client_command_reply_free(cmd);