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"
37 #include "client_internal.h"
39 /* Client command reply list. */
40 SilcClientCommandReply silc_command_reply_list[] =
42 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
43 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
44 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
45 SILC_CLIENT_CMD_REPLY(nick, NICK),
46 SILC_CLIENT_CMD_REPLY(list, LIST),
47 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
48 SILC_CLIENT_CMD_REPLY(invite, INVITE),
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(shutdown, SHUTDOWN),
63 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
64 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
65 SILC_CLIENT_CMD_REPLY(users, USERS),
66 SILC_CLIENT_CMD_REPLY(ban, BAN),
71 const SilcCommandStatusMessage silc_command_status_messages[] = {
73 { STAT(NO_SUCH_NICK), "There was no such nickname" },
74 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
75 { STAT(NO_SUCH_SERVER), "No such server" },
76 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
77 { STAT(NO_RECIPIENT), "No recipient given" },
78 { STAT(UNKNOWN_COMMAND), "Unknown command" },
79 { STAT(WILDCARDS), "Unknown command" },
80 { STAT(NO_CLIENT_ID), "No Client ID given" },
81 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
82 { STAT(NO_SERVER_ID), "No Server ID given" },
83 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
84 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
85 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
86 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
87 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
88 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
89 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
90 { STAT(USER_ON_CHANNEL), "User already on the channel" },
91 { STAT(NOT_REGISTERED), "You have not registered" },
92 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
93 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
94 { STAT(PERM_DENIED), "Permission denied" },
95 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
96 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
97 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
98 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
99 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
100 { STAT(UNKNOWN_MODE), "Unknown mode" },
101 { STAT(NOT_YOU), "Cannot change mode for other users" },
102 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
103 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
104 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
105 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
106 { STAT(BAD_NICKNAME), "Bad nickname" },
107 { STAT(BAD_CHANNEL), "Bad channel name" },
108 { STAT(AUTH_FAILED), "Authentication failed" },
109 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
113 /* Command reply operation that is called at the end of all command replys.
114 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
115 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
116 #define ARGS cmd->client, cmd->sock->user_data, \
117 cmd->payload, TRUE, silc_command_get(cmd->payload), status
119 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
120 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
121 cmd->sock->user_data, cmd->payload, FALSE, \
122 silc_command_get(cmd->payload), status)
124 /* Process received command reply. */
126 void silc_client_command_reply_process(SilcClient client,
127 SilcSocketConnection sock,
128 SilcPacketContext *packet)
130 SilcBuffer buffer = packet->buffer;
131 SilcClientCommandReply *cmd;
132 SilcClientCommandReplyContext ctx;
133 SilcCommandPayload payload;
135 unsigned short ident;
137 /* Get command reply payload from packet */
138 payload = silc_command_payload_parse(buffer);
140 /* Silently ignore bad reply packet */
141 SILC_LOG_DEBUG(("Bad command reply packet"));
145 /* Allocate command reply context. This must be free'd by the
146 command reply routine receiving it. */
147 ctx = silc_calloc(1, sizeof(*ctx));
148 ctx->client = client;
150 ctx->payload = payload;
151 ctx->args = silc_command_get_args(ctx->payload);
152 ctx->packet = packet;
153 ident = silc_command_get_ident(ctx->payload);
155 /* Check for pending commands and mark to be exeucted */
156 silc_client_command_pending_check(sock->user_data, ctx,
157 silc_command_get(ctx->payload), ident);
159 /* Execute command reply */
160 command = silc_command_get(ctx->payload);
161 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
162 if (cmd->cmd == command)
165 if (cmd == NULL || !cmd->cb) {
173 /* Returns status message string */
175 char *silc_client_command_status_message(SilcCommandStatus status)
179 for (i = 0; silc_command_status_messages[i].message; i++) {
180 if (silc_command_status_messages[i].status == status)
184 if (silc_command_status_messages[i].message == NULL)
187 return silc_command_status_messages[i].message;
190 /* Free command reply context and its internals. */
192 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
195 silc_command_free_payload(cmd->payload);
201 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
202 SilcCommandStatus status)
204 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
205 SilcClientID *client_id;
206 SilcIDCacheEntry id_cache = NULL;
207 SilcClientEntry client_entry = NULL;
209 unsigned char *id_data, *tmp;
210 char *nickname = NULL, *username = NULL;
211 char *realname = NULL;
212 unsigned int idle = 0, mode = 0;
213 SilcBuffer channels = NULL;
215 argc = silc_argument_get_arg_num(cmd->args);
217 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
223 client_id = silc_id_payload_parse_id(id_data, len);
229 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
230 username = silc_argument_get_arg_type(cmd->args, 4, &len);
231 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
232 if (!nickname || !username || !realname) {
237 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
239 channels = silc_buffer_alloc(len);
240 silc_buffer_pull_tail(channels, SILC_BUFFER_END(channels));
241 silc_buffer_put(channels, tmp, len);
244 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
246 SILC_GET32_MSB(mode, tmp);
248 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
250 SILC_GET32_MSB(idle, tmp);
252 /* Check if we have this client cached already. */
253 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
254 SILC_ID_CLIENT, &id_cache)) {
255 SILC_LOG_DEBUG(("Adding new client entry"));
257 client_entry = silc_calloc(1, sizeof(*client_entry));
258 client_entry->id = client_id;
259 silc_parse_nickname(nickname, &client_entry->nickname,
260 &client_entry->server, &client_entry->num);
261 client_entry->username = strdup(username);
263 client_entry->realname = strdup(realname);
264 client_entry->mode = mode;
266 /* Add client to cache */
267 silc_idcache_add(conn->client_cache, client_entry->nickname,
268 strlen(client_entry->nickname),
269 SILC_ID_CLIENT, client_id, (void *)client_entry,
272 client_entry = (SilcClientEntry)id_cache->context;
273 if (client_entry->nickname)
274 silc_free(client_entry->nickname);
275 if (client_entry->server)
276 silc_free(client_entry->server);
277 if (client_entry->username)
278 silc_free(client_entry->username);
279 if (client_entry->realname)
280 silc_free(client_entry->realname);
281 client_entry->mode = mode;
283 SILC_LOG_DEBUG(("Updating client entry"));
285 silc_parse_nickname(nickname, &client_entry->nickname,
286 &client_entry->server, &client_entry->num);
287 client_entry->username = strdup(username);
289 client_entry->realname = strdup(realname);
291 id_cache->data = client_entry->nickname;
292 id_cache->data_len = strlen(client_entry->nickname);
293 silc_idcache_sort_by_data(conn->client_cache);
295 silc_free(client_id);
298 /* Notify application */
300 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
301 channels, mode, idle));
304 silc_buffer_free(channels);
307 /* Received reply for WHOIS command. This maybe called several times
308 for one WHOIS command as server may reply with list of results. */
310 SILC_CLIENT_CMD_REPLY_FUNC(whois)
312 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
313 SilcCommandStatus status;
316 SILC_LOG_DEBUG(("Start"));
318 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
319 SILC_GET16_MSB(status, tmp);
320 if (status != SILC_STATUS_OK &&
321 status != SILC_STATUS_LIST_START &&
322 status != SILC_STATUS_LIST_ITEM &&
323 status != SILC_STATUS_LIST_END) {
328 /* Display one whois reply */
329 if (status == SILC_STATUS_OK)
330 silc_client_command_reply_whois_save(cmd, status);
333 if (status == SILC_STATUS_LIST_START ||
334 status == SILC_STATUS_LIST_ITEM ||
335 status == SILC_STATUS_LIST_END)
336 silc_client_command_reply_whois_save(cmd, status);
338 /* Pending callbacks are not executed if this was an list entry */
339 if (status != SILC_STATUS_OK &&
340 status != SILC_STATUS_LIST_END) {
341 silc_client_command_reply_free(cmd);
345 /* Execute any pending command callbacks */
346 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
349 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
350 silc_client_command_reply_free(cmd);
353 /* Received reply for WHOWAS command. */
355 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
357 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
358 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
359 SilcCommandStatus status;
360 SilcClientID *client_id;
361 SilcIDCacheEntry id_cache = NULL;
362 SilcClientEntry client_entry = NULL;
364 unsigned char *id_data, *tmp;
365 char *nickname, *username;
366 char *realname = NULL;
368 SILC_LOG_DEBUG(("Start"));
370 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
371 SILC_GET16_MSB(status, tmp);
372 if (status != SILC_STATUS_OK &&
373 status != SILC_STATUS_LIST_START &&
374 status != SILC_STATUS_LIST_ITEM &&
375 status != SILC_STATUS_LIST_END) {
380 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
386 client_id = silc_id_payload_parse_id(id_data, len);
392 /* Get the client entry, if exists */
393 if (silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
394 SILC_ID_CLIENT, &id_cache))
395 client_entry = (SilcClientEntry)id_cache->context;
396 silc_free(client_id);
398 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
399 username = silc_argument_get_arg_type(cmd->args, 4, &len);
400 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
401 if (!nickname || !username) {
405 /* Notify application. We don't save any history information to any
406 cache. Just pass the data to the application for displaying on
408 COMMAND_REPLY((ARGS, client_entry, nickname, username, realname));
410 /* Pending callbacks are not executed if this was an list entry */
411 if (status != SILC_STATUS_OK &&
412 status != SILC_STATUS_LIST_END) {
413 silc_client_command_reply_free(cmd);
417 /* Execute any pending command callbacks */
418 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
421 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
422 silc_client_command_reply_free(cmd);
426 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
427 SilcCommandStatus status)
429 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
430 SilcClientID *client_id;
431 SilcIDCacheEntry id_cache = NULL;
432 SilcClientEntry client_entry = NULL;
434 unsigned char *id_data;
435 char *nickname = NULL, *username = NULL;
437 argc = silc_argument_get_arg_num(cmd->args);
439 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
445 client_id = silc_id_payload_parse_id(id_data, len);
451 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
452 username = silc_argument_get_arg_type(cmd->args, 4, &len);
454 /* Check if we have this client cached already. */
455 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
456 SILC_ID_CLIENT, &id_cache)) {
457 SILC_LOG_DEBUG(("Adding new client entry"));
459 client_entry = silc_calloc(1, sizeof(*client_entry));
460 client_entry->id = client_id;
461 silc_parse_nickname(nickname, &client_entry->nickname,
462 &client_entry->server, &client_entry->num);
464 client_entry->username = strdup(username);
466 /* Add client to cache */
467 silc_idcache_add(conn->client_cache, client_entry->nickname,
468 strlen(client_entry->nickname),
469 SILC_ID_CLIENT, client_id, (void *)client_entry,
472 client_entry = (SilcClientEntry)id_cache->context;
473 if (client_entry->nickname)
474 silc_free(client_entry->nickname);
475 if (client_entry->server)
476 silc_free(client_entry->server);
477 if (username && client_entry->username)
478 silc_free(client_entry->username);
480 SILC_LOG_DEBUG(("Updating client entry"));
482 silc_parse_nickname(nickname, &client_entry->nickname,
483 &client_entry->server, &client_entry->num);
486 client_entry->username = strdup(username);
488 id_cache->data = client_entry->nickname;
489 id_cache->data_len = strlen(client_entry->nickname);
490 silc_idcache_sort_by_data(conn->client_cache);
492 silc_free(client_id);
495 /* Notify application */
496 COMMAND_REPLY((ARGS, client_entry, nickname, username));
499 /* Received reply for IDENTIFY command. This maybe called several times
500 for one IDENTIFY command as server may reply with list of results.
501 This is totally silent and does not print anything on screen. */
503 SILC_CLIENT_CMD_REPLY_FUNC(identify)
505 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
506 SilcCommandStatus status;
509 SILC_LOG_DEBUG(("Start"));
511 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
512 SILC_GET16_MSB(status, tmp);
513 if (status != SILC_STATUS_OK &&
514 status != SILC_STATUS_LIST_START &&
515 status != SILC_STATUS_LIST_ITEM &&
516 status != SILC_STATUS_LIST_END) {
521 /* Save one IDENTIFY entry */
522 if (status == SILC_STATUS_OK)
523 silc_client_command_reply_identify_save(cmd, status);
526 if (status == SILC_STATUS_LIST_START ||
527 status == SILC_STATUS_LIST_ITEM ||
528 status == SILC_STATUS_LIST_END)
529 silc_client_command_reply_identify_save(cmd, status);
531 /* Pending callbacks are not executed if this was an list entry */
532 if (status != SILC_STATUS_OK &&
533 status != SILC_STATUS_LIST_END) {
534 silc_client_command_reply_free(cmd);
538 /* Execute any pending command callbacks */
539 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
542 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
543 silc_client_command_reply_free(cmd);
546 /* Received reply for command NICK. If everything went without errors
547 we just received our new Client ID. */
549 SILC_CLIENT_CMD_REPLY_FUNC(nick)
551 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
552 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
553 SilcCommandStatus status;
556 unsigned int argc, len;
558 SILC_LOG_DEBUG(("Start"));
560 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
561 if (status != SILC_STATUS_OK) {
562 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
563 silc_client_command_status_message(status));
568 argc = silc_argument_get_arg_num(cmd->args);
569 if (argc < 2 || argc > 2) {
570 cmd->client->ops->say(cmd->client, conn,
571 "Cannot set nickname: bad reply to command");
576 /* Take received Client ID */
577 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
578 idp = silc_id_payload_parse_data(tmp, len);
583 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
585 /* Notify application */
586 COMMAND_REPLY((ARGS, conn->local_entry));
588 /* Execute any pending command callbacks */
589 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
592 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
593 silc_client_command_reply_free(cmd);
596 /* Received reply to the LIST command. */
598 SILC_CLIENT_CMD_REPLY_FUNC(list)
600 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
601 SilcCommandStatus status;
602 unsigned char *tmp, *name, *topic;
603 unsigned int usercount = 0;
605 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
606 SILC_GET16_MSB(status, tmp);
607 if (status != SILC_STATUS_OK &&
608 status != SILC_STATUS_LIST_START &&
609 status != SILC_STATUS_LIST_ITEM &&
610 status != SILC_STATUS_LIST_END) {
615 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
616 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
617 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
619 SILC_GET32_MSB(usercount, tmp);
621 /* Notify application */
622 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
624 /* Pending callbacks are not executed if this was an list entry */
625 if (status != SILC_STATUS_OK &&
626 status != SILC_STATUS_LIST_END) {
627 silc_client_command_reply_free(cmd);
631 /* Execute any pending command callbacks */
632 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
635 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
636 silc_client_command_reply_free(cmd);
639 /* Received reply to topic command. */
641 SILC_CLIENT_CMD_REPLY_FUNC(topic)
643 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
644 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
645 SilcCommandStatus status;
646 SilcChannelEntry channel;
647 SilcChannelID *channel_id = NULL;
648 SilcIDCacheEntry id_cache = NULL;
651 unsigned int argc, len;
653 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
654 if (status != SILC_STATUS_OK) {
655 cmd->client->ops->say(cmd->client, conn,
656 "%s", silc_client_command_status_message(status));
658 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
659 silc_client_command_reply_free(cmd);
663 argc = silc_argument_get_arg_num(cmd->args);
664 if (argc < 1 || argc > 3) {
669 /* Take Channel ID */
670 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
675 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
679 channel_id = silc_id_payload_parse_id(tmp, len);
683 /* Get the channel entry */
684 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
685 SILC_ID_CHANNEL, &id_cache)) {
686 silc_free(channel_id);
691 channel = (SilcChannelEntry)id_cache->context;
693 cmd->client->ops->say(cmd->client, conn,
694 "Topic on channel %s: %s", channel->channel_name,
697 /* Notify application */
698 COMMAND_REPLY((ARGS, channel, topic));
700 /* Execute any pending command callbacks */
701 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
704 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
705 silc_client_command_reply_free(cmd);
708 /* Received reply to invite command. */
710 SILC_CLIENT_CMD_REPLY_FUNC(invite)
712 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
713 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
714 SilcCommandStatus status;
717 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
718 SILC_GET16_MSB(status, tmp);
719 if (status != SILC_STATUS_OK) {
720 cmd->client->ops->say(cmd->client, conn,
721 "%s", silc_client_command_status_message(status));
723 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
724 silc_client_command_reply_free(cmd);
728 /* Notify application */
729 COMMAND_REPLY((ARGS));
731 /* Execute any pending command callbacks */
732 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
734 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
735 silc_client_command_reply_free(cmd);
738 /* Received reply to the KILL command. */
740 SILC_CLIENT_CMD_REPLY_FUNC(kill)
742 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
743 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
744 SilcCommandStatus status;
747 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
748 SILC_GET16_MSB(status, tmp);
749 if (status != SILC_STATUS_OK) {
750 cmd->client->ops->say(cmd->client, conn,
751 "%s", silc_client_command_status_message(status));
756 /* Notify application */
757 COMMAND_REPLY((ARGS));
759 /* Execute any pending command callbacks */
760 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
763 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
764 silc_client_command_reply_free(cmd);
767 /* Received reply to INFO command. We receive the server ID and some
768 information about the server user requested. */
770 SILC_CLIENT_CMD_REPLY_FUNC(info)
772 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
773 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
774 SilcClient client = cmd->client;
775 SilcCommandStatus status;
778 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
779 SILC_GET16_MSB(status, tmp);
780 if (status != SILC_STATUS_OK) {
781 cmd->client->ops->say(cmd->client, conn,
782 "%s", silc_client_command_status_message(status));
784 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
785 silc_client_command_reply_free(cmd);
790 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
794 /* XXX save server id */
796 /* Get server name */
797 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
801 /* Get server info */
802 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
806 client->ops->say(cmd->client, conn, "Info: %s", tmp);
808 /* Notify application */
809 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
811 /* Execute any pending command callbacks */
812 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
815 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
816 silc_client_command_reply_free(cmd);
819 /* Received reply to PING command. The reply time is shown to user. */
821 SILC_CLIENT_CMD_REPLY_FUNC(ping)
823 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
824 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
825 SilcCommandStatus status;
828 time_t diff, curtime;
830 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
831 if (status != SILC_STATUS_OK) {
832 cmd->client->ops->say(cmd->client, conn,
833 "%s", silc_client_command_status_message(status));
838 curtime = time(NULL);
839 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
840 cmd->packet->src_id_type);
846 for (i = 0; i < conn->ping_count; i++) {
847 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
848 diff = curtime - conn->ping[i].start_time;
849 cmd->client->ops->say(cmd->client, conn,
850 "Ping reply from %s: %d second%s",
851 conn->ping[i].dest_name, diff,
852 diff == 1 ? "" : "s");
854 conn->ping[i].start_time = 0;
855 silc_free(conn->ping[i].dest_id);
856 conn->ping[i].dest_id = NULL;
857 silc_free(conn->ping[i].dest_name);
858 conn->ping[i].dest_name = NULL;
865 /* Notify application */
866 COMMAND_REPLY((ARGS));
868 /* Execute any pending command callbacks */
869 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
872 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
873 silc_client_command_reply_free(cmd);
876 /* Received reply for JOIN command. */
878 SILC_CLIENT_CMD_REPLY_FUNC(join)
880 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
881 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
882 SilcCommandStatus status;
883 SilcIDPayload idp = NULL;
884 SilcChannelEntry channel;
885 SilcIDCacheEntry id_cache = NULL;
887 unsigned int argc, mode, len, list_count;
888 char *topic, *tmp, *channel_name = NULL, *hmac;
889 SilcBuffer keyp, client_id_list, client_mode_list;
892 SILC_LOG_DEBUG(("Start"));
894 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
895 if (status != SILC_STATUS_OK) {
896 cmd->client->ops->say(cmd->client, conn,
897 "%s", silc_client_command_status_message(status));
902 argc = silc_argument_get_arg_num(cmd->args);
903 if (argc < 7 || argc > 14) {
904 cmd->client->ops->say(cmd->client, conn,
905 "Cannot join channel: Bad reply packet");
910 /* Get channel name */
911 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
913 cmd->client->ops->say(cmd->client, conn,
914 "Cannot join channel: Bad reply packet");
918 channel_name = strdup(tmp);
921 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
923 cmd->client->ops->say(cmd->client, conn,
924 "Cannot join channel: Bad reply packet");
926 silc_free(channel_name);
929 idp = silc_id_payload_parse_data(tmp, len);
932 silc_free(channel_name);
936 /* Get channel mode */
937 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
939 SILC_GET32_MSB(mode, tmp);
943 /* Get channel key */
944 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
946 silc_id_payload_free(idp);
947 silc_free(channel_name);
950 keyp = silc_buffer_alloc(len);
951 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
952 silc_buffer_put(keyp, tmp, len);
955 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
957 /* Save received Channel ID. This actually creates the channel */
958 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
960 silc_id_payload_free(idp);
963 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
965 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
966 cmd->client->ops->say(cmd->client, conn,
967 "Cannot join channel: Unsupported HMAC `%s'",
970 silc_free(channel_name);
975 /* Get the list count */
976 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
979 SILC_GET32_MSB(list_count, tmp);
981 /* Get Client ID list */
982 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
986 client_id_list = silc_buffer_alloc(len);
987 silc_buffer_pull_tail(client_id_list, len);
988 silc_buffer_put(client_id_list, tmp, len);
990 /* Get client mode list */
991 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
995 client_mode_list = silc_buffer_alloc(len);
996 silc_buffer_pull_tail(client_mode_list, len);
997 silc_buffer_put(client_mode_list, tmp, len);
999 /* Add clients we received in the reply to the channel */
1000 for (i = 0; i < list_count; i++) {
1001 unsigned short idp_len;
1003 SilcClientID *client_id;
1004 SilcClientEntry client_entry;
1007 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1009 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1014 SILC_GET32_MSB(mode, client_mode_list->data);
1016 /* Check if we have this client cached already. */
1017 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1018 SILC_ID_CLIENT, &id_cache)) {
1019 /* No, we don't have it, add entry for it. */
1020 client_entry = silc_calloc(1, sizeof(*client_entry));
1021 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1022 silc_idcache_add(conn->client_cache, NULL, 0, SILC_ID_CLIENT,
1023 client_entry->id, (void *)client_entry, FALSE, FALSE);
1025 /* Yes, we have it already */
1026 client_entry = (SilcClientEntry)id_cache->context;
1029 /* Join the client to the channel */
1030 chu = silc_calloc(1, sizeof(*chu));
1031 chu->client = client_entry;
1033 silc_list_add(channel->clients, chu);
1034 silc_free(client_id);
1036 silc_buffer_pull(client_id_list, idp_len);
1037 silc_buffer_pull(client_mode_list, 4);
1039 silc_buffer_push(client_id_list, client_id_list->data -
1040 client_id_list->head);
1041 silc_buffer_push(client_mode_list, client_mode_list->data -
1042 client_mode_list->head);
1044 /* Save channel key */
1045 silc_client_save_channel_key(conn, keyp, channel);
1047 /* Notify application */
1048 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0, keyp->head, NULL,
1049 NULL, topic, hmac, list_count, client_id_list,
1052 /* Execute any pending command callbacks */
1053 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1055 silc_buffer_free(keyp);
1056 silc_buffer_free(client_id_list);
1057 silc_buffer_free(client_mode_list);
1060 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1061 silc_client_command_reply_free(cmd);
1064 /* Received reply for MOTD command */
1066 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1068 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1069 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1070 SilcCommandStatus status;
1071 unsigned int argc, i;
1073 char *motd = NULL, *cp, line[256];
1075 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1076 SILC_GET16_MSB(status, tmp);
1077 if (status != SILC_STATUS_OK) {
1078 cmd->client->ops->say(cmd->client, conn,
1079 "%s", silc_client_command_status_message(status));
1080 COMMAND_REPLY_ERROR;
1084 argc = silc_argument_get_arg_num(cmd->args);
1086 COMMAND_REPLY_ERROR;
1091 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1093 COMMAND_REPLY_ERROR;
1100 if (cp[i++] == '\n') {
1101 memset(line, 0, sizeof(line));
1102 strncat(line, cp, i - 1);
1108 cmd->client->ops->say(cmd->client, conn, "%s", line);
1117 /* Notify application */
1118 COMMAND_REPLY((ARGS, motd));
1120 /* Execute any pending command callbacks */
1121 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1124 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1125 silc_client_command_reply_free(cmd);
1128 /* Received reply tot he UMODE command. Save the current user mode */
1130 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1132 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1133 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1134 SilcCommandStatus status;
1138 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1139 SILC_GET16_MSB(status, tmp);
1140 if (status != SILC_STATUS_OK) {
1141 cmd->client->ops->say(cmd->client, conn,
1142 "%s", silc_client_command_status_message(status));
1143 COMMAND_REPLY_ERROR;
1147 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1149 COMMAND_REPLY_ERROR;
1153 SILC_GET32_MSB(mode, tmp);
1154 conn->local_entry->mode = mode;
1156 /* Notify application */
1157 COMMAND_REPLY((ARGS, mode));
1159 /* Execute any pending command callbacks */
1160 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1163 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1164 silc_client_command_reply_free(cmd);
1167 /* Received reply for CMODE command. */
1169 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1171 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1172 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1173 SilcCommandStatus status;
1176 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1177 if (status != SILC_STATUS_OK) {
1178 cmd->client->ops->say(cmd->client, conn,
1179 "%s", silc_client_command_status_message(status));
1180 COMMAND_REPLY_ERROR;
1184 /* Get channel mode */
1185 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1187 COMMAND_REPLY_ERROR;
1191 /* Notify application */
1192 COMMAND_REPLY((ARGS, tmp));
1194 /* Execute any pending command callbacks */
1195 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1198 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1199 silc_client_command_reply_free(cmd);
1202 /* Received reply for CUMODE command */
1204 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1206 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1207 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1208 SilcCommandStatus status;
1209 SilcIDCacheEntry id_cache = NULL;
1210 SilcClientID *client_id;
1211 unsigned char *tmp, *id;
1214 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1215 if (status != SILC_STATUS_OK) {
1216 cmd->client->ops->say(cmd->client, conn,
1217 "%s", silc_client_command_status_message(status));
1218 COMMAND_REPLY_ERROR;
1222 /* Get channel mode */
1223 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1225 COMMAND_REPLY_ERROR;
1230 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1232 COMMAND_REPLY_ERROR;
1235 client_id = silc_id_payload_parse_id(id, len);
1237 COMMAND_REPLY_ERROR;
1241 /* Get client entry */
1242 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1243 SILC_ID_CLIENT, &id_cache)) {
1244 COMMAND_REPLY_ERROR;
1248 /* Notify application */
1249 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1250 silc_free(client_id);
1252 /* Execute any pending command callbacks */
1253 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1256 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1257 silc_client_command_reply_free(cmd);
1260 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1262 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1263 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1264 SilcCommandStatus status;
1267 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1268 SILC_GET16_MSB(status, tmp);
1269 if (status != SILC_STATUS_OK) {
1270 cmd->client->ops->say(cmd->client, conn,
1271 "%s", silc_client_command_status_message(status));
1272 COMMAND_REPLY_ERROR;
1276 /* Notify application */
1277 COMMAND_REPLY((ARGS));
1279 /* Execute any pending command callbacks */
1280 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1283 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1284 silc_client_command_reply_free(cmd);
1287 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1289 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1290 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1291 SilcCommandStatus status;
1294 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1295 SILC_GET16_MSB(status, tmp);
1296 if (status != SILC_STATUS_OK) {
1297 cmd->client->ops->say(cmd->client, conn,
1298 "%s", silc_client_command_status_message(status));
1299 COMMAND_REPLY_ERROR;
1303 /* Notify application */
1304 COMMAND_REPLY((ARGS));
1306 /* Execute any pending command callbacks */
1307 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1310 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1311 silc_client_command_reply_free(cmd);
1314 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1316 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1317 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1318 SilcCommandStatus status;
1321 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1322 SILC_GET16_MSB(status, tmp);
1323 if (status != SILC_STATUS_OK) {
1324 cmd->client->ops->say(cmd->client, conn,
1325 "%s", silc_client_command_status_message(status));
1326 COMMAND_REPLY_ERROR;
1330 /* Notify application */
1331 COMMAND_REPLY((ARGS));
1333 /* Execute any pending command callbacks */
1334 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1337 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1338 silc_client_command_reply_free(cmd);
1341 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1343 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1344 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1345 SilcCommandStatus status;
1348 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1349 SILC_GET16_MSB(status, tmp);
1350 if (status != SILC_STATUS_OK) {
1351 cmd->client->ops->say(cmd->client, conn,
1352 "%s", silc_client_command_status_message(status));
1353 COMMAND_REPLY_ERROR;
1357 /* Notify application */
1358 COMMAND_REPLY((ARGS));
1360 /* Execute any pending command callbacks */
1361 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1364 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1365 silc_client_command_reply_free(cmd);
1368 SILC_CLIENT_CMD_REPLY_FUNC(restart)
1370 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1371 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1372 SilcCommandStatus status;
1375 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1376 SILC_GET16_MSB(status, tmp);
1377 if (status != SILC_STATUS_OK) {
1378 cmd->client->ops->say(cmd->client, conn,
1379 "%s", silc_client_command_status_message(status));
1380 COMMAND_REPLY_ERROR;
1384 /* Notify application */
1385 COMMAND_REPLY((ARGS));
1387 /* Execute any pending command callbacks */
1388 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_RESTART);
1391 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_RESTART);
1392 silc_client_command_reply_free(cmd);
1395 SILC_CLIENT_CMD_REPLY_FUNC(close)
1397 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1398 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1399 SilcCommandStatus status;
1402 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1403 SILC_GET16_MSB(status, tmp);
1404 if (status != SILC_STATUS_OK) {
1405 cmd->client->ops->say(cmd->client, conn,
1406 "%s", silc_client_command_status_message(status));
1407 COMMAND_REPLY_ERROR;
1411 /* Notify application */
1412 COMMAND_REPLY((ARGS));
1414 /* Execute any pending command callbacks */
1415 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1418 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1419 silc_client_command_reply_free(cmd);
1422 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1424 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1425 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1426 SilcCommandStatus status;
1429 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1430 SILC_GET16_MSB(status, tmp);
1431 if (status != SILC_STATUS_OK) {
1432 cmd->client->ops->say(cmd->client, conn,
1433 "%s", silc_client_command_status_message(status));
1434 COMMAND_REPLY_ERROR;
1438 /* Notify application */
1439 COMMAND_REPLY((ARGS));
1441 /* Execute any pending command callbacks */
1442 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1445 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1446 silc_client_command_reply_free(cmd);
1449 /* Reply to LEAVE command. */
1451 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1453 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1454 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1455 SilcCommandStatus status;
1458 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1459 SILC_GET16_MSB(status, tmp);
1460 if (status != SILC_STATUS_OK) {
1461 cmd->client->ops->say(cmd->client, conn,
1462 "%s", silc_client_command_status_message(status));
1463 COMMAND_REPLY_ERROR;
1467 /* Notify application */
1468 COMMAND_REPLY((ARGS));
1470 /* Execute any pending command callbacks */
1471 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1474 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1475 silc_client_command_reply_free(cmd);
1478 /* Reply to USERS command. Received list of client ID's and theirs modes
1479 on the channel we requested. */
1481 SILC_CLIENT_CMD_REPLY_FUNC(users)
1483 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1484 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1485 SilcCommandStatus status;
1486 SilcIDCacheEntry id_cache = NULL;
1487 SilcChannelEntry channel;
1488 SilcChannelUser chu;
1489 SilcChannelID *channel_id = NULL;
1490 SilcBuffer client_id_list;
1491 SilcBuffer client_mode_list;
1493 unsigned int tmp_len, list_count;
1495 unsigned char **res_argv = NULL;
1496 unsigned int *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1498 SILC_LOG_DEBUG(("Start"));
1500 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1501 SILC_GET16_MSB(status, tmp);
1502 if (status != SILC_STATUS_OK) {
1503 cmd->client->ops->say(cmd->client, conn,
1504 "%s", silc_client_command_status_message(status));
1505 COMMAND_REPLY_ERROR;
1509 /* Get channel ID */
1510 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1513 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1517 /* Get the list count */
1518 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1521 SILC_GET32_MSB(list_count, tmp);
1523 /* Get Client ID list */
1524 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1528 client_id_list = silc_buffer_alloc(tmp_len);
1529 silc_buffer_pull_tail(client_id_list, tmp_len);
1530 silc_buffer_put(client_id_list, tmp, tmp_len);
1532 /* Get client mode list */
1533 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1537 client_mode_list = silc_buffer_alloc(tmp_len);
1538 silc_buffer_pull_tail(client_mode_list, tmp_len);
1539 silc_buffer_put(client_mode_list, tmp, tmp_len);
1541 /* Get channel entry */
1542 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1543 SILC_ID_CHANNEL, &id_cache)) {
1544 COMMAND_REPLY_ERROR;
1547 channel = (SilcChannelEntry)id_cache->context;
1549 /* Remove old client list from channel. */
1550 silc_list_start(channel->clients);
1551 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1552 silc_list_del(channel->clients, chu);
1556 /* Cache the received Client ID's and modes. This cache expires
1557 whenever server sends notify message to channel. It means two things;
1558 some user has joined or leaved the channel. XXX! */
1559 for (i = 0; i < list_count; i++) {
1560 unsigned short idp_len;
1562 SilcClientID *client_id;
1563 SilcClientEntry client;
1566 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1568 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1573 SILC_GET32_MSB(mode, client_mode_list->data);
1575 /* Check if we have this client cached already. */
1576 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1577 SILC_ID_CLIENT, &id_cache)) {
1578 /* No we don't have it, query it from the server. Assemble argument
1579 table that will be sent fr the IDENTIFY command later. */
1580 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1582 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1584 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1586 res_argv[res_argc] = client_id_list->data;
1587 res_argv_lens[res_argc] = idp_len;
1588 res_argv_types[res_argc] = res_argc + 3;
1591 /* Found the client, join it to the channel */
1592 client = (SilcClientEntry)id_cache->context;
1593 chu = silc_calloc(1, sizeof(*chu));
1594 chu->client = client;
1596 silc_list_add(channel->clients, chu);
1598 silc_free(client_id);
1602 silc_buffer_pull(client_id_list, idp_len);
1603 silc_buffer_pull(client_mode_list, 4);
1606 /* Query the client information from server if the list included clients
1607 that we don't know about. */
1611 /* Send the IDENTIFY command to server */
1612 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1613 res_argc, res_argv, res_argv_lens,
1614 res_argv_types, ++conn->cmd_ident);
1615 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1616 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1619 /* Register pending command callback. After we've received the IDENTIFY
1620 command reply we will reprocess this command reply by re-calling this
1621 USERS command reply callback. */
1622 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1623 NULL, silc_client_command_reply_users, cmd);
1625 silc_buffer_free(res_cmd);
1627 silc_free(channel_id);
1629 silc_free(res_argv);
1630 silc_free(res_argv_lens);
1631 silc_free(res_argv_types);
1635 /* Notify application */
1636 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1638 /* Execute any pending command callbacks */
1639 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1641 silc_buffer_free(client_id_list);
1642 silc_buffer_free(client_mode_list);
1646 silc_free(channel_id);
1647 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1648 silc_client_command_reply_free(cmd);
1651 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1653 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1654 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1655 SilcCommandStatus status;
1656 SilcIDCacheEntry id_cache = NULL;
1657 SilcChannelEntry channel;
1658 SilcChannelID *channel_id;
1662 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1663 SILC_GET16_MSB(status, tmp);
1664 if (status != SILC_STATUS_OK) {
1665 cmd->client->ops->say(cmd->client, conn,
1666 "%s", silc_client_command_status_message(status));
1667 COMMAND_REPLY_ERROR;
1671 /* Take Channel ID */
1672 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1676 channel_id = silc_id_payload_parse_id(tmp, len);
1680 /* Get the channel entry */
1681 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1682 SILC_ID_CHANNEL, &id_cache)) {
1683 silc_free(channel_id);
1684 COMMAND_REPLY_ERROR;
1688 channel = (SilcChannelEntry)id_cache->context;
1690 /* Get the ban list */
1691 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1693 /* Notify application */
1694 COMMAND_REPLY((ARGS, channel, tmp));
1696 /* Execute any pending command callbacks */
1697 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1700 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1701 silc_client_command_reply_free(cmd);