5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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.
22 #include "serverincludes.h"
23 #include "server_internal.h"
24 #include "command_reply.h"
26 /* All functions that call the COMMAND_CHECK_STATUS or the
27 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
29 #define COMMAND_CHECK_STATUS \
31 SILC_LOG_DEBUG(("Start")); \
32 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
33 if (status != SILC_STATUS_OK) \
37 #define COMMAND_CHECK_STATUS_LIST \
39 SILC_LOG_DEBUG(("Start")); \
40 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
41 if (status != SILC_STATUS_OK && \
42 status != SILC_STATUS_LIST_START && \
43 status != SILC_STATUS_LIST_ITEM && \
44 status != SILC_STATUS_LIST_END) \
48 /* Server command reply list. Not all commands have reply function as
49 they are never sent by server. More maybe added later if need appears. */
50 SilcServerCommandReply silc_command_reply_list[] =
52 SILC_SERVER_CMD_REPLY(whois, WHOIS),
53 SILC_SERVER_CMD_REPLY(whowas, WHOWAS),
54 SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
55 SILC_SERVER_CMD_REPLY(info, INFO),
56 SILC_SERVER_CMD_REPLY(motd, MOTD),
57 SILC_SERVER_CMD_REPLY(join, JOIN),
58 SILC_SERVER_CMD_REPLY(stats, STATS),
59 SILC_SERVER_CMD_REPLY(users, USERS),
60 SILC_SERVER_CMD_REPLY(getkey, GETKEY),
61 SILC_SERVER_CMD_REPLY(list, LIST),
66 /* Process received command reply. */
68 void silc_server_command_reply_process(SilcServer server,
69 SilcSocketConnection sock,
72 SilcServerCommandReply *cmd;
73 SilcServerCommandReplyContext ctx;
74 SilcCommandPayload payload;
78 SILC_LOG_DEBUG(("Start"));
80 /* Get command reply payload from packet */
81 payload = silc_command_payload_parse(buffer->data, buffer->len);
83 /* Silently ignore bad reply packet */
84 SILC_LOG_DEBUG(("Bad command reply packet"));
88 /* Allocate command reply context. This must be free'd by the
89 command reply routine receiving it. */
90 ctx = silc_calloc(1, sizeof(*ctx));
92 ctx->sock = silc_socket_dup(sock);
93 ctx->payload = payload;
94 ctx->args = silc_command_get_args(ctx->payload);
95 ident = silc_command_get_ident(ctx->payload);
97 /* Check for pending commands and mark to be exeucted */
99 silc_server_command_pending_check(server, ctx,
100 silc_command_get(ctx->payload),
101 ident, &ctx->callbacks_count);
103 /* Execute command reply */
104 command = silc_command_get(ctx->payload);
105 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
106 if (cmd->cmd == command)
109 if (cmd == NULL || !cmd->cb) {
110 silc_server_command_reply_free(ctx);
117 /* Free command reply context and its internals. */
119 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
122 silc_command_payload_free(cmd->payload);
124 silc_socket_free(cmd->sock); /* Decrease the reference counter */
125 silc_free(cmd->callbacks);
130 /* Caches the received WHOIS information. */
133 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
135 SilcServer server = cmd->server;
136 unsigned char *tmp, *id_data;
137 char *nickname, *username, *realname, *servername = NULL;
138 unsigned char *fingerprint;
139 SilcClientID *client_id;
140 SilcClientEntry client;
143 SilcUInt32 mode = 0, len, id_len, flen;
146 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
147 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
148 username = silc_argument_get_arg_type(cmd->args, 4, &len);
149 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
150 if (!id_data || !nickname || !username || !realname) {
151 SILC_LOG_ERROR(("Incomplete WHOIS info: %s %s %s",
152 nickname ? nickname : "",
153 username ? username : "",
154 realname ? realname : ""));
158 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
160 SILC_GET32_MSB(mode, tmp);
162 client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
166 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);
168 /* Check if we have this client cached already. */
170 client = silc_idlist_find_client_by_id(server->local_list, client_id,
173 client = silc_idlist_find_client_by_id(server->global_list, client_id,
179 /* If router did not find such Client ID in its lists then this must
180 be bogus client or some router in the net is buggy. */
181 if (server->server_type != SILC_SERVER)
184 /* Take hostname out of nick string if it includes it. */
185 silc_parse_userfqdn(nickname, &nick, &servername);
187 /* We don't have that client anywhere, add it. The client is added
188 to global list since server didn't have it in the lists so it must be
190 client = silc_idlist_add_client(server->global_list, nick,
192 strdup(realname), client_id,
193 cmd->sock->user_data, NULL,
196 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
200 client->data.status |=
201 (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
202 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
204 client->servername = servername;
206 /* We have the client already, update the data */
208 SILC_LOG_DEBUG(("Updating client data"));
210 /* Take hostname out of nick string if it includes it. */
211 silc_parse_userfqdn(nickname, &nick, &servername);
213 /* Remove the old cache entry */
214 silc_idcache_del_by_context(global ? server->global_list->clients :
215 server->local_list->clients, client);
217 silc_free(client->nickname);
218 silc_free(client->username);
219 silc_free(client->userinfo);
220 silc_free(client->servername);
222 client->nickname = nick;
223 client->username = strdup(username);
224 client->userinfo = strdup(realname);
225 client->servername = servername;
227 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
228 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
230 /* If client is global and is not on any channel then add that we'll
231 expire the entry after a while. */
232 if (global && !silc_hash_table_count(client->channels) &&
233 server->server_type == SILC_SERVER)
234 expire = time(NULL) + 300;
236 /* Create new cache entry */
237 silc_idcache_add(global ? server->global_list->clients :
238 server->local_list->clients, nick, client->id,
239 client, expire, NULL);
240 silc_free(client_id);
243 if (fingerprint && flen == sizeof(client->data.fingerprint))
244 memcpy(client->data.fingerprint, fingerprint, flen);
249 /* Reiceved reply for WHOIS command. We sent the whois request to our
250 primary router, if we are normal server, and thus has now received reply
251 to the command. We will figure out what client originally sent us the
252 command and will send the reply to it. If we are router we will figure
253 out who server sent us the command and send reply to that one. */
255 SILC_SERVER_CMD_REPLY_FUNC(whois)
257 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
258 SilcServer server = cmd->server;
259 SilcCommandStatus status;
261 COMMAND_CHECK_STATUS_LIST;
263 if (!silc_server_command_reply_whois_save(cmd))
266 /* Pending callbacks are not executed if this was an list entry */
267 if (status != SILC_STATUS_OK &&
268 status != SILC_STATUS_LIST_END) {
269 silc_server_command_reply_free(cmd);
274 /* If we received notify for invalid ID we'll remove the ID if we
276 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
277 cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
278 SilcClientEntry client;
280 unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
282 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
284 SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
285 "the entry from cache"));
286 client = silc_idlist_find_client_by_id(server->global_list,
287 client_id, FALSE, NULL);
289 silc_server_remove_from_channels(server, NULL, client, TRUE,
291 silc_idlist_del_client(server->global_list, client);
293 silc_free(client_id);
298 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
299 silc_server_command_reply_free(cmd);
302 /* Caches the received WHOWAS information for a short period of time. */
305 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
307 SilcServer server = cmd->server;
308 SilcUInt32 len, id_len;
309 unsigned char *id_data;
310 char *nickname, *username, *realname, *servername = NULL;
311 SilcClientID *client_id;
312 SilcClientEntry client;
313 SilcIDCacheEntry cache = NULL;
317 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
318 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
319 username = silc_argument_get_arg_type(cmd->args, 4, &len);
320 if (!id_data || !nickname || !username)
323 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
325 client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
329 /* Check if we have this client cached already. */
331 client = silc_idlist_find_client_by_id(server->local_list, client_id,
334 client = silc_idlist_find_client_by_id(server->global_list,
335 client_id, FALSE, &cache);
340 /* If router did not find such Client ID in its lists then this must
341 be bogus client or some router in the net is buggy. */
342 if (server->server_type != SILC_SERVER)
345 /* Take hostname out of nick string if it includes it. */
346 silc_parse_userfqdn(nickname, &nick, &servername);
348 /* We don't have that client anywhere, add it. The client is added
349 to global list since server didn't have it in the lists so it must be
351 client = silc_idlist_add_client(server->global_list, nick,
352 strdup(username), strdup(realname),
353 silc_id_dup(client_id, SILC_ID_CLIENT),
354 cmd->sock->user_data, NULL,
355 SILC_ID_CACHE_EXPIRE_DEF);
357 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
361 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
362 client->servername = servername;
364 /* We have the client already, update the data */
366 /* Take hostname out of nick string if it includes it. */
367 silc_parse_userfqdn(nickname, &nick, &servername);
369 silc_free(client->nickname);
370 silc_free(client->username);
372 client->nickname = nick;
373 client->username = strdup(username);
374 client->servername = servername;
376 /* Remove the old cache entry and create a new one */
377 silc_idcache_del_by_context(global ? server->global_list->clients :
378 server->local_list->clients, client);
379 silc_idcache_add(global ? server->global_list->clients :
380 server->local_list->clients, nick, client->id,
384 silc_free(client_id);
389 /* Received reply for WHOWAS command. Cache the client information only for
390 a short period of time. */
392 SILC_SERVER_CMD_REPLY_FUNC(whowas)
394 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
395 SilcCommandStatus status;
397 COMMAND_CHECK_STATUS_LIST;
399 if (!silc_server_command_reply_whowas_save(cmd))
402 /* Pending callbacks are not executed if this was an list entry */
403 if (status != SILC_STATUS_OK &&
404 status != SILC_STATUS_LIST_END) {
405 silc_server_command_reply_free(cmd);
410 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
411 silc_server_command_reply_free(cmd);
414 /* Caches the received IDENTIFY information. */
417 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
419 SilcServer server = cmd->server;
420 SilcUInt32 len, id_len;
421 unsigned char *id_data;
423 SilcClientID *client_id = NULL;
424 SilcServerID *server_id = NULL;
425 SilcChannelID *channel_id = NULL;
426 SilcClientEntry client;
427 SilcServerEntry server_entry;
428 SilcChannelEntry channel;
431 SilcIDPayload idp = NULL;
435 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
438 idp = silc_id_payload_parse(id_data, id_len);
442 name = silc_argument_get_arg_type(cmd->args, 3, &len);
443 info = silc_argument_get_arg_type(cmd->args, 4, &len);
445 id_type = silc_id_payload_get_type(idp);
449 client_id = silc_id_payload_get_id(idp);
453 SILC_LOG_DEBUG(("Received client information"));
455 client = silc_idlist_find_client_by_id(server->local_list,
456 client_id, FALSE, NULL);
458 client = silc_idlist_find_client_by_id(server->global_list, client_id,
463 /* If router did not find such Client ID in its lists then this must
464 be bogus client or some router in the net is buggy. */
465 if (server->server_type != SILC_SERVER)
470 silc_parse_userfqdn(name, &nick, NULL);
472 /* We don't have that client anywhere, add it. The client is added
473 to global list since server didn't have it in the lists so it must be
475 client = silc_idlist_add_client(server->global_list, nick,
476 info ? strdup(info) : NULL, NULL,
477 client_id, cmd->sock->user_data, NULL,
480 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
483 client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
484 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
485 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
487 /* We have the client already, update the data */
489 SILC_LOG_DEBUG(("Updating client data"));
493 silc_parse_userfqdn(name, &nick, NULL);
495 /* Remove the old cache entry */
496 silc_idcache_del_by_context(global ? server->global_list->clients :
497 server->local_list->clients, client);
499 silc_free(client->nickname);
500 client->nickname = nick;
504 silc_free(client->username);
505 client->username = strdup(info);
508 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
509 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
512 /* If client is global and is not on any channel then add that we'll
513 expire the entry after a while. */
514 if (global && !silc_hash_table_count(client->channels) &&
515 server->server_type == SILC_SERVER)
516 expire = time(NULL) + 300;
518 /* Add new cache entry */
519 silc_idcache_add(global ? server->global_list->clients :
520 server->local_list->clients, nick, client->id,
521 client, expire, NULL);
524 silc_free(client_id);
533 server_id = silc_id_payload_get_id(idp);
537 SILC_LOG_DEBUG(("Received server information"));
539 server_entry = silc_idlist_find_server_by_id(server->local_list,
540 server_id, FALSE, NULL);
542 server_entry = silc_idlist_find_server_by_id(server->global_list,
543 server_id, FALSE, NULL);
545 /* If router did not find such Server ID in its lists then this must
546 be bogus server or some router in the net is buggy. */
547 if (server->server_type != SILC_SERVER)
550 /* We don't have that server anywhere, add it. */
551 server_entry = silc_idlist_add_server(server->global_list,
553 server_id, NULL, NULL);
555 silc_free(server_id);
558 server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
559 server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
560 server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
564 silc_free(server_id);
567 case SILC_ID_CHANNEL:
571 channel_id = silc_id_payload_get_id(idp);
575 SILC_LOG_DEBUG(("Received channel information"));
577 channel = silc_idlist_find_channel_by_name(server->local_list,
580 channel = silc_idlist_find_channel_by_name(server->global_list,
583 /* If router did not find such Channel ID in its lists then this must
584 be bogus channel or some router in the net is buggy. */
585 if (server->server_type != SILC_SERVER)
588 /* We don't have that server anywhere, add it. */
589 channel = silc_idlist_add_channel(server->global_list, strdup(name),
590 SILC_CHANNEL_MODE_NONE, channel_id,
591 server->router, NULL, NULL, 0);
593 silc_free(channel_id);
599 silc_free(channel_id);
603 silc_id_payload_free(idp);
607 silc_id_payload_free(idp);
611 /* Received reply for forwarded IDENTIFY command. We have received the
612 requested identify information now and we will cache it. After this we
613 will call the pending command so that the requestee gets the information
616 SILC_SERVER_CMD_REPLY_FUNC(identify)
618 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
619 SilcServer server = cmd->server;
620 SilcCommandStatus status;
622 COMMAND_CHECK_STATUS_LIST;
624 if (!silc_server_command_reply_identify_save(cmd))
627 /* Pending callbacks are not executed if this was an list entry */
628 if (status != SILC_STATUS_OK &&
629 status != SILC_STATUS_LIST_END) {
630 silc_server_command_reply_free(cmd);
635 /* If we received notify for invalid ID we'll remove the ID if we
637 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
638 cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
639 SilcClientEntry client;
641 unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
643 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
645 SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
646 "the entry from cache"));
647 client = silc_idlist_find_client_by_id(server->global_list,
648 client_id, FALSE, NULL);
650 silc_server_remove_from_channels(server, NULL, client, TRUE,
652 silc_idlist_del_client(server->global_list, client);
654 silc_free(client_id);
659 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
660 silc_server_command_reply_free(cmd);
663 /* Received reply fro INFO command. Cache the server and its information */
665 SILC_SERVER_CMD_REPLY_FUNC(info)
667 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
668 SilcServer server = cmd->server;
669 SilcCommandStatus status;
670 SilcServerEntry entry;
671 SilcServerID *server_id;
673 unsigned char *tmp, *name;
675 COMMAND_CHECK_STATUS;
678 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
681 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
686 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
690 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
693 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
696 /* Add the server to global list */
697 server_id = silc_id_dup(server_id, SILC_ID_SERVER);
698 entry = silc_idlist_add_server(server->global_list, name, 0,
699 server_id, NULL, NULL);
701 silc_free(server_id);
704 entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
708 /* Get the info string */
709 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
713 entry->server_info = tmp ? strdup(tmp) : NULL;
716 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
717 silc_server_command_reply_free(cmd);
720 /* Received reply fro MOTD command. */
722 SILC_SERVER_CMD_REPLY_FUNC(motd)
724 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
725 SilcServer server = cmd->server;
726 SilcCommandStatus status;
727 SilcServerEntry entry = NULL;
728 SilcServerID *server_id;
732 COMMAND_CHECK_STATUS;
735 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
738 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
742 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
745 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
752 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
759 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
760 silc_server_command_reply_free(cmd);
766 /* Received reply for forwarded JOIN command. Router has created or joined
767 the client to the channel. We save some channel information locally
770 SILC_SERVER_CMD_REPLY_FUNC(join)
772 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
773 SilcServer server = cmd->server;
774 SilcIDCacheEntry cache = NULL;
775 SilcCommandStatus status;
777 SilcClientID *client_id = NULL;
778 SilcChannelEntry entry;
779 SilcHmac hmac = NULL;
780 SilcUInt32 id_len, len, list_count;
781 unsigned char *id_string;
782 char *channel_name, *tmp;
783 SilcUInt32 mode, created;
784 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
786 COMMAND_CHECK_STATUS;
788 /* Get channel name */
789 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
794 id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
799 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
802 client_id = silc_id_payload_parse_id(tmp, len, NULL);
807 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
810 SILC_GET32_MSB(mode, tmp);
812 /* Get created boolean value */
813 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
816 SILC_GET32_MSB(created, tmp);
817 if (created != 0 && created != 1)
820 /* Get channel key */
821 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
823 keyp = silc_buffer_alloc(len);
824 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
825 silc_buffer_put(keyp, tmp, len);
828 /* Parse the Channel ID */
829 id = silc_id_payload_parse_id(id_string, id_len, NULL);
834 tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
836 if (!silc_hmac_alloc(tmp, NULL, &hmac))
840 /* Get the list count */
841 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
844 SILC_GET32_MSB(list_count, tmp);
846 /* Get Client ID list */
847 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
851 client_id_list = silc_buffer_alloc(len);
852 silc_buffer_pull_tail(client_id_list, len);
853 silc_buffer_put(client_id_list, tmp, len);
855 /* Get client mode list */
856 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
860 client_mode_list = silc_buffer_alloc(len);
861 silc_buffer_pull_tail(client_mode_list, len);
862 silc_buffer_put(client_mode_list, tmp, len);
864 /* See whether we already have the channel. */
865 entry = silc_idlist_find_channel_by_name(server->local_list,
866 channel_name, &cache);
868 /* Add new channel */
870 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
871 (created == 0 ? "existing" : "created"), channel_name,
872 silc_id_render(id, SILC_ID_CHANNEL)));
874 /* If the channel is found from global list we must move it to the
876 entry = silc_idlist_find_channel_by_name(server->global_list,
877 channel_name, &cache);
879 silc_idlist_del_channel(server->global_list, entry);
881 /* Add the channel to our local list. */
882 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
883 SILC_CHANNEL_MODE_NONE, id,
884 server->router, NULL, hmac, 0);
889 server->stat.my_channels++;
891 /* The entry exists. */
893 /* If ID has changed, then update it to the cache too. */
894 if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
895 silc_idlist_replace_channel_id(server->local_list, entry->id, id);
897 entry->disabled = FALSE;
899 /* Remove the founder auth data if the mode is not set but we have
901 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
902 silc_pkcs_public_key_free(entry->founder_key);
903 silc_free(entry->founder_passwd);
904 entry->founder_passwd = NULL;
908 if (entry->hmac_name && hmac) {
909 silc_free(entry->hmac_name);
910 entry->hmac_name = strdup(silc_hmac_get_name(hmac));
913 /* Get the ban list */
914 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
916 silc_free(entry->ban_list);
917 entry->ban_list = silc_memdup(tmp, len);
920 /* Get the invite list */
921 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
923 silc_free(entry->invite_list);
924 entry->invite_list = silc_memdup(tmp, len);
928 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
930 silc_free(entry->topic);
931 entry->topic = strdup(tmp);
934 /* If channel was not created we know there is global users on the
936 entry->global_users = (created == 0 ? TRUE : FALSE);
938 /* If channel was just created the mask must be zero */
939 if (!entry->global_users && mode) {
940 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
941 "new channel, forcing it to zero", cmd->sock->hostname));
945 /* Save channel mode */
948 /* Save channel key */
950 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
951 silc_server_save_channel_key(server, keyp, entry);
952 silc_buffer_free(keyp);
955 /* Save the users to the channel */
956 silc_server_save_users_on_channel(server, cmd->sock, entry,
957 client_id, client_id_list,
958 client_mode_list, list_count);
961 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
962 silc_free(client_id);
963 silc_server_command_reply_free(cmd);
966 silc_buffer_free(client_id_list);
967 if (client_mode_list)
968 silc_buffer_free(client_mode_list);
971 /* Received reply to STATS command. */
973 SILC_SERVER_CMD_REPLY_FUNC(stats)
975 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
976 SilcServer server = cmd->server;
977 SilcCommandStatus status;
980 SilcBufferStruct buf;
982 COMMAND_CHECK_STATUS;
984 /* Get statistics structure */
985 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
986 if (server->server_type == SILC_SERVER && tmp) {
987 silc_buffer_set(&buf, tmp, tmp_len);
988 silc_buffer_unformat(&buf,
989 SILC_STR_UI_INT(NULL),
990 SILC_STR_UI_INT(NULL),
991 SILC_STR_UI_INT(NULL),
992 SILC_STR_UI_INT(NULL),
993 SILC_STR_UI_INT(NULL),
994 SILC_STR_UI_INT(NULL),
995 SILC_STR_UI_INT(&server->stat.cell_clients),
996 SILC_STR_UI_INT(&server->stat.cell_channels),
997 SILC_STR_UI_INT(&server->stat.cell_servers),
998 SILC_STR_UI_INT(&server->stat.clients),
999 SILC_STR_UI_INT(&server->stat.channels),
1000 SILC_STR_UI_INT(&server->stat.servers),
1001 SILC_STR_UI_INT(&server->stat.routers),
1002 SILC_STR_UI_INT(&server->stat.server_ops),
1003 SILC_STR_UI_INT(&server->stat.router_ops),
1008 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1011 SILC_SERVER_CMD_REPLY_FUNC(users)
1013 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1014 SilcServer server = cmd->server;
1015 SilcCommandStatus status;
1016 SilcChannelEntry channel;
1017 SilcChannelID *channel_id = NULL;
1018 SilcBuffer client_id_list;
1019 SilcBuffer client_mode_list;
1022 SilcUInt32 list_count;
1024 COMMAND_CHECK_STATUS;
1026 /* Get channel ID */
1027 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1030 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1034 /* Get channel entry */
1035 channel = silc_idlist_find_channel_by_id(server->local_list,
1038 channel = silc_idlist_find_channel_by_id(server->global_list,
1043 if (server->server_type != SILC_SERVER)
1046 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1047 silc_server_send_command(server, server->router->connection,
1048 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1049 1, 5, idp->data, idp->len);
1050 silc_buffer_free(idp);
1052 /* Register pending command callback. After we've received the channel
1053 information we will reprocess this command reply by re-calling this
1054 USERS command reply callback. */
1055 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1057 silc_server_command_reply_users, cmd);
1062 /* Get the list count */
1063 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1066 SILC_GET32_MSB(list_count, tmp);
1068 /* Get Client ID list */
1069 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1073 client_id_list = silc_buffer_alloc(tmp_len);
1074 silc_buffer_pull_tail(client_id_list, tmp_len);
1075 silc_buffer_put(client_id_list, tmp, tmp_len);
1077 /* Get client mode list */
1078 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1082 client_mode_list = silc_buffer_alloc(tmp_len);
1083 silc_buffer_pull_tail(client_mode_list, tmp_len);
1084 silc_buffer_put(client_mode_list, tmp, tmp_len);
1086 /* Save the users to the channel */
1087 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1088 client_id_list, client_mode_list,
1091 silc_buffer_free(client_id_list);
1092 silc_buffer_free(client_mode_list);
1095 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1096 silc_free(channel_id);
1097 silc_server_command_reply_free(cmd);
1100 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1102 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1103 SilcServer server = cmd->server;
1104 SilcCommandStatus status;
1105 SilcClientEntry client = NULL;
1106 SilcServerEntry server_entry = NULL;
1107 SilcClientID *client_id = NULL;
1108 SilcServerID *server_id = NULL;
1110 unsigned char *tmp, *pk;
1113 SilcIDPayload idp = NULL;
1115 SilcPublicKey public_key = NULL;
1117 COMMAND_CHECK_STATUS;
1119 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1122 idp = silc_id_payload_parse(tmp, len);
1126 /* Get the public key payload */
1127 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1131 /* Decode the public key */
1133 SILC_GET16_MSB(pk_len, tmp);
1134 SILC_GET16_MSB(type, tmp + 2);
1137 if (type != SILC_SKE_PK_TYPE_SILC)
1140 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1143 id_type = silc_id_payload_get_type(idp);
1144 if (id_type == SILC_ID_CLIENT) {
1145 client_id = silc_id_payload_get_id(idp);
1147 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1150 client = silc_idlist_find_client_by_id(server->global_list,
1151 client_id, TRUE, NULL);
1156 client->data.public_key = public_key;
1157 } else if (id_type == SILC_ID_SERVER) {
1158 server_id = silc_id_payload_get_id(idp);
1160 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1162 if (!server_entry) {
1163 server_entry = silc_idlist_find_server_by_id(server->global_list,
1164 server_id, TRUE, NULL);
1169 server_entry->data.public_key = public_key;
1175 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1177 silc_id_payload_free(idp);
1178 silc_free(client_id);
1179 silc_free(server_id);
1181 silc_pkcs_public_key_free(public_key);
1182 silc_server_command_reply_free(cmd);
1185 SILC_SERVER_CMD_REPLY_FUNC(list)
1187 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1188 SilcServer server = cmd->server;
1189 SilcCommandStatus status;
1190 SilcChannelID *channel_id = NULL;
1191 SilcChannelEntry channel;
1192 SilcIDCacheEntry cache;
1194 unsigned char *tmp, *name, *topic;
1195 SilcUInt32 usercount = 0;
1196 bool global_list = FALSE;
1198 COMMAND_CHECK_STATUS_LIST;
1200 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1201 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1205 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1206 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1207 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1209 SILC_GET32_MSB(usercount, tmp);
1211 /* Add the channel entry if we do not have it already */
1212 channel = silc_idlist_find_channel_by_name(server->local_list,
1215 channel = silc_idlist_find_channel_by_name(server->global_list,
1220 /* If router did not find such channel in its lists then this must
1221 be bogus channel or some router in the net is buggy. */
1222 if (server->server_type != SILC_SERVER)
1225 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1226 SILC_CHANNEL_MODE_NONE, channel_id,
1227 server->router, NULL, NULL,
1233 /* Found, update expiry */
1234 if (global_list && server->server_type == SILC_SERVER)
1235 cache->expire = time(NULL) + 60;
1238 channel->user_count = usercount;
1241 silc_free(channel->topic);
1242 channel->topic = strdup(topic);
1245 /* Pending callbacks are not executed if this was an list entry */
1246 if (status != SILC_STATUS_OK &&
1247 status != SILC_STATUS_LIST_END) {
1248 silc_server_command_reply_free(cmd);
1252 /* Now purge all old entries from the global list, otherwise we'll might
1253 have non-existent entries for long periods of time in the cache. */
1254 silc_idcache_purge(server->global_list->channels);
1257 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1258 silc_free(channel_id);
1259 silc_server_command_reply_free(cmd);