5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 * Command reply functions are "the otherside" of the command functions.
22 * Reply to a command sent by server is handled by these functions.
24 * The arguments received from server are also passed to the calling
25 * application through command_reply client operation. The arguments are
26 * exactly same and in same order as the server sent it. However, ID's are
27 * not sent to the application. Instead, corresponding ID entry is sent
28 * to the application. For example, instead of sending Client ID the
29 * corresponding SilcClientEntry is sent to the application. The case is
30 * same with for example Channel ID's. This way application has all the
31 * necessary data already in hand without redundant searching. If ID is
32 * received but ID entry does not exist, NULL is sent.
36 #include "clientlibincludes.h"
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(kill, KILL),
49 SILC_CLIENT_CMD_REPLY(info, INFO),
50 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
51 SILC_CLIENT_CMD_REPLY(ping, PING),
52 SILC_CLIENT_CMD_REPLY(oper, OPER),
53 SILC_CLIENT_CMD_REPLY(join, JOIN),
54 SILC_CLIENT_CMD_REPLY(motd, MOTD),
55 SILC_CLIENT_CMD_REPLY(umode, UMODE),
56 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
57 SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
58 SILC_CLIENT_CMD_REPLY(kick, KICK),
59 SILC_CLIENT_CMD_REPLY(restart, RESTART),
60 SILC_CLIENT_CMD_REPLY(close, CLOSE),
61 SILC_CLIENT_CMD_REPLY(shutdown, SHUTDOWN),
62 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
63 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
64 SILC_CLIENT_CMD_REPLY(users, USERS),
69 /* Status message structure. Messages are defined below. */
71 SilcCommandStatus status;
73 } SilcCommandStatusMessage;
75 /* Status messages returned by the server */
76 #define STAT(x) SILC_STATUS_ERR_##x
77 const SilcCommandStatusMessage silc_command_status_messages[] = {
79 { STAT(NO_SUCH_NICK), "No such nickname" },
80 { STAT(NO_SUCH_CHANNEL), "No such channel" },
81 { STAT(NO_SUCH_SERVER), "No such server" },
82 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
83 { STAT(NO_RECIPIENT), "No recipient given" },
84 { STAT(UNKNOWN_COMMAND), "Unknown command" },
85 { STAT(WILDCARDS), "Unknown command" },
86 { STAT(NO_CLIENT_ID), "No Client ID given" },
87 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
88 { STAT(NO_SERVER_ID), "No Server ID given" },
89 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
90 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
91 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
92 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
93 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
94 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
95 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
96 { STAT(USER_ON_CHANNEL), "User already on the channel" },
97 { STAT(NOT_REGISTERED), "You have not registered" },
98 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
99 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
100 { STAT(PERM_DENIED), "Your host is not among the privileged" },
101 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
102 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
103 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
104 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
105 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
106 { STAT(UNKNOWN_MODE), "Unknown mode" },
107 { STAT(NOT_YOU), "Cannot change mode for other users" },
108 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
109 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
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" },
115 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
120 /* Command reply operation that is called at the end of all command replys.
121 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
122 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
123 #define ARGS cmd->client, cmd->sock->user_data, \
124 cmd->payload, TRUE, silc_command_get(cmd->payload), status
126 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
127 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
128 cmd->sock->user_data, cmd->payload, FALSE, \
129 silc_command_get(cmd->payload), status)
131 /* Process received command reply. */
133 void silc_client_command_reply_process(SilcClient client,
134 SilcSocketConnection sock,
135 SilcPacketContext *packet)
137 SilcBuffer buffer = packet->buffer;
138 SilcClientCommandReply *cmd;
139 SilcClientCommandReplyContext ctx;
140 SilcCommandPayload payload;
142 unsigned short ident;
144 /* Get command reply payload from packet */
145 payload = silc_command_payload_parse(buffer);
147 /* Silently ignore bad reply packet */
148 SILC_LOG_DEBUG(("Bad command reply packet"));
152 /* Allocate command reply context. This must be free'd by the
153 command reply routine receiving it. */
154 ctx = silc_calloc(1, sizeof(*ctx));
155 ctx->client = client;
157 ctx->payload = payload;
158 ctx->args = silc_command_get_args(ctx->payload);
159 ctx->packet = packet;
160 ident = silc_command_get_ident(ctx->payload);
162 /* Check for pending commands and mark to be exeucted */
163 silc_client_command_pending_check(sock->user_data, ctx,
164 silc_command_get(ctx->payload), ident);
166 /* Execute command reply */
167 command = silc_command_get(ctx->payload);
168 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
169 if (cmd->cmd == command)
172 if (cmd == NULL || !cmd->cb) {
180 /* Returns status message string */
183 silc_client_command_status_message(SilcCommandStatus status)
187 for (i = 0; silc_command_status_messages[i].message; i++) {
188 if (silc_command_status_messages[i].status == status)
192 if (silc_command_status_messages[i].message == NULL)
195 return silc_command_status_messages[i].message;
198 /* Free command reply context and its internals. */
200 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
203 silc_command_free_payload(cmd->payload);
209 silc_client_command_reply_whois_print(SilcClientCommandReplyContext cmd,
210 SilcCommandStatus status)
214 unsigned char *id_data;
215 char *nickname = NULL, *username = NULL;
216 char *realname = NULL;
217 SilcClientID *client_id;
218 SilcIDCacheEntry id_cache = NULL;
219 SilcClientEntry client_entry = NULL;
220 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
222 memset(buf, 0, sizeof(buf));
224 argc = silc_argument_get_arg_num(cmd->args);
226 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
232 client_id = silc_id_payload_parse_id(id_data, len);
238 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
240 strncat(buf, nickname, len);
241 strncat(buf, " is ", 4);
244 username = silc_argument_get_arg_type(cmd->args, 4, &len);
246 strncat(buf, username, len);
249 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
251 strncat(buf, " (", 2);
252 strncat(buf, realname, len);
253 strncat(buf, ")", 1);
256 /* Check if we have this client cached already. */
257 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
258 SILC_ID_CLIENT, &id_cache)) {
259 client_entry = silc_calloc(1, sizeof(*client_entry));
260 client_entry->id = client_id;
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 /* Add client to cache */
268 silc_idcache_add(conn->client_cache, client_entry->nickname,
269 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
271 client_entry = (SilcClientEntry)id_cache->context;
272 if (client_entry->nickname)
273 silc_free(client_entry->nickname);
274 if (client_entry->server)
275 silc_free(client_entry->server);
276 if (client_entry->username)
277 silc_free(client_entry->username);
278 if (client_entry->realname)
279 silc_free(client_entry->realname);
281 silc_parse_nickname(nickname, &client_entry->nickname,
282 &client_entry->server, &client_entry->num);
283 client_entry->username = strdup(username);
285 client_entry->realname = strdup(realname);
287 id_cache->data = client_entry->nickname;
288 silc_idcache_sort_by_data(conn->client_cache);
290 silc_free(client_id);
294 cmd->client->ops->say(cmd->client, conn, "%s", buf);
296 /* Notify application */
297 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
301 /* Received reply for WHOIS command. This maybe called several times
302 for one WHOIS command as server may reply with list of results. */
304 SILC_CLIENT_CMD_REPLY_FUNC(whois)
306 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
307 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
308 SilcCommandStatus status;
311 SILC_LOG_DEBUG(("Start"));
313 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
314 SILC_GET16_MSB(status, tmp);
315 if (status != SILC_STATUS_OK &&
316 status != SILC_STATUS_LIST_START &&
317 status != SILC_STATUS_LIST_ITEM &&
318 status != SILC_STATUS_LIST_END) {
319 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
320 /* Take nickname which may be provided */
321 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
323 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
324 silc_client_command_status_message(status));
326 cmd->client->ops->say(cmd->client, conn, "%s",
327 silc_client_command_status_message(status));
331 cmd->client->ops->say(cmd->client, conn,
332 "%s", silc_client_command_status_message(status));
338 /* Display one whois reply */
339 if (status == SILC_STATUS_OK) {
340 silc_client_command_reply_whois_print(cmd, status);
343 /* XXX list should not be displayed untill all items has been received. */
344 if (status == SILC_STATUS_LIST_START) {
345 silc_client_command_reply_whois_print(cmd, status);
348 if (status == SILC_STATUS_LIST_ITEM) {
349 silc_client_command_reply_whois_print(cmd, status);
352 if (status == SILC_STATUS_LIST_END) {
353 silc_client_command_reply_whois_print(cmd, status);
356 /* Execute any pending command callbacks */
357 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
360 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
361 silc_client_command_reply_free(cmd);
364 /* Received reply for WHOWAS command. */
366 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
371 /* Received reply for IDENTIFY command. This maybe called several times
372 for one IDENTIFY command as server may reply with list of results.
373 This is totally silent and does not print anything on screen. */
375 SILC_CLIENT_CMD_REPLY_FUNC(identify)
377 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
378 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
379 SilcClientEntry client_entry;
380 SilcIDCacheEntry id_cache = NULL;
381 SilcCommandStatus status;
384 SILC_LOG_DEBUG(("Start"));
386 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
387 SILC_GET16_MSB(status, tmp);
388 if (status != SILC_STATUS_OK) {
389 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
390 /* Take nickname which may be provided */
391 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
393 cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
394 silc_client_command_status_message(status));
396 cmd->client->ops->say(cmd->client, conn, "%s",
397 silc_client_command_status_message(status));
401 cmd->client->ops->say(cmd->client, conn,
402 "%s", silc_client_command_status_message(status));
408 /* Display one whois reply */
409 if (status == SILC_STATUS_OK) {
411 unsigned char *id_data;
414 SilcClientID *client_id;
416 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
419 client_id = silc_id_payload_parse_id(id_data, len);
423 nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
424 username = silc_argument_get_arg_type(cmd->args, 4, NULL);
426 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
427 SILC_ID_CLIENT, &id_cache)) {
428 client_entry = silc_calloc(1, sizeof(*client_entry));
429 client_entry->id = client_id;
430 silc_parse_nickname(nickname, &client_entry->nickname,
431 &client_entry->server, &client_entry->num);
433 client_entry->username = strdup(username);
435 /* Add client to cache */
436 silc_idcache_add(conn->client_cache, client_entry->nickname,
437 SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
439 client_entry = (SilcClientEntry)id_cache->context;
440 if (client_entry->nickname)
441 silc_free(client_entry->nickname);
442 if (client_entry->server)
443 silc_free(client_entry->server);
444 if (username && client_entry->username)
445 silc_free(client_entry->username);
447 silc_parse_nickname(nickname, &client_entry->nickname,
448 &client_entry->server, &client_entry->num);
451 client_entry->username = strdup(username);
453 id_cache->data = client_entry->nickname;
454 silc_idcache_sort_by_data(conn->client_cache);
456 silc_free(client_id);
460 if (status == SILC_STATUS_LIST_START) {
464 if (status == SILC_STATUS_LIST_END) {
468 /* Execute any pending command callbacks */
469 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
472 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
473 silc_client_command_reply_free(cmd);
476 /* Received reply for command NICK. If everything went without errors
477 we just received our new Client ID. */
479 SILC_CLIENT_CMD_REPLY_FUNC(nick)
481 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
482 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
483 SilcCommandStatus status;
486 unsigned int argc, len;
488 SILC_LOG_DEBUG(("Start"));
490 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
491 if (status != SILC_STATUS_OK) {
492 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
493 silc_client_command_status_message(status));
498 argc = silc_argument_get_arg_num(cmd->args);
499 if (argc < 2 || argc > 2) {
500 cmd->client->ops->say(cmd->client, conn,
501 "Cannot set nickname: bad reply to command");
506 /* Take received Client ID */
507 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
508 idp = silc_id_payload_parse_data(tmp, len);
513 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
515 /* Notify application */
516 COMMAND_REPLY((ARGS, conn->local_entry));
518 /* Execute any pending command callbacks */
519 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
522 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
523 silc_client_command_reply_free(cmd);
526 SILC_CLIENT_CMD_REPLY_FUNC(list)
530 /* Received reply to topic command. */
532 SILC_CLIENT_CMD_REPLY_FUNC(topic)
534 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
535 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
536 SilcCommandStatus status;
537 SilcChannelEntry channel;
538 SilcChannelID *channel_id = NULL;
539 SilcIDCacheEntry id_cache = NULL;
542 unsigned int argc, len;
544 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
545 if (status != SILC_STATUS_OK) {
546 cmd->client->ops->say(cmd->client, conn,
547 "%s", silc_client_command_status_message(status));
549 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
550 silc_client_command_reply_free(cmd);
554 argc = silc_argument_get_arg_num(cmd->args);
555 if (argc < 1 || argc > 3) {
560 /* Take Channel ID */
561 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
566 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
570 channel_id = silc_id_payload_parse_id(tmp, len);
574 /* Get the channel name */
575 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
576 SILC_ID_CHANNEL, &id_cache)) {
577 silc_free(channel_id);
582 channel = (SilcChannelEntry)id_cache->context;
584 cmd->client->ops->say(cmd->client, conn,
585 "Topic on channel %s: %s", channel->channel_name,
588 /* Notify application */
589 COMMAND_REPLY((ARGS, channel, topic));
591 /* Execute any pending command callbacks */
592 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
595 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
596 silc_client_command_reply_free(cmd);
599 /* Received reply to invite command. */
601 SILC_CLIENT_CMD_REPLY_FUNC(invite)
603 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
604 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
605 SilcCommandStatus status;
608 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
609 SILC_GET16_MSB(status, tmp);
610 if (status != SILC_STATUS_OK) {
611 cmd->client->ops->say(cmd->client, conn,
612 "%s", silc_client_command_status_message(status));
614 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
615 silc_client_command_reply_free(cmd);
619 /* Notify application */
620 COMMAND_REPLY((ARGS));
622 /* Execute any pending command callbacks */
623 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
625 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
626 silc_client_command_reply_free(cmd);
629 SILC_CLIENT_CMD_REPLY_FUNC(kill)
633 /* Received reply to INFO command. We receive the server ID and some
634 information about the server user requested. */
636 SILC_CLIENT_CMD_REPLY_FUNC(info)
638 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
639 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
640 SilcClient client = cmd->client;
641 SilcCommandStatus status;
644 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
645 SILC_GET16_MSB(status, tmp);
646 if (status != SILC_STATUS_OK) {
647 cmd->client->ops->say(cmd->client, conn,
648 "%s", silc_client_command_status_message(status));
650 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
651 silc_client_command_reply_free(cmd);
656 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
660 /* XXX save server id */
662 /* Get server info */
663 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
667 client->ops->say(cmd->client, conn, "Info: %s", tmp);
669 /* Notify application */
670 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
672 /* Execute any pending command callbacks */
673 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
676 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
677 silc_client_command_reply_free(cmd);
680 /* Received reply to PING command. The reply time is shown to user. */
682 SILC_CLIENT_CMD_REPLY_FUNC(ping)
684 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
685 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
686 SilcCommandStatus status;
689 time_t diff, curtime;
691 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
692 if (status != SILC_STATUS_OK) {
693 cmd->client->ops->say(cmd->client, conn,
694 "%s", silc_client_command_status_message(status));
699 curtime = time(NULL);
700 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
701 cmd->packet->src_id_type);
707 for (i = 0; i < conn->ping_count; i++) {
708 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
709 diff = curtime - conn->ping[i].start_time;
710 cmd->client->ops->say(cmd->client, conn,
711 "Ping reply from %s: %d second%s",
712 conn->ping[i].dest_name, diff,
713 diff == 1 ? "" : "s");
715 conn->ping[i].start_time = 0;
716 silc_free(conn->ping[i].dest_id);
717 conn->ping[i].dest_id = NULL;
718 silc_free(conn->ping[i].dest_name);
719 conn->ping[i].dest_name = NULL;
726 /* Notify application */
727 COMMAND_REPLY((ARGS));
729 /* Execute any pending command callbacks */
730 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
733 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
734 silc_client_command_reply_free(cmd);
737 /* Received reply for JOIN command. */
739 SILC_CLIENT_CMD_REPLY_FUNC(join)
741 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
742 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
743 SilcClient client = cmd->client;
744 SilcCommandStatus status;
745 SilcIDPayload idp = NULL;
746 unsigned int argc, mode, len;
747 char *topic, *tmp, *channel_name = NULL;
750 SILC_LOG_DEBUG(("Start"));
752 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
753 if (status != SILC_STATUS_OK) {
754 cmd->client->ops->say(cmd->client, conn,
755 "%s", silc_client_command_status_message(status));
760 argc = silc_argument_get_arg_num(cmd->args);
761 if (argc < 3 || argc > 9) {
762 cmd->client->ops->say(cmd->client, conn,
763 "Cannot join channel: Bad reply packet");
768 /* Get channel name */
769 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
771 cmd->client->ops->say(cmd->client, conn,
772 "Cannot join channel: Bad reply packet");
776 channel_name = strdup(tmp);
779 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
781 cmd->client->ops->say(cmd->client, conn,
782 "Cannot join channel: Bad reply packet");
784 silc_free(channel_name);
787 idp = silc_id_payload_parse_data(tmp, len);
790 silc_free(channel_name);
794 /* Get channel mode */
795 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
797 SILC_GET32_MSB(mode, tmp);
801 /* Get channel key */
802 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
804 silc_id_payload_free(idp);
805 silc_free(channel_name);
808 keyp = silc_buffer_alloc(len);
809 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
810 silc_buffer_put(keyp, tmp, len);
813 topic = silc_argument_get_arg_type(cmd->args, 8, NULL);
815 /* Save received Channel ID */
816 silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
818 silc_id_payload_free(idp);
820 /* Save channel key */
821 silc_client_save_channel_key(conn, keyp, conn->current_channel);
822 silc_buffer_free(keyp);
825 client->ops->say(cmd->client, conn,
826 "Topic for %s: %s", channel_name, topic);
828 /* Notify application */
829 COMMAND_REPLY((ARGS, channel_name, conn->current_channel, mode,
832 /* Execute any pending command callbacks */
833 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
836 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
837 silc_client_command_reply_free(cmd);
840 /* Received reply for MOTD command */
842 SILC_CLIENT_CMD_REPLY_FUNC(motd)
844 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
845 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
846 SilcCommandStatus status;
847 unsigned int argc, i;
849 char *motd = NULL, *cp, line[256];
851 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
852 SILC_GET16_MSB(status, tmp);
853 if (status != SILC_STATUS_OK) {
854 cmd->client->ops->say(cmd->client, conn,
855 "%s", silc_client_command_status_message(status));
860 argc = silc_argument_get_arg_num(cmd->args);
867 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
876 if (cp[i++] == '\n') {
877 memset(line, 0, sizeof(line));
878 strncat(line, cp, i - 1);
884 cmd->client->ops->say(cmd->client, conn, "%s", line);
893 /* Notify application */
894 COMMAND_REPLY((ARGS, motd));
896 /* Execute any pending command callbacks */
897 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
900 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
901 silc_client_command_reply_free(cmd);
904 SILC_CLIENT_CMD_REPLY_FUNC(umode)
908 /* Received reply for CMODE command. */
910 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
912 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
913 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
914 SilcCommandStatus status;
917 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
918 if (status != SILC_STATUS_OK) {
919 cmd->client->ops->say(cmd->client, conn,
920 "%s", silc_client_command_status_message(status));
925 /* Get channel mode */
926 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
932 /* Notify application */
933 COMMAND_REPLY((ARGS, tmp));
935 /* Execute any pending command callbacks */
936 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
939 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
940 silc_client_command_reply_free(cmd);
943 /* Received reply for CUMODE command */
945 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
947 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
948 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
949 SilcCommandStatus status;
950 SilcIDCacheEntry id_cache = NULL;
951 SilcClientID *client_id;
952 unsigned char *tmp, *id;
955 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
956 if (status != SILC_STATUS_OK) {
957 cmd->client->ops->say(cmd->client, conn,
958 "%s", silc_client_command_status_message(status));
963 /* Get channel mode */
964 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
971 id = silc_argument_get_arg_type(cmd->args, 3, &len);
976 client_id = silc_id_payload_parse_id(id, len);
982 /* Get client entry */
983 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
984 SILC_ID_CLIENT, &id_cache)) {
989 /* Notify application */
990 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
991 silc_free(client_id);
993 /* Execute any pending command callbacks */
994 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
997 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
998 silc_client_command_reply_free(cmd);
1001 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1003 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1004 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1005 SilcCommandStatus status;
1008 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1009 SILC_GET16_MSB(status, tmp);
1010 if (status != SILC_STATUS_OK) {
1011 cmd->client->ops->say(cmd->client, conn,
1012 "%s", silc_client_command_status_message(status));
1013 COMMAND_REPLY_ERROR;
1017 /* Notify application */
1018 COMMAND_REPLY((ARGS));
1020 /* Execute any pending command callbacks */
1021 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1024 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1025 silc_client_command_reply_free(cmd);
1028 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1032 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1036 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1038 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1039 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1040 SilcCommandStatus status;
1043 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1044 SILC_GET16_MSB(status, tmp);
1045 if (status != SILC_STATUS_OK) {
1046 cmd->client->ops->say(cmd->client, conn,
1047 "%s", silc_client_command_status_message(status));
1048 COMMAND_REPLY_ERROR;
1052 /* Notify application */
1053 COMMAND_REPLY((ARGS));
1055 /* Execute any pending command callbacks */
1056 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1059 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1060 silc_client_command_reply_free(cmd);
1063 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1065 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1066 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1067 SilcCommandStatus status;
1070 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1071 SILC_GET16_MSB(status, tmp);
1072 if (status != SILC_STATUS_OK) {
1073 cmd->client->ops->say(cmd->client, conn,
1074 "%s", silc_client_command_status_message(status));
1075 COMMAND_REPLY_ERROR;
1079 /* Notify application */
1080 COMMAND_REPLY((ARGS));
1082 /* Execute any pending command callbacks */
1083 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1086 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1087 silc_client_command_reply_free(cmd);
1090 SILC_CLIENT_CMD_REPLY_FUNC(close)
1092 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1093 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1094 SilcCommandStatus status;
1097 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1098 SILC_GET16_MSB(status, tmp);
1099 if (status != SILC_STATUS_OK) {
1100 cmd->client->ops->say(cmd->client, conn,
1101 "%s", silc_client_command_status_message(status));
1102 COMMAND_REPLY_ERROR;
1106 /* Notify application */
1107 COMMAND_REPLY((ARGS));
1109 /* Execute any pending command callbacks */
1110 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1113 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1114 silc_client_command_reply_free(cmd);
1117 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1119 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1120 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1121 SilcCommandStatus status;
1124 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1125 SILC_GET16_MSB(status, tmp);
1126 if (status != SILC_STATUS_OK) {
1127 cmd->client->ops->say(cmd->client, conn,
1128 "%s", silc_client_command_status_message(status));
1129 COMMAND_REPLY_ERROR;
1133 /* Notify application */
1134 COMMAND_REPLY((ARGS));
1136 /* Execute any pending command callbacks */
1137 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1140 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1141 silc_client_command_reply_free(cmd);
1144 /* Reply to LEAVE command. */
1146 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1148 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1149 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1150 SilcCommandStatus status;
1153 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1154 SILC_GET16_MSB(status, tmp);
1155 if (status != SILC_STATUS_OK) {
1156 cmd->client->ops->say(cmd->client, conn,
1157 "%s", silc_client_command_status_message(status));
1158 COMMAND_REPLY_ERROR;
1162 /* Notify application */
1163 COMMAND_REPLY((ARGS));
1165 /* Execute any pending command callbacks */
1166 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1169 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1170 silc_client_command_reply_free(cmd);
1173 /* Reply to USERS command. Received list of client ID's and theirs modes
1174 on the channel we requested. */
1176 SILC_CLIENT_CMD_REPLY_FUNC(users)
1178 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1179 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1180 SilcCommandStatus status;
1181 SilcIDCacheEntry id_cache = NULL;
1182 SilcChannelEntry channel;
1183 SilcChannelUser chu;
1184 SilcChannelID *channel_id = NULL;
1185 SilcBuffer client_id_list;
1186 SilcBuffer client_mode_list;
1188 unsigned int tmp_len, list_count;
1190 unsigned char **res_argv = NULL;
1191 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1193 SILC_LOG_DEBUG(("Start"));
1195 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1196 SILC_GET16_MSB(status, tmp);
1197 if (status != SILC_STATUS_OK) {
1198 cmd->client->ops->say(cmd->client, conn,
1199 "%s", silc_client_command_status_message(status));
1200 COMMAND_REPLY_ERROR;
1204 /* Get channel ID */
1205 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1208 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1212 /* Get the list count */
1213 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1216 SILC_GET32_MSB(list_count, tmp);
1218 /* Get Client ID list */
1219 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1223 client_id_list = silc_buffer_alloc(tmp_len);
1224 silc_buffer_pull_tail(client_id_list, tmp_len);
1225 silc_buffer_put(client_id_list, tmp, tmp_len);
1227 /* Get client mode list */
1228 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1232 client_mode_list = silc_buffer_alloc(tmp_len);
1233 silc_buffer_pull_tail(client_mode_list, tmp_len);
1234 silc_buffer_put(client_mode_list, tmp, tmp_len);
1236 /* Get channel entry */
1237 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1238 SILC_ID_CHANNEL, &id_cache)) {
1239 COMMAND_REPLY_ERROR;
1242 channel = (SilcChannelEntry)id_cache->context;
1244 /* Remove old client list from channel. */
1245 silc_list_start(channel->clients);
1246 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1247 silc_list_del(channel->clients, chu);
1251 /* Cache the received Client ID's and modes. This cache expires
1252 whenever server sends notify message to channel. It means two things;
1253 some user has joined or leaved the channel. XXX! */
1254 for (i = 0; i < list_count; i++) {
1255 unsigned short idp_len;
1257 SilcClientID *client_id;
1258 SilcClientEntry client;
1261 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1263 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1268 SILC_GET32_MSB(mode, client_mode_list->data);
1270 /* Check if we have this client cached already. */
1271 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1272 SILC_ID_CLIENT, &id_cache)) {
1273 /* No we don't have it, query it from the server. Assemble argument
1274 table that will be sent fr the IDENTIFY command later. */
1275 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1277 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1279 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1281 res_argv[res_argc] = client_id_list->data;
1282 res_argv_lens[res_argc] = idp_len;
1283 res_argv_types[res_argc] = res_argc + 3;
1286 /* Found the client, join it to the channel */
1287 client = (SilcClientEntry)id_cache->context;
1288 chu = silc_calloc(1, sizeof(*chu));
1289 chu->client = client;
1291 silc_list_add(channel->clients, chu);
1293 silc_free(client_id);
1297 silc_buffer_pull(client_id_list, idp_len);
1298 silc_buffer_pull(client_mode_list, 4);
1301 /* Query the client information from server if the list included clients
1302 that we don't know about. */
1306 /* Send the IDENTIFY command to server */
1307 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1308 res_argc, res_argv, res_argv_lens,
1309 res_argv_types, ++conn->cmd_ident);
1310 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1311 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1314 /* Register pending command callback. After we've received the IDENTIFY
1315 command reply we will reprocess this command reply by re-calling this
1316 USERS command reply callback. */
1317 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1318 NULL, silc_client_command_reply_users, cmd);
1320 silc_buffer_free(res_cmd);
1322 silc_free(channel_id);
1324 silc_free(res_argv);
1325 silc_free(res_argv_lens);
1326 silc_free(res_argv_types);
1330 /* We have all the clients on the channel cached now. Create a nice
1331 output for user interface and notify application. */
1333 if (!cmd->callback) {
1334 /* Server has sent us USERS reply even when we haven't actually sent
1335 USERS command. This is normal behaviour when joining to a channel.
1336 Display some nice information on the user interface. */
1337 int k = 0, len1 = 0, len2 = 0;
1338 char *name_list = NULL;
1340 silc_list_start(channel->clients);
1341 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1342 char *m, *n = chu->client->nickname;
1346 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
1348 m = silc_client_chumode_char(chu->mode);
1350 memcpy(name_list + (len1 - len2), m, strlen(m));
1355 memcpy(name_list + (len1 - len2), n, len2);
1356 name_list[len1] = 0;
1358 if (k == silc_list_count(channel->clients) - 1)
1360 memcpy(name_list + len1, " ", 1);
1365 cmd->client->ops->say(cmd->client, conn, "Users on %s: %s",
1366 channel->channel_name, name_list);
1367 silc_free(name_list);
1370 /* Notify application */
1371 COMMAND_REPLY((ARGS, channel, client_id_list->head,
1372 client_mode_list->head));
1374 /* Execute any pending command callbacks */
1375 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1377 silc_buffer_free(client_id_list);
1378 silc_buffer_free(client_mode_list);
1382 silc_free(channel_id);
1383 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1384 silc_client_command_reply_free(cmd);