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(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),
65 SILC_CLIENT_CMD_REPLY(ban, BAN),
70 const SilcCommandStatusMessage silc_command_status_messages[] = {
72 { STAT(NO_SUCH_NICK), "There was no such nickname" },
73 { STAT(NO_SUCH_CHANNEL), "There was no such channel" },
74 { STAT(NO_SUCH_SERVER), "No such server" },
75 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
76 { STAT(NO_RECIPIENT), "No recipient given" },
77 { STAT(UNKNOWN_COMMAND), "Unknown command" },
78 { STAT(WILDCARDS), "Unknown command" },
79 { STAT(NO_CLIENT_ID), "No Client ID given" },
80 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
81 { STAT(NO_SERVER_ID), "No Server ID given" },
82 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
83 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
84 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
85 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
86 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
87 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
88 { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
89 { STAT(USER_ON_CHANNEL), "User already on the channel" },
90 { STAT(NOT_REGISTERED), "You have not registered" },
91 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
92 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
93 { STAT(PERM_DENIED), "Permission denied" },
94 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
95 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
96 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
97 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
98 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
99 { STAT(UNKNOWN_MODE), "Unknown mode" },
100 { STAT(NOT_YOU), "Cannot change mode for other users" },
101 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
102 { STAT(NO_CHANNEL_FOPRIV),"Permission denied. You are not channel founder" },
103 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
104 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
105 { STAT(BAD_NICKNAME), "Bad nickname" },
106 { STAT(BAD_CHANNEL), "Bad channel name" },
107 { STAT(AUTH_FAILED), "Authentication failed" },
108 { STAT(UNKNOWN_ALGORITHM), "Unsupported algorithm" },
112 /* Command reply operation that is called at the end of all command replys.
113 Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
114 #define COMMAND_REPLY(args) cmd->client->ops->command_reply args
115 #define ARGS cmd->client, cmd->sock->user_data, \
116 cmd->payload, TRUE, silc_command_get(cmd->payload), status
118 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
119 #define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
120 cmd->sock->user_data, cmd->payload, FALSE, \
121 silc_command_get(cmd->payload), status)
123 /* Process received command reply. */
125 void silc_client_command_reply_process(SilcClient client,
126 SilcSocketConnection sock,
127 SilcPacketContext *packet)
129 SilcBuffer buffer = packet->buffer;
130 SilcClientCommandReply *cmd;
131 SilcClientCommandReplyContext ctx;
132 SilcCommandPayload payload;
136 /* Get command reply payload from packet */
137 payload = silc_command_payload_parse(buffer);
139 /* Silently ignore bad reply packet */
140 SILC_LOG_DEBUG(("Bad command reply packet"));
144 /* Allocate command reply context. This must be free'd by the
145 command reply routine receiving it. */
146 ctx = silc_calloc(1, sizeof(*ctx));
147 ctx->client = client;
149 ctx->payload = payload;
150 ctx->args = silc_command_get_args(ctx->payload);
151 ctx->packet = packet;
152 ident = silc_command_get_ident(ctx->payload);
154 /* Check for pending commands and mark to be exeucted */
155 silc_client_command_pending_check(sock->user_data, ctx,
156 silc_command_get(ctx->payload), ident);
158 /* Execute command reply */
159 command = silc_command_get(ctx->payload);
160 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
161 if (cmd->cmd == command)
164 if (cmd == NULL || !cmd->cb) {
172 /* Returns status message string */
174 char *silc_client_command_status_message(SilcCommandStatus status)
178 for (i = 0; silc_command_status_messages[i].message; i++) {
179 if (silc_command_status_messages[i].status == status)
183 if (silc_command_status_messages[i].message == NULL)
186 return silc_command_status_messages[i].message;
189 /* Free command reply context and its internals. */
191 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
194 silc_command_free_payload(cmd->payload);
200 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
201 SilcCommandStatus status)
203 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
204 SilcClientID *client_id;
205 SilcIDCacheEntry id_cache = NULL;
206 SilcClientEntry client_entry = NULL;
209 unsigned char *id_data, *tmp;
210 char *nickname = NULL, *username = NULL;
211 char *realname = NULL;
212 uint32 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;
435 unsigned char *id_data;
436 char *nickname = NULL, *username = NULL;
438 argc = silc_argument_get_arg_num(cmd->args);
440 id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
446 client_id = silc_id_payload_parse_id(id_data, len);
452 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
453 username = silc_argument_get_arg_type(cmd->args, 4, &len);
455 /* Check if we have this client cached already. */
456 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
457 SILC_ID_CLIENT, &id_cache)) {
458 SILC_LOG_DEBUG(("Adding new client entry"));
460 client_entry = silc_calloc(1, sizeof(*client_entry));
461 client_entry->id = client_id;
462 silc_parse_nickname(nickname, &client_entry->nickname,
463 &client_entry->server, &client_entry->num);
465 client_entry->username = strdup(username);
467 /* Add client to cache */
468 silc_idcache_add(conn->client_cache, client_entry->nickname,
469 strlen(client_entry->nickname),
470 SILC_ID_CLIENT, client_id, (void *)client_entry,
473 client_entry = (SilcClientEntry)id_cache->context;
474 if (client_entry->nickname)
475 silc_free(client_entry->nickname);
476 if (client_entry->server)
477 silc_free(client_entry->server);
478 if (username && client_entry->username)
479 silc_free(client_entry->username);
481 SILC_LOG_DEBUG(("Updating client entry"));
483 silc_parse_nickname(nickname, &client_entry->nickname,
484 &client_entry->server, &client_entry->num);
487 client_entry->username = strdup(username);
489 id_cache->data = client_entry->nickname;
490 id_cache->data_len = strlen(client_entry->nickname);
491 silc_idcache_sort_by_data(conn->client_cache);
493 silc_free(client_id);
496 /* Notify application */
497 COMMAND_REPLY((ARGS, client_entry, nickname, username));
500 /* Received reply for IDENTIFY command. This maybe called several times
501 for one IDENTIFY command as server may reply with list of results.
502 This is totally silent and does not print anything on screen. */
504 SILC_CLIENT_CMD_REPLY_FUNC(identify)
506 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
507 SilcCommandStatus status;
510 SILC_LOG_DEBUG(("Start"));
512 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
513 SILC_GET16_MSB(status, tmp);
514 if (status != SILC_STATUS_OK &&
515 status != SILC_STATUS_LIST_START &&
516 status != SILC_STATUS_LIST_ITEM &&
517 status != SILC_STATUS_LIST_END) {
522 /* Save one IDENTIFY entry */
523 if (status == SILC_STATUS_OK)
524 silc_client_command_reply_identify_save(cmd, status);
527 if (status == SILC_STATUS_LIST_START ||
528 status == SILC_STATUS_LIST_ITEM ||
529 status == SILC_STATUS_LIST_END)
530 silc_client_command_reply_identify_save(cmd, status);
532 /* Pending callbacks are not executed if this was an list entry */
533 if (status != SILC_STATUS_OK &&
534 status != SILC_STATUS_LIST_END) {
535 silc_client_command_reply_free(cmd);
539 /* Execute any pending command callbacks */
540 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
543 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
544 silc_client_command_reply_free(cmd);
547 /* Received reply for command NICK. If everything went without errors
548 we just received our new Client ID. */
550 SILC_CLIENT_CMD_REPLY_FUNC(nick)
552 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
553 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
554 SilcCommandStatus status;
559 SILC_LOG_DEBUG(("Start"));
561 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
562 if (status != SILC_STATUS_OK) {
563 cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
564 silc_client_command_status_message(status));
569 argc = silc_argument_get_arg_num(cmd->args);
570 if (argc < 2 || argc > 2) {
571 cmd->client->ops->say(cmd->client, conn,
572 "Cannot set nickname: bad reply to command");
577 /* Take received Client ID */
578 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
579 idp = silc_id_payload_parse_data(tmp, len);
584 silc_client_receive_new_id(cmd->client, cmd->sock, idp);
586 /* Notify application */
587 COMMAND_REPLY((ARGS, conn->local_entry));
589 /* Execute any pending command callbacks */
590 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
593 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_NICK);
594 silc_client_command_reply_free(cmd);
597 /* Received reply to the LIST command. */
599 SILC_CLIENT_CMD_REPLY_FUNC(list)
601 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
602 SilcCommandStatus status;
603 unsigned char *tmp, *name, *topic;
604 uint32 usercount = 0;
606 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
607 SILC_GET16_MSB(status, tmp);
608 if (status != SILC_STATUS_OK &&
609 status != SILC_STATUS_LIST_START &&
610 status != SILC_STATUS_LIST_ITEM &&
611 status != SILC_STATUS_LIST_END) {
616 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
617 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
618 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
620 SILC_GET32_MSB(usercount, tmp);
622 /* Notify application */
623 COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
625 /* Pending callbacks are not executed if this was an list entry */
626 if (status != SILC_STATUS_OK &&
627 status != SILC_STATUS_LIST_END) {
628 silc_client_command_reply_free(cmd);
632 /* Execute any pending command callbacks */
633 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
636 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
637 silc_client_command_reply_free(cmd);
640 /* Received reply to topic command. */
642 SILC_CLIENT_CMD_REPLY_FUNC(topic)
644 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
645 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
646 SilcCommandStatus status;
647 SilcChannelEntry channel;
648 SilcChannelID *channel_id = NULL;
649 SilcIDCacheEntry id_cache = NULL;
654 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
655 if (status != SILC_STATUS_OK) {
656 cmd->client->ops->say(cmd->client, conn,
657 "%s", silc_client_command_status_message(status));
659 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
660 silc_client_command_reply_free(cmd);
664 argc = silc_argument_get_arg_num(cmd->args);
665 if (argc < 1 || argc > 3) {
670 /* Take Channel ID */
671 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
676 topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
680 channel_id = silc_id_payload_parse_id(tmp, len);
684 /* Get the channel entry */
685 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
686 SILC_ID_CHANNEL, &id_cache)) {
687 silc_free(channel_id);
692 channel = (SilcChannelEntry)id_cache->context;
694 cmd->client->ops->say(cmd->client, conn,
695 "Topic on channel %s: %s", channel->channel_name,
698 /* Notify application */
699 COMMAND_REPLY((ARGS, channel, topic));
701 /* Execute any pending command callbacks */
702 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_TOPIC);
705 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_TOPIC);
706 silc_client_command_reply_free(cmd);
709 /* Received reply to invite command. */
711 SILC_CLIENT_CMD_REPLY_FUNC(invite)
713 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
714 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
715 SilcCommandStatus status;
716 SilcChannelEntry channel;
717 SilcChannelID *channel_id;
718 SilcIDCacheEntry id_cache;
722 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
723 SILC_GET16_MSB(status, tmp);
724 if (status != SILC_STATUS_OK) {
725 cmd->client->ops->say(cmd->client, conn,
726 "%s", silc_client_command_status_message(status));
728 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
729 silc_client_command_reply_free(cmd);
733 /* Take Channel ID */
734 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
738 channel_id = silc_id_payload_parse_id(tmp, len);
742 /* Get the channel entry */
743 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
744 SILC_ID_CHANNEL, &id_cache)) {
745 silc_free(channel_id);
750 channel = (SilcChannelEntry)id_cache->context;
752 /* Get the invite list */
753 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
755 /* Notify application */
756 COMMAND_REPLY((ARGS, channel, tmp));
758 /* Execute any pending command callbacks */
759 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
762 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
763 silc_client_command_reply_free(cmd);
766 /* Received reply to the KILL command. */
768 SILC_CLIENT_CMD_REPLY_FUNC(kill)
770 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
771 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
772 SilcCommandStatus status;
775 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
776 SILC_GET16_MSB(status, tmp);
777 if (status != SILC_STATUS_OK) {
778 cmd->client->ops->say(cmd->client, conn,
779 "%s", silc_client_command_status_message(status));
784 /* Notify application */
785 COMMAND_REPLY((ARGS));
787 /* Execute any pending command callbacks */
788 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
791 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KILL);
792 silc_client_command_reply_free(cmd);
795 /* Received reply to INFO command. We receive the server ID and some
796 information about the server user requested. */
798 SILC_CLIENT_CMD_REPLY_FUNC(info)
800 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
801 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
802 SilcClient client = cmd->client;
803 SilcCommandStatus status;
806 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
807 SILC_GET16_MSB(status, tmp);
808 if (status != SILC_STATUS_OK) {
809 cmd->client->ops->say(cmd->client, conn,
810 "%s", silc_client_command_status_message(status));
812 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
813 silc_client_command_reply_free(cmd);
818 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
822 /* XXX save server id */
824 /* Get server name */
825 tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
829 /* Get server info */
830 tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
834 client->ops->say(cmd->client, conn, "Info: %s", tmp);
836 /* Notify application */
837 COMMAND_REPLY((ARGS, NULL, (char *)tmp));
839 /* Execute any pending command callbacks */
840 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
843 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
844 silc_client_command_reply_free(cmd);
847 /* Received reply to PING command. The reply time is shown to user. */
849 SILC_CLIENT_CMD_REPLY_FUNC(ping)
851 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
852 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
853 SilcCommandStatus status;
856 time_t diff, curtime;
858 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
859 if (status != SILC_STATUS_OK) {
860 cmd->client->ops->say(cmd->client, conn,
861 "%s", silc_client_command_status_message(status));
866 curtime = time(NULL);
867 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
868 cmd->packet->src_id_type);
874 for (i = 0; i < conn->ping_count; i++) {
875 if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
876 diff = curtime - conn->ping[i].start_time;
877 cmd->client->ops->say(cmd->client, conn,
878 "Ping reply from %s: %d second%s",
879 conn->ping[i].dest_name, diff,
880 diff == 1 ? "" : "s");
882 conn->ping[i].start_time = 0;
883 silc_free(conn->ping[i].dest_id);
884 conn->ping[i].dest_id = NULL;
885 silc_free(conn->ping[i].dest_name);
886 conn->ping[i].dest_name = NULL;
893 /* Notify application */
894 COMMAND_REPLY((ARGS));
896 /* Execute any pending command callbacks */
897 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PING);
900 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_PING);
901 silc_client_command_reply_free(cmd);
904 /* Received reply for JOIN command. */
906 SILC_CLIENT_CMD_REPLY_FUNC(join)
908 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
909 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
910 SilcCommandStatus status;
911 SilcIDPayload idp = NULL;
912 SilcChannelEntry channel;
913 SilcIDCacheEntry id_cache = NULL;
915 uint32 argc, mode, len, list_count;
916 char *topic, *tmp, *channel_name = NULL, *hmac;
917 SilcBuffer keyp = NULL, client_id_list, client_mode_list;
920 SILC_LOG_DEBUG(("Start"));
922 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
923 if (status != SILC_STATUS_OK) {
924 cmd->client->ops->say(cmd->client, conn,
925 "%s", silc_client_command_status_message(status));
930 argc = silc_argument_get_arg_num(cmd->args);
931 if (argc < 7 || argc > 14) {
932 cmd->client->ops->say(cmd->client, conn,
933 "Cannot join channel: Bad reply packet");
938 /* Get channel name */
939 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
941 cmd->client->ops->say(cmd->client, conn,
942 "Cannot join channel: Bad reply packet");
946 channel_name = strdup(tmp);
949 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
951 cmd->client->ops->say(cmd->client, conn,
952 "Cannot join channel: Bad reply packet");
954 silc_free(channel_name);
957 idp = silc_id_payload_parse_data(tmp, len);
960 silc_free(channel_name);
964 /* Get channel mode */
965 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
967 SILC_GET32_MSB(mode, tmp);
971 /* Get channel key */
972 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
974 keyp = silc_buffer_alloc(len);
975 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
976 silc_buffer_put(keyp, tmp, len);
980 topic = silc_argument_get_arg_type(cmd->args, 10, NULL);
982 /* Save received Channel ID. This actually creates the channel */
983 channel = silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
985 silc_id_payload_free(idp);
988 hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
990 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
991 cmd->client->ops->say(cmd->client, conn,
992 "Cannot join channel: Unsupported HMAC `%s'",
995 silc_free(channel_name);
1000 /* Get the list count */
1001 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
1004 SILC_GET32_MSB(list_count, tmp);
1006 /* Get Client ID list */
1007 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
1011 client_id_list = silc_buffer_alloc(len);
1012 silc_buffer_pull_tail(client_id_list, len);
1013 silc_buffer_put(client_id_list, tmp, len);
1015 /* Get client mode list */
1016 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
1020 client_mode_list = silc_buffer_alloc(len);
1021 silc_buffer_pull_tail(client_mode_list, len);
1022 silc_buffer_put(client_mode_list, tmp, len);
1024 /* Add clients we received in the reply to the channel */
1025 for (i = 0; i < list_count; i++) {
1028 SilcClientID *client_id;
1029 SilcClientEntry client_entry;
1032 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1034 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1039 SILC_GET32_MSB(mode, client_mode_list->data);
1041 /* Check if we have this client cached already. */
1042 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1043 SILC_ID_CLIENT, &id_cache)) {
1044 /* No, we don't have it, add entry for it. */
1045 client_entry = silc_calloc(1, sizeof(*client_entry));
1046 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
1047 silc_idcache_add(conn->client_cache, NULL, 0, SILC_ID_CLIENT,
1048 client_entry->id, (void *)client_entry, FALSE, FALSE);
1050 /* Yes, we have it already */
1051 client_entry = (SilcClientEntry)id_cache->context;
1054 /* Join the client to the channel */
1055 chu = silc_calloc(1, sizeof(*chu));
1056 chu->client = client_entry;
1058 silc_list_add(channel->clients, chu);
1059 silc_free(client_id);
1061 silc_buffer_pull(client_id_list, idp_len);
1062 silc_buffer_pull(client_mode_list, 4);
1064 silc_buffer_push(client_id_list, client_id_list->data -
1065 client_id_list->head);
1066 silc_buffer_push(client_mode_list, client_mode_list->data -
1067 client_mode_list->head);
1069 /* Save channel key */
1070 if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
1071 silc_client_save_channel_key(conn, keyp, channel);
1073 /* Client is now joined to the channel */
1074 channel->on_channel = TRUE;
1076 /* Notify application */
1077 COMMAND_REPLY((ARGS, channel_name, channel, mode, 0,
1078 keyp ? keyp->head : NULL, NULL,
1079 NULL, topic, hmac, list_count, client_id_list,
1082 /* Execute any pending command callbacks */
1083 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1086 silc_buffer_free(keyp);
1087 silc_buffer_free(client_id_list);
1088 silc_buffer_free(client_mode_list);
1091 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
1092 silc_client_command_reply_free(cmd);
1095 /* Received reply for MOTD command */
1097 SILC_CLIENT_CMD_REPLY_FUNC(motd)
1099 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1100 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1101 SilcCommandStatus status;
1104 char *motd = NULL, *cp, line[256];
1106 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1107 SILC_GET16_MSB(status, tmp);
1108 if (status != SILC_STATUS_OK) {
1109 cmd->client->ops->say(cmd->client, conn,
1110 "%s", silc_client_command_status_message(status));
1111 COMMAND_REPLY_ERROR;
1115 argc = silc_argument_get_arg_num(cmd->args);
1117 COMMAND_REPLY_ERROR;
1122 motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
1124 COMMAND_REPLY_ERROR;
1131 if (cp[i++] == '\n') {
1132 memset(line, 0, sizeof(line));
1133 strncat(line, cp, i - 1);
1139 cmd->client->ops->say(cmd->client, conn, "%s", line);
1148 /* Notify application */
1149 COMMAND_REPLY((ARGS, motd));
1151 /* Execute any pending command callbacks */
1152 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
1155 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
1156 silc_client_command_reply_free(cmd);
1159 /* Received reply tot he UMODE command. Save the current user mode */
1161 SILC_CLIENT_CMD_REPLY_FUNC(umode)
1163 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1164 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1165 SilcCommandStatus status;
1169 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1170 SILC_GET16_MSB(status, tmp);
1171 if (status != SILC_STATUS_OK) {
1172 cmd->client->ops->say(cmd->client, conn,
1173 "%s", silc_client_command_status_message(status));
1174 COMMAND_REPLY_ERROR;
1178 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1180 COMMAND_REPLY_ERROR;
1184 SILC_GET32_MSB(mode, tmp);
1185 conn->local_entry->mode = mode;
1187 /* Notify application */
1188 COMMAND_REPLY((ARGS, mode));
1190 /* Execute any pending command callbacks */
1191 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_UMODE);
1194 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_UMODE);
1195 silc_client_command_reply_free(cmd);
1198 /* Received reply for CMODE command. */
1200 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
1202 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1203 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1204 SilcCommandStatus status;
1207 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1208 if (status != SILC_STATUS_OK) {
1209 cmd->client->ops->say(cmd->client, conn,
1210 "%s", silc_client_command_status_message(status));
1211 COMMAND_REPLY_ERROR;
1215 /* Get channel mode */
1216 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1218 COMMAND_REPLY_ERROR;
1222 /* Notify application */
1223 COMMAND_REPLY((ARGS, tmp));
1225 /* Execute any pending command callbacks */
1226 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
1229 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CMODE);
1230 silc_client_command_reply_free(cmd);
1233 /* Received reply for CUMODE command */
1235 SILC_CLIENT_CMD_REPLY_FUNC(cumode)
1237 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1238 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1239 SilcCommandStatus status;
1240 SilcIDCacheEntry id_cache = NULL;
1241 SilcClientID *client_id;
1242 unsigned char *tmp, *id;
1245 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
1246 if (status != SILC_STATUS_OK) {
1247 cmd->client->ops->say(cmd->client, conn,
1248 "%s", silc_client_command_status_message(status));
1249 COMMAND_REPLY_ERROR;
1253 /* Get channel mode */
1254 tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
1256 COMMAND_REPLY_ERROR;
1261 id = silc_argument_get_arg_type(cmd->args, 3, &len);
1263 COMMAND_REPLY_ERROR;
1266 client_id = silc_id_payload_parse_id(id, len);
1268 COMMAND_REPLY_ERROR;
1272 /* Get client entry */
1273 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1274 SILC_ID_CLIENT, &id_cache)) {
1275 COMMAND_REPLY_ERROR;
1279 /* Notify application */
1280 COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
1281 silc_free(client_id);
1283 /* Execute any pending command callbacks */
1284 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
1287 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CUMODE);
1288 silc_client_command_reply_free(cmd);
1291 SILC_CLIENT_CMD_REPLY_FUNC(kick)
1293 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1294 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1295 SilcCommandStatus status;
1298 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1299 SILC_GET16_MSB(status, tmp);
1300 if (status != SILC_STATUS_OK) {
1301 cmd->client->ops->say(cmd->client, conn,
1302 "%s", silc_client_command_status_message(status));
1303 COMMAND_REPLY_ERROR;
1307 /* Notify application */
1308 COMMAND_REPLY((ARGS));
1310 /* Execute any pending command callbacks */
1311 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
1314 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_KICK);
1315 silc_client_command_reply_free(cmd);
1318 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
1320 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1321 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1322 SilcCommandStatus status;
1325 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1326 SILC_GET16_MSB(status, tmp);
1327 if (status != SILC_STATUS_OK) {
1328 cmd->client->ops->say(cmd->client, conn,
1329 "%s", silc_client_command_status_message(status));
1330 COMMAND_REPLY_ERROR;
1334 /* Notify application */
1335 COMMAND_REPLY((ARGS));
1337 /* Execute any pending command callbacks */
1338 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SILCOPER);
1341 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SILCOPER);
1342 silc_client_command_reply_free(cmd);
1345 SILC_CLIENT_CMD_REPLY_FUNC(oper)
1347 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1348 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1349 SilcCommandStatus status;
1352 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1353 SILC_GET16_MSB(status, tmp);
1354 if (status != SILC_STATUS_OK) {
1355 cmd->client->ops->say(cmd->client, conn,
1356 "%s", silc_client_command_status_message(status));
1357 COMMAND_REPLY_ERROR;
1361 /* Notify application */
1362 COMMAND_REPLY((ARGS));
1364 /* Execute any pending command callbacks */
1365 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_OPER);
1368 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_OPER);
1369 silc_client_command_reply_free(cmd);
1372 SILC_CLIENT_CMD_REPLY_FUNC(connect)
1374 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1375 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1376 SilcCommandStatus status;
1379 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1380 SILC_GET16_MSB(status, tmp);
1381 if (status != SILC_STATUS_OK) {
1382 cmd->client->ops->say(cmd->client, conn,
1383 "%s", silc_client_command_status_message(status));
1384 COMMAND_REPLY_ERROR;
1388 /* Notify application */
1389 COMMAND_REPLY((ARGS));
1391 /* Execute any pending command callbacks */
1392 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
1395 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CONNECT);
1396 silc_client_command_reply_free(cmd);
1399 SILC_CLIENT_CMD_REPLY_FUNC(close)
1401 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1402 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1403 SilcCommandStatus status;
1406 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1407 SILC_GET16_MSB(status, tmp);
1408 if (status != SILC_STATUS_OK) {
1409 cmd->client->ops->say(cmd->client, conn,
1410 "%s", silc_client_command_status_message(status));
1411 COMMAND_REPLY_ERROR;
1415 /* Notify application */
1416 COMMAND_REPLY((ARGS));
1418 /* Execute any pending command callbacks */
1419 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
1422 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_CLOSE);
1423 silc_client_command_reply_free(cmd);
1426 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
1428 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1429 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1430 SilcCommandStatus status;
1433 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1434 SILC_GET16_MSB(status, tmp);
1435 if (status != SILC_STATUS_OK) {
1436 cmd->client->ops->say(cmd->client, conn,
1437 "%s", silc_client_command_status_message(status));
1438 COMMAND_REPLY_ERROR;
1442 /* Notify application */
1443 COMMAND_REPLY((ARGS));
1445 /* Execute any pending command callbacks */
1446 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
1449 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_SHUTDOWN);
1450 silc_client_command_reply_free(cmd);
1453 /* Reply to LEAVE command. */
1455 SILC_CLIENT_CMD_REPLY_FUNC(leave)
1457 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1458 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1459 SilcCommandStatus status;
1462 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1463 SILC_GET16_MSB(status, tmp);
1464 if (status != SILC_STATUS_OK) {
1465 cmd->client->ops->say(cmd->client, conn,
1466 "%s", silc_client_command_status_message(status));
1467 COMMAND_REPLY_ERROR;
1471 /* Notify application */
1472 COMMAND_REPLY((ARGS));
1474 /* Execute any pending command callbacks */
1475 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
1478 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LEAVE);
1479 silc_client_command_reply_free(cmd);
1482 /* Reply to USERS command. Received list of client ID's and theirs modes
1483 on the channel we requested. */
1485 SILC_CLIENT_CMD_REPLY_FUNC(users)
1487 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1488 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1489 SilcCommandStatus status;
1490 SilcIDCacheEntry id_cache = NULL;
1491 SilcChannelEntry channel;
1492 SilcChannelUser chu;
1493 SilcChannelID *channel_id = NULL;
1494 SilcBuffer client_id_list;
1495 SilcBuffer client_mode_list;
1497 uint32 tmp_len, list_count;
1499 unsigned char **res_argv = NULL;
1500 uint32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
1502 SILC_LOG_DEBUG(("Start"));
1504 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1505 SILC_GET16_MSB(status, tmp);
1506 if (status != SILC_STATUS_OK) {
1507 cmd->client->ops->say(cmd->client, conn,
1508 "%s", silc_client_command_status_message(status));
1509 COMMAND_REPLY_ERROR;
1513 /* Get channel ID */
1514 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1517 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1521 /* Get the list count */
1522 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1525 SILC_GET32_MSB(list_count, tmp);
1527 /* Get Client ID list */
1528 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1532 client_id_list = silc_buffer_alloc(tmp_len);
1533 silc_buffer_pull_tail(client_id_list, tmp_len);
1534 silc_buffer_put(client_id_list, tmp, tmp_len);
1536 /* Get client mode list */
1537 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1541 client_mode_list = silc_buffer_alloc(tmp_len);
1542 silc_buffer_pull_tail(client_mode_list, tmp_len);
1543 silc_buffer_put(client_mode_list, tmp, tmp_len);
1545 /* Get channel entry */
1546 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1547 SILC_ID_CHANNEL, &id_cache)) {
1548 COMMAND_REPLY_ERROR;
1551 channel = (SilcChannelEntry)id_cache->context;
1553 /* Remove old client list from channel. */
1554 silc_list_start(channel->clients);
1555 while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
1556 silc_list_del(channel->clients, chu);
1560 /* Cache the received Client ID's and modes. This cache expires
1561 whenever server sends notify message to channel. It means two things;
1562 some user has joined or leaved the channel. XXX! */
1563 for (i = 0; i < list_count; i++) {
1566 SilcClientID *client_id;
1567 SilcClientEntry client;
1570 SILC_GET16_MSB(idp_len, client_id_list->data + 2);
1572 client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
1577 SILC_GET32_MSB(mode, client_mode_list->data);
1579 /* Check if we have this client cached already. */
1580 if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
1581 SILC_ID_CLIENT, &id_cache)) {
1582 /* No we don't have it, query it from the server. Assemble argument
1583 table that will be sent fr the IDENTIFY command later. */
1584 res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
1586 res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
1588 res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
1590 res_argv[res_argc] = client_id_list->data;
1591 res_argv_lens[res_argc] = idp_len;
1592 res_argv_types[res_argc] = res_argc + 3;
1595 /* Found the client, join it to the channel */
1596 client = (SilcClientEntry)id_cache->context;
1597 chu = silc_calloc(1, sizeof(*chu));
1598 chu->client = client;
1600 silc_list_add(channel->clients, chu);
1602 silc_free(client_id);
1606 silc_buffer_pull(client_id_list, idp_len);
1607 silc_buffer_pull(client_mode_list, 4);
1610 /* Query the client information from server if the list included clients
1611 that we don't know about. */
1615 /* Send the IDENTIFY command to server */
1616 res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
1617 res_argc, res_argv, res_argv_lens,
1618 res_argv_types, ++conn->cmd_ident);
1619 silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
1620 NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
1623 /* Register pending command callback. After we've received the IDENTIFY
1624 command reply we will reprocess this command reply by re-calling this
1625 USERS command reply callback. */
1626 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
1627 NULL, silc_client_command_reply_users, cmd);
1629 silc_buffer_free(res_cmd);
1631 silc_free(channel_id);
1633 silc_free(res_argv);
1634 silc_free(res_argv_lens);
1635 silc_free(res_argv_types);
1639 /* Notify application */
1640 COMMAND_REPLY((ARGS, channel, list_count, client_id_list, client_mode_list));
1642 /* Execute any pending command callbacks */
1643 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1645 silc_buffer_free(client_id_list);
1646 silc_buffer_free(client_mode_list);
1650 silc_free(channel_id);
1651 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1652 silc_client_command_reply_free(cmd);
1655 SILC_CLIENT_CMD_REPLY_FUNC(ban)
1657 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
1658 SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
1659 SilcCommandStatus status;
1660 SilcIDCacheEntry id_cache = NULL;
1661 SilcChannelEntry channel;
1662 SilcChannelID *channel_id;
1666 tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
1667 SILC_GET16_MSB(status, tmp);
1668 if (status != SILC_STATUS_OK) {
1669 cmd->client->ops->say(cmd->client, conn,
1670 "%s", silc_client_command_status_message(status));
1671 COMMAND_REPLY_ERROR;
1675 /* Take Channel ID */
1676 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1680 channel_id = silc_id_payload_parse_id(tmp, len);
1684 /* Get the channel entry */
1685 if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
1686 SILC_ID_CHANNEL, &id_cache)) {
1687 silc_free(channel_id);
1688 COMMAND_REPLY_ERROR;
1692 channel = (SilcChannelEntry)id_cache->context;
1694 /* Get the ban list */
1695 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1697 /* Notify application */
1698 COMMAND_REPLY((ARGS, channel, tmp));
1700 /* Execute any pending command callbacks */
1701 SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_BAN);
1704 SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_BAN);
1705 silc_client_command_reply_free(cmd);