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_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
111 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
112 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
113 { STAT(BAD_NICKNAME), "Bad nickname" },
114 { STAT(BAD_CHANNEL), "Bad channel name" },
115 { STAT(AUTH_FAILED), "Authentication failed" },
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(quit)
633 SILC_CLIENT_CMD_REPLY_FUNC(kill)
637 /* Received reply to INFO command. We receive the server ID and some
638 information about the server user requested. */
640 SILC_CLIENT_CMD_REPLY_FUNC(info)
642 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
643 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
644 SilcClient client = cmd->client;
645 SilcCommandStatus status;
648 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
649 SILC_GET16_MSB(status, tmp);
650 if (status != SILC_STATUS_OK) {
651 cmd->client->ops->say(cmd->client, conn,
652 "%s", silc_client_command_status_message(status));
654 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
655 silc_client_command_reply_free(cmd);
660 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
664 /* XXX save server id */
666 /* Get server info */
667 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
671 client->ops->say(cmd->client, conn, "Info: %s", tmp);
673 /* Notify application */
674 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
676 /* Execute any pending command callbacks */
677 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
680 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
681 silc_client_command_reply_free(cmd);
684 SILC_CLIENT_CMD_REPLY_FUNC(connect)
688 /* Received reply to PING command. The reply time is shown to user. */
690 SILC_CLIENT_CMD_REPLY_FUNC(ping)
692 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
693 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
694 SilcCommandStatus status;
697 time_t diff, curtime;
699 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
700 if (status != SILC_STATUS_OK) {
701 cmd->client->ops->say(cmd->client, conn,
702 "%s", silc_client_command_status_message(status));
707 curtime = time(NULL);
708 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
709 cmd->packet->src_id_type);
715 for (i = 0; i < conn->ping_count; i++) {
716 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
717 diff = curtime - conn->ping[i].start_time;
718 cmd->client->ops->say(cmd->client, conn,
719 "Ping reply from %s: %d second%s",
720 conn->ping[i].dest_name, diff,
721 diff == 1 ? "" : "s");
723 conn->ping[i].start_time = 0;
724 silc_free(conn->ping[i].dest_id);
725 conn->ping[i].dest_id = NULL;
726 silc_free(conn->ping[i].dest_name);
727 conn->ping[i].dest_name = NULL;
734 /* Notify application */
735 COMMAND_REPLY((ARGS));
737 /* Execute any pending command callbacks */
738 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
741 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
742 silc_client_command_reply_free(cmd);
745 SILC_CLIENT_CMD_REPLY_FUNC(oper)
749 /* Received reply for JOIN command. */
751 SILC_CLIENT_CMD_REPLY_FUNC(join)
753 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
754 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
755 SilcClient client = cmd->client;
756 SilcCommandStatus status;
757 SilcIDPayload idp = NULL;
758 unsigned int argc, mode, len;
759 char *topic, *tmp, *channel_name = NULL;
762 SILC_LOG_DEBUG(("Start"));
764 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
765 if (status != SILC_STATUS_OK) {
766 cmd->client->ops->say(cmd->client, conn,
767 "%s", silc_client_command_status_message(status));
772 argc = silc_argument_get_arg_num(cmd->args);
773 if (argc < 3 || argc > 9) {
774 cmd->client->ops->say(cmd->client, conn,
775 "Cannot join channel: Bad reply packet");
780 /* Get channel name */
781 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
783 cmd->client->ops->say(cmd->client, conn,
784 "Cannot join channel: Bad reply packet");
788 channel_name = strdup(tmp);
791 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
793 cmd->client->ops->say(cmd->client, conn,
794 "Cannot join channel: Bad reply packet");
796 silc_free(channel_name);
799 idp = silc_id_payload_parse_data(tmp, len);
802 silc_free(channel_name);
806 /* Get channel mode */
807 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
809 SILC_GET32_MSB(mode, tmp);
813 /* Get channel key */
814 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
816 silc_id_payload_free(idp);
817 silc_free(channel_name);
820 keyp = silc_buffer_alloc(len);
821 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
822 silc_buffer_put(keyp, tmp, len);
825 topic = silc_argument_get_arg_type(cmd->args, 8, NULL);
827 /* Save received Channel ID */
828 silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
830 silc_id_payload_free(idp);
832 /* Save channel key */
833 silc_client_save_channel_key(conn, keyp, conn->current_channel);
834 silc_buffer_free(keyp);
837 client->ops->say(cmd->client, conn,
838 "Topic for %s: %s", channel_name, topic);
840 /* Notify application */
841 COMMAND_REPLY((ARGS, channel_name, conn->current_channel, mode,
844 /* Execute any pending command callbacks */
845 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
848 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
849 silc_client_command_reply_free(cmd);
852 /* Received reply for MOTD command */
854 SILC_CLIENT_CMD_REPLY_FUNC(motd)
856 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
857 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
858 SilcCommandStatus status;
859 unsigned int argc, i;
861 char *motd = NULL, *cp, line[256];
863 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
864 SILC_GET16_MSB(status, tmp);
865 if (status != SILC_STATUS_OK) {
866 cmd->client->ops->say(cmd->client, conn,
867 "%s", silc_client_command_status_message(status));
872 argc = silc_argument_get_arg_num(cmd->args);
879 motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
888 if (cp[i++] == '\n') {
889 memset(line, 0, sizeof(line));
890 strncat(line, cp, i - 1);
896 cmd->client->ops->say(cmd->client, conn, "%s", line);
905 /* Notify application */
906 COMMAND_REPLY((ARGS, motd));
908 /* Execute any pending command callbacks */
909 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
912 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
913 silc_client_command_reply_free(cmd);
916 SILC_CLIENT_CMD_REPLY_FUNC(umode)
920 /* Received reply for CMODE command. */
922 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
924 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
925 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
926 SilcCommandStatus status;
929 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
930 if (status != SILC_STATUS_OK) {
931 cmd->client->ops->say(cmd->client, conn,
932 "%s", silc_client_command_status_message(status));
937 /* Get channel mode */
938 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
944 /* Notify application */
945 COMMAND_REPLY((ARGS, tmp));
947 /* Execute any pending command callbacks */
948 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
951 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
952 silc_client_command_reply_free(cmd);
955 /* Received reply for CUMODE command */
957 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
959 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
960 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
961 SilcCommandStatus status;
962 SilcIDCacheEntry id_cache = NULL;
963 SilcClientID *client_id;
964 unsigned char *tmp, *id;
967 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
968 if (status != SILC_STATUS_OK) {
969 cmd->client->ops->say(cmd->client, conn,
970 "%s", silc_client_command_status_message(status));
975 /* Get channel mode */
976 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
983 id = silc_argument_get_arg_type(cmd->args, 3, &len);
988 client_id = silc_id_payload_parse_id(id, len);
994 /* Get client entry */
995 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
996 SILC_ID_CLIENT, &id_cache)) {
1001 /* Notify application */
1002 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1003 silc_free(client_id);
1005 /* Execute any pending command callbacks */
1006 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1009 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1010 silc_client_command_reply_free(cmd);
1013 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1015 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1016 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1017 SilcCommandStatus status;
1020 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1021 SILC_GET16_MSB(status, tmp);
1022 if (status != SILC_STATUS_OK) {
1023 cmd->client->ops->say(cmd->client, conn,
1024 "%s", silc_client_command_status_message(status));
1025 COMMAND_REPLY_ERROR;
1029 /* Notify application */
1030 COMMAND_REPLY((ARGS));
1032 /* Execute any pending command callbacks */
1033 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1036 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1037 silc_client_command_reply_free(cmd);
1040 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1044 SILC_CLIENT_CMD_REPLY_FUNC(close)
1048 SILC_CLIENT_CMD_REPLY_FUNC(die)
1052 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1056 /* Reply to LEAVE command. */
1058 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1060 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1061 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1062 SilcCommandStatus status;
1065 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1066 SILC_GET16_MSB(status, tmp);
1067 if (status != SILC_STATUS_OK) {
1068 cmd->client->ops->say(cmd->client, conn,
1069 "%s", silc_client_command_status_message(status));
1070 COMMAND_REPLY_ERROR;
1074 /* Notify application */
1075 COMMAND_REPLY((ARGS));
1077 /* Execute any pending command callbacks */
1078 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1081 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1082 silc_client_command_reply_free(cmd);
1085 /* Reply to USERS command. Received list of client ID's and theirs modes
1086 on the channel we requested. */
1088 SILC_CLIENT_CMD_REPLY_FUNC(users)
1090 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1091 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1092 SilcCommandStatus status;
1093 SilcIDCacheEntry id_cache = NULL;
1094 SilcChannelEntry channel;
1095 SilcChannelUser chu;
1096 SilcChannelID *channel_id = NULL;
1097 SilcBuffer client_id_list;
1098 SilcBuffer client_mode_list;
1100 unsigned int tmp_len, list_count;
1102 unsigned char **res_argv = NULL;
1103 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1105 SILC_LOG_DEBUG(("Start"));
1107 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1108 SILC_GET16_MSB(status, tmp);
1109 if (status != SILC_STATUS_OK) {
1110 cmd->client->ops->say(cmd->client, conn,
1111 "%s", silc_client_command_status_message(status));
1112 COMMAND_REPLY_ERROR;
1116 /* Get channel ID */
1117 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1120 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1124 /* Get the list count */
1125 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1128 SILC_GET32_MSB(list_count, tmp);
1130 /* Get Client ID list */
1131 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1135 client_id_list = silc_buffer_alloc(tmp_len);
1136 silc_buffer_pull_tail(client_id_list, tmp_len);
1137 silc_buffer_put(client_id_list, tmp, tmp_len);
1139 /* Get client mode list */
1140 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1144 client_mode_list = silc_buffer_alloc(tmp_len);
1145 silc_buffer_pull_tail(client_mode_list, tmp_len);
1146 silc_buffer_put(client_mode_list, tmp, tmp_len);
1148 /* Get channel entry */
1149 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1150 SILC_ID_CHANNEL, &id_cache)) {
1151 COMMAND_REPLY_ERROR;
1154 channel = (SilcChannelEntry)id_cache->context;
1156 /* Remove old client list from channel. */
1157 silc_list_start(channel->clients);
1158 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1159 silc_list_del(channel->clients, chu);
1163 /* Cache the received Client ID's and modes. This cache expires
1164 whenever server sends notify message to channel. It means two things;
1165 some user has joined or leaved the channel. XXX! */
1166 for (i = 0; i < list_count; i++) {
1167 unsigned short idp_len;
1169 SilcClientID *client_id;
1170 SilcClientEntry client;
1173 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1175 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1180 SILC_GET32_MSB(mode, client_mode_list->data);
1182 /* Check if we have this client cached already. */
1183 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1184 SILC_ID_CLIENT, &id_cache)) {
1185 /* No we don't have it, query it from the server. Assemble argument
1186 table that will be sent fr the IDENTIFY command later. */
1187 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1189 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1191 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1193 res_argv[res_argc] = client_id_list->data;
1194 res_argv_lens[res_argc] = idp_len;
1195 res_argv_types[res_argc] = res_argc + 3;
1198 /* Found the client, join it to the channel */
1199 client = (SilcClientEntry)id_cache->context;
1200 chu = silc_calloc(1, sizeof(*chu));
1201 chu->client = client;
1203 silc_list_add(channel->clients, chu);
1205 silc_free(client_id);
1209 silc_buffer_pull(client_id_list, idp_len);
1210 silc_buffer_pull(client_mode_list, 4);
1213 /* Query the client information from server if the list included clients
1214 that we don't know about. */
1218 /* Send the IDENTIFY command to server */
1219 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1220 res_argc, res_argv, res_argv_lens,
1221 res_argv_types, ++conn->cmd_ident);
1222 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1223 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1226 /* Register pending command callback. After we've received the IDENTIFY
1227 command reply we will reprocess this command reply by re-calling this
1228 USERS command reply callback. */
1229 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1230 NULL, silc_client_command_reply_users, cmd);
1232 silc_buffer_free(res_cmd);
1234 silc_free(channel_id);
1236 silc_free(res_argv);
1237 silc_free(res_argv_lens);
1238 silc_free(res_argv_types);
1242 /* We have all the clients on the channel cached now. Create a nice
1243 output for user interface and notify application. */
1245 if (!cmd->callback) {
1246 /* Server has sent us USERS reply even when we haven't actually sent
1247 USERS command. This is normal behaviour when joining to a channel.
1248 Display some nice information on the user interface. */
1249 int k = 0, len1 = 0, len2 = 0;
1250 char *name_list = NULL;
1252 silc_list_start(channel->clients);
1253 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1254 char *m, *n = chu->client->nickname;
1258 name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
1260 m = silc_client_chumode_char(chu->mode);
1262 memcpy(name_list + (len1 - len2), m, strlen(m));
1267 memcpy(name_list + (len1 - len2), n, len2);
1268 name_list[len1] = 0;
1270 if (k == silc_list_count(channel->clients) - 1)
1272 memcpy(name_list + len1, " ", 1);
1277 cmd->client->ops->say(cmd->client, conn, "Users on %s: %s",
1278 channel->channel_name, name_list);
1279 silc_free(name_list);
1282 /* Notify application */
1283 COMMAND_REPLY((ARGS, channel, client_id_list->head,
1284 client_mode_list->head));
1286 /* Execute any pending command callbacks */
1287 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1289 silc_buffer_free(client_id_list);
1290 silc_buffer_free(client_mode_list);
1294 silc_free(channel_id);
1295 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1296 silc_client_command_reply_free(cmd);