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 macros must have
27 out: and err: goto labels. */
29 #define COMMAND_CHECK_STATUS \
31 SILC_LOG_DEBUG(("Start")); \
32 if (!silc_command_get_status(cmd->payload, &status, &error)) { \
33 if (SILC_STATUS_IS_ERROR(status)) \
35 if (status == SILC_STATUS_LIST_END) \
41 /* Server command reply list. Not all commands have reply function as
42 they are never sent by server. More maybe added later if need appears. */
43 SilcServerCommandReply silc_command_reply_list[] =
45 SILC_SERVER_CMD_REPLY(whois, WHOIS),
46 SILC_SERVER_CMD_REPLY(whowas, WHOWAS),
47 SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
48 SILC_SERVER_CMD_REPLY(info, INFO),
49 SILC_SERVER_CMD_REPLY(motd, MOTD),
50 SILC_SERVER_CMD_REPLY(join, JOIN),
51 SILC_SERVER_CMD_REPLY(stats, STATS),
52 SILC_SERVER_CMD_REPLY(users, USERS),
53 SILC_SERVER_CMD_REPLY(getkey, GETKEY),
54 SILC_SERVER_CMD_REPLY(list, LIST),
59 /* Process received command reply. */
61 void silc_server_command_reply_process(SilcServer server,
62 SilcSocketConnection sock,
65 SilcServerCommandReply *cmd;
66 SilcServerCommandReplyContext ctx;
67 SilcCommandPayload payload;
70 SILC_LOG_DEBUG(("Start"));
72 /* Get command reply payload from packet */
73 payload = silc_command_payload_parse(buffer->data, buffer->len);
75 /* Silently ignore bad reply packet */
76 SILC_LOG_DEBUG(("Bad command reply packet"));
80 /* Allocate command reply context. This must be free'd by the
81 command reply routine receiving it. */
82 ctx = silc_calloc(1, sizeof(*ctx));
84 ctx->sock = silc_socket_dup(sock);
85 ctx->payload = payload;
86 ctx->args = silc_command_get_args(ctx->payload);
87 ctx->ident = silc_command_get_ident(ctx->payload);
88 command = silc_command_get(ctx->payload);
90 /* Client is not allowed to send reply to all commands */
91 if (sock->type == SILC_SOCKET_TYPE_CLIENT &&
92 command != SILC_COMMAND_WHOIS) {
93 silc_server_command_reply_free(ctx);
97 /* Check for pending commands and mark to be exeucted */
99 silc_server_command_pending_check(server, command,
100 ctx->ident, &ctx->callbacks_count);
102 /* Execute command reply */
103 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
104 if (cmd->cmd == command)
107 if (cmd == NULL || !cmd->cb) {
108 silc_server_command_reply_free(ctx);
115 /* Free command reply context and its internals. */
117 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
120 silc_command_payload_free(cmd->payload);
122 silc_socket_free(cmd->sock); /* Decrease the reference counter */
123 silc_free(cmd->callbacks);
129 silc_server_command_process_error(SilcServerCommandReplyContext cmd,
132 SilcServer server = cmd->server;
134 /* If we received notify for invalid ID we'll remove the ID if we
136 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
137 cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
138 SilcClientEntry client;
140 unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
142 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
144 SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
145 "the entry from cache"));
146 client = silc_idlist_find_client_by_id(server->global_list,
147 client_id, FALSE, NULL);
149 silc_server_remove_from_channels(server, NULL, client, TRUE,
151 silc_idlist_del_data(client);
152 silc_idlist_del_client(server->global_list, client);
154 silc_free(client_id);
160 /* Caches the received WHOIS information. */
163 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
165 SilcServer server = cmd->server;
166 unsigned char *tmp, *id_data, *umodes;
167 char *nickname, *username, *realname, *servername = NULL;
168 unsigned char *fingerprint;
169 SilcClientID *client_id;
170 SilcClientEntry client;
171 SilcIDCacheEntry cache = NULL;
174 SilcUInt32 mode = 0, len, len2, id_len, flen;
176 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
177 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
178 username = silc_argument_get_arg_type(cmd->args, 4, &len);
179 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
180 if (!id_data || !nickname || !username || !realname)
183 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
185 SILC_GET32_MSB(mode, tmp);
187 client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
191 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);
193 /* Check if we have this client cached already. */
195 client = silc_idlist_find_client_by_id(server->local_list, client_id,
198 client = silc_idlist_find_client_by_id(server->global_list, client_id,
204 /* If router did not find such Client ID in its lists then this must
205 be bogus client or some router in the net is buggy. */
206 if (server->server_type != SILC_SERVER)
209 /* Take hostname out of nick string if it includes it. */
210 silc_parse_userfqdn(nickname, &nick, &servername);
212 /* We don't have that client anywhere, add it. The client is added
213 to global list since server didn't have it in the lists so it must be
215 client = silc_idlist_add_client(server->global_list, nick,
217 strdup(realname), client_id,
218 cmd->sock->user_data, NULL, 0);
220 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
224 client->data.status |=
225 (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
226 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
228 client->servername = servername;
230 /* We have the client already, update the data */
232 SILC_LOG_DEBUG(("Updating client data"));
234 /* Take hostname out of nick string if it includes it. */
235 silc_parse_userfqdn(nickname, &nick, &servername);
237 /* Remove the old cache entry */
238 silc_idcache_del_by_context(global ? server->global_list->clients :
239 server->local_list->clients, client);
241 silc_free(client->nickname);
242 silc_free(client->username);
243 silc_free(client->userinfo);
244 silc_free(client->servername);
246 client->nickname = nick;
247 client->username = strdup(username);
248 client->userinfo = strdup(realname);
249 client->servername = servername;
251 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
252 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
254 /* Create new cache entry */
255 silc_idcache_add(global ? server->global_list->clients :
256 server->local_list->clients, nick, client->id,
258 silc_free(client_id);
261 /* Save channel list if it was sent to us */
262 if (server->server_type == SILC_SERVER) {
263 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
264 umodes = silc_argument_get_arg_type(cmd->args, 10, &len2);
266 SilcBufferStruct channels_buf, umodes_buf;
267 silc_buffer_set(&channels_buf, tmp, len);
268 silc_buffer_set(&umodes_buf, umodes, len2);
269 silc_server_save_user_channels(server, cmd->sock, client, &channels_buf,
272 silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
275 /* If client is global and is not on any channel then add that we'll
276 expire the entry after a while. */
278 silc_idlist_find_client_by_id(server->global_list, client->id,
280 if (!silc_hash_table_count(client->channels))
281 cache->expire = time(NULL) + 300;
287 if (fingerprint && flen == sizeof(client->data.fingerprint))
288 memcpy(client->data.fingerprint, fingerprint, flen);
290 /* Take Requested Attributes if set. */
291 tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
293 silc_free(client->attrs);
294 client->attrs = silc_memdup(tmp, len);
295 client->attrs_len = len;
301 /* Handle requested attributes reply in WHOIS from client */
304 silc_server_command_reply_whois_save_client(SilcServerCommandReplyContext cmd)
308 SilcClientEntry client = cmd->sock->user_data;
310 /* Take Requested Attributes if set. */
311 tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
313 silc_free(client->attrs);
314 client->attrs = silc_memdup(tmp, len);
315 client->attrs_len = len;
318 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
323 /* Reiceved reply for WHOIS command. We sent the whois request to our
324 primary router, if we are normal server, and thus has now received reply
325 to the command. We will figure out what client originally sent us the
326 command and will send the reply to it. If we are router we will figure
327 out who server sent us the command and send reply to that one. */
329 SILC_SERVER_CMD_REPLY_FUNC(whois)
331 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
332 SilcStatus status, error;
334 COMMAND_CHECK_STATUS;
336 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) {
337 if (!silc_server_command_reply_whois_save(cmd))
340 if (!silc_server_command_reply_whois_save_client(cmd))
344 /* Pending callbacks are not executed if this was an list entry */
345 if (status != SILC_STATUS_OK &&
346 status != SILC_STATUS_LIST_END) {
347 silc_server_command_reply_free(cmd);
352 silc_server_command_process_error(cmd, error);
353 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
354 silc_server_command_reply_free(cmd);
358 silc_server_command_process_error(cmd, error);
359 silc_server_command_reply_free(cmd);
362 /* Caches the received WHOWAS information for a short period of time. */
365 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
367 SilcServer server = cmd->server;
368 SilcUInt32 len, id_len;
369 unsigned char *id_data;
370 char *nickname, *username, *realname, *servername = NULL;
371 SilcClientID *client_id;
372 SilcClientEntry client;
373 SilcIDCacheEntry cache = NULL;
377 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
378 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
379 username = silc_argument_get_arg_type(cmd->args, 4, &len);
380 if (!id_data || !nickname || !username)
383 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
385 client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
389 /* Check if we have this client cached already. */
391 client = silc_idlist_find_client_by_id(server->local_list, client_id,
394 client = silc_idlist_find_client_by_id(server->global_list,
395 client_id, FALSE, &cache);
400 /* If router did not find such Client ID in its lists then this must
401 be bogus client or some router in the net is buggy. */
402 if (server->server_type != SILC_SERVER)
405 /* Take hostname out of nick string if it includes it. */
406 silc_parse_userfqdn(nickname, &nick, &servername);
408 /* We don't have that client anywhere, add it. The client is added
409 to global list since server didn't have it in the lists so it must be
411 client = silc_idlist_add_client(server->global_list, nick,
412 strdup(username), strdup(realname),
413 silc_id_dup(client_id, SILC_ID_CLIENT),
414 cmd->sock->user_data, NULL,
415 SILC_ID_CACHE_EXPIRE_DEF);
417 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
421 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
422 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
423 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
424 client->servername = servername;
426 /* We have the client already, update the data */
428 /* Take hostname out of nick string if it includes it. */
429 silc_parse_userfqdn(nickname, &nick, &servername);
431 silc_free(client->nickname);
432 silc_free(client->username);
433 silc_free(client->servername);
435 client->nickname = nick;
436 client->username = strdup(username);
437 client->servername = servername;
438 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
439 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
441 /* Remove the old cache entry and create a new one */
442 silc_idcache_del_by_context(global ? server->global_list->clients :
443 server->local_list->clients, client);
444 silc_idcache_add(global ? server->global_list->clients :
445 server->local_list->clients, nick, client->id,
449 /* If client is global and is not on any channel then add that we'll
450 expire the entry after a while. */
452 silc_idlist_find_client_by_id(server->global_list, client->id,
454 if (!silc_hash_table_count(client->channels))
455 cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
460 silc_free(client_id);
465 /* Received reply for WHOWAS command. Cache the client information only for
466 a short period of time. */
468 SILC_SERVER_CMD_REPLY_FUNC(whowas)
470 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
471 SilcStatus status, error;
473 COMMAND_CHECK_STATUS;
475 if (!silc_server_command_reply_whowas_save(cmd))
478 /* Pending callbacks are not executed if this was an list entry */
479 if (status != SILC_STATUS_OK &&
480 status != SILC_STATUS_LIST_END) {
481 silc_server_command_reply_free(cmd);
486 silc_server_command_process_error(cmd, error);
487 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
488 silc_server_command_reply_free(cmd);
492 silc_server_command_process_error(cmd, error);
493 silc_server_command_reply_free(cmd);
496 /* Caches the received IDENTIFY information. */
499 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
501 SilcServer server = cmd->server;
502 SilcUInt32 len, id_len;
503 unsigned char *id_data;
505 SilcClientID *client_id = NULL;
506 SilcServerID *server_id = NULL;
507 SilcChannelID *channel_id = NULL;
508 SilcClientEntry client;
509 SilcServerEntry server_entry;
510 SilcChannelEntry channel;
513 SilcIDPayload idp = NULL;
517 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
520 idp = silc_id_payload_parse(id_data, id_len);
524 name = silc_argument_get_arg_type(cmd->args, 3, &len);
525 info = silc_argument_get_arg_type(cmd->args, 4, &len);
527 id_type = silc_id_payload_get_type(idp);
531 client_id = silc_id_payload_get_id(idp);
535 SILC_LOG_DEBUG(("Received client information"));
537 client = silc_idlist_find_client_by_id(server->local_list,
538 client_id, FALSE, NULL);
540 client = silc_idlist_find_client_by_id(server->global_list, client_id,
545 /* If router did not find such Client ID in its lists then this must
546 be bogus client or some router in the net is buggy. */
547 if (server->server_type != SILC_SERVER)
552 silc_parse_userfqdn(name, &nick, NULL);
554 /* We don't have that client anywhere, add it. The client is added
555 to global list since server didn't have it in the lists so it must be
557 client = silc_idlist_add_client(server->global_list, nick,
558 info ? strdup(info) : NULL, NULL,
559 client_id, cmd->sock->user_data,
560 NULL, time(NULL) + 300);
562 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
565 client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
566 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
567 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
569 /* We have the client already, update the data */
571 SILC_LOG_DEBUG(("Updating client data"));
575 silc_parse_userfqdn(name, &nick, NULL);
577 /* Remove the old cache entry */
578 silc_idcache_del_by_context(global ? server->global_list->clients :
579 server->local_list->clients, client);
581 silc_free(client->nickname);
582 client->nickname = nick;
586 silc_free(client->username);
587 client->username = strdup(info);
590 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
591 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
594 /* Add new cache entry */
595 silc_idcache_add(global ? server->global_list->clients :
596 server->local_list->clients, nick, client->id,
597 client, expire, NULL);
600 /* If client is global and is not on any channel then add that we'll
601 expire the entry after a while. */
602 if (global && server->server_type == SILC_SERVER) {
603 SilcIDCacheEntry cache = NULL;
604 silc_idlist_find_client_by_id(server->global_list, client->id,
606 if (!silc_hash_table_count(client->channels))
607 cache->expire = time(NULL) + 300;
612 silc_free(client_id);
621 server_id = silc_id_payload_get_id(idp);
625 SILC_LOG_DEBUG(("Received server information"));
627 server_entry = silc_idlist_find_server_by_id(server->local_list,
628 server_id, FALSE, NULL);
630 server_entry = silc_idlist_find_server_by_id(server->global_list,
631 server_id, FALSE, NULL);
633 /* If router did not find such Server ID in its lists then this must
634 be bogus server or some router in the net is buggy. */
635 if (server->server_type != SILC_SERVER)
638 /* We don't have that server anywhere, add it. */
639 server_entry = silc_idlist_add_server(server->global_list,
641 server_id, server->router,
642 SILC_PRIMARY_ROUTE(server));
644 silc_free(server_id);
647 server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
648 server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
649 server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
653 silc_free(server_id);
656 case SILC_ID_CHANNEL:
660 channel_id = silc_id_payload_get_id(idp);
664 SILC_LOG_DEBUG(("Received channel information"));
666 channel = silc_idlist_find_channel_by_name(server->local_list,
669 channel = silc_idlist_find_channel_by_name(server->global_list,
672 /* If router did not find such Channel ID in its lists then this must
673 be bogus channel or some router in the net is buggy. */
674 if (server->server_type != SILC_SERVER)
677 /* We don't have that channel anywhere, add it. */
678 channel = silc_idlist_add_channel(server->global_list, strdup(name),
679 SILC_CHANNEL_MODE_NONE, channel_id,
680 server->router, NULL, NULL, 0);
682 silc_free(channel_id);
688 silc_free(channel_id);
692 silc_id_payload_free(idp);
696 silc_id_payload_free(idp);
700 /* Received reply for forwarded IDENTIFY command. We have received the
701 requested identify information now and we will cache it. After this we
702 will call the pending command so that the requestee gets the information
705 SILC_SERVER_CMD_REPLY_FUNC(identify)
707 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
708 SilcStatus status, error;
710 COMMAND_CHECK_STATUS;
712 if (!silc_server_command_reply_identify_save(cmd))
715 /* Pending callbacks are not executed if this was an list entry */
716 if (status != SILC_STATUS_OK &&
717 status != SILC_STATUS_LIST_END) {
718 silc_server_command_reply_free(cmd);
723 silc_server_command_process_error(cmd, error);
724 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
725 silc_server_command_reply_free(cmd);
729 silc_server_command_process_error(cmd, error);
730 silc_server_command_reply_free(cmd);
733 /* Received reply fro INFO command. Cache the server and its information */
735 SILC_SERVER_CMD_REPLY_FUNC(info)
737 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
738 SilcServer server = cmd->server;
739 SilcStatus status, error;
740 SilcServerEntry entry;
741 SilcServerID *server_id;
743 unsigned char *tmp, *name;
745 COMMAND_CHECK_STATUS;
748 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
751 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
756 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
760 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
763 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
766 /* Add the server to global list */
767 server_id = silc_id_dup(server_id, SILC_ID_SERVER);
768 entry = silc_idlist_add_server(server->global_list, name, 0,
769 server_id, cmd->sock->user_data,
772 silc_free(server_id);
775 entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
779 /* Get the info string */
780 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
784 entry->server_info = tmp ? strdup(tmp) : NULL;
787 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
789 silc_server_command_reply_free(cmd);
792 /* Received reply fro MOTD command. */
794 SILC_SERVER_CMD_REPLY_FUNC(motd)
796 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
797 SilcServer server = cmd->server;
798 SilcStatus status, error;
799 SilcServerEntry entry = NULL;
800 SilcServerID *server_id;
804 COMMAND_CHECK_STATUS;
807 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
810 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
814 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
817 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
824 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
831 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
833 silc_server_command_reply_free(cmd);
839 /* Received reply for forwarded JOIN command. Router has created or joined
840 the client to the channel. We save some channel information locally
843 SILC_SERVER_CMD_REPLY_FUNC(join)
845 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
846 SilcServer server = cmd->server;
847 SilcIDCacheEntry cache = NULL;
848 SilcStatus status, error;
850 SilcClientID *client_id = NULL;
851 SilcChannelEntry entry;
852 SilcHmac hmac = NULL;
853 SilcUInt32 id_len, len, list_count;
854 unsigned char *id_string;
855 char *channel_name, *tmp;
856 SilcUInt32 mode, created;
857 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
858 SilcPublicKey founder_key = NULL;
860 COMMAND_CHECK_STATUS;
862 /* Get channel name */
863 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
868 id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
873 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
876 client_id = silc_id_payload_parse_id(tmp, len, NULL);
881 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
884 SILC_GET32_MSB(mode, tmp);
886 /* Get created boolean value */
887 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
890 SILC_GET32_MSB(created, tmp);
891 if (created != 0 && created != 1)
894 /* Get channel key */
895 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
897 keyp = silc_buffer_alloc(len);
898 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
899 silc_buffer_put(keyp, tmp, len);
902 /* Parse the Channel ID */
903 id = silc_id_payload_parse_id(id_string, id_len, NULL);
908 tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
910 if (!silc_hmac_alloc(tmp, NULL, &hmac))
914 /* Get the list count */
915 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
918 SILC_GET32_MSB(list_count, tmp);
920 /* Get Client ID list */
921 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
925 client_id_list = silc_buffer_alloc(len);
926 silc_buffer_pull_tail(client_id_list, len);
927 silc_buffer_put(client_id_list, tmp, len);
929 /* Get client mode list */
930 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
934 client_mode_list = silc_buffer_alloc(len);
935 silc_buffer_pull_tail(client_mode_list, len);
936 silc_buffer_put(client_mode_list, tmp, len);
938 /* Get founder key */
939 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
941 silc_pkcs_public_key_decode(tmp, len, &founder_key);
943 /* See whether we already have the channel. */
944 entry = silc_idlist_find_channel_by_name(server->local_list,
945 channel_name, &cache);
947 /* Add new channel */
949 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
950 (created == 0 ? "existing" : "created"), channel_name,
951 silc_id_render(id, SILC_ID_CHANNEL)));
953 /* If the channel is found from global list we must move it to the
955 entry = silc_idlist_find_channel_by_name(server->global_list,
956 channel_name, &cache);
958 silc_idlist_del_channel(server->global_list, entry);
960 /* Add the channel to our local list. */
961 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
962 SILC_CHANNEL_MODE_NONE, id,
963 server->router, NULL, hmac, 0);
969 server->stat.my_channels++;
970 server->stat.channels++;
972 /* The entry exists. */
974 /* If ID has changed, then update it to the cache too. */
975 if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
976 silc_idlist_replace_channel_id(server->local_list, entry->id, id);
978 entry->disabled = FALSE;
980 /* Remove the founder auth data if the mode is not set but we have
982 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
983 silc_pkcs_public_key_free(entry->founder_key);
984 entry->founder_key = NULL;
989 if (entry->founder_key)
990 silc_pkcs_public_key_free(entry->founder_key);
991 entry->founder_key = founder_key;
995 if (entry->hmac_name && (hmac || (!hmac && entry->hmac))) {
996 silc_free(entry->hmac_name);
997 entry->hmac_name = strdup(silc_hmac_get_name(hmac ? hmac : entry->hmac));
1000 /* Get the ban list */
1001 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
1003 silc_free(entry->ban_list);
1004 entry->ban_list = silc_memdup(tmp, len);
1007 /* Get the invite list */
1008 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
1010 silc_free(entry->invite_list);
1011 entry->invite_list = silc_memdup(tmp, len);
1015 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
1017 silc_free(entry->topic);
1018 entry->topic = strdup(tmp);
1021 /* If channel was not created we know there is global users on the
1023 entry->global_users = (created == 0 ? TRUE : FALSE);
1025 /* If channel was just created the mask must be zero */
1026 if (!entry->global_users && mode) {
1027 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
1028 "new channel, forcing it to zero", cmd->sock->hostname));
1032 /* Save channel mode */
1035 /* Save channel key */
1037 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
1038 silc_server_save_channel_key(server, keyp, entry);
1039 silc_buffer_free(keyp);
1042 /* Save the users to the channel */
1043 silc_server_save_users_on_channel(server, cmd->sock, entry,
1044 client_id, client_id_list,
1045 client_mode_list, list_count);
1046 entry->users_resolved = TRUE;
1049 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1052 silc_hmac_free(hmac);
1053 silc_free(client_id);
1054 silc_server_command_reply_free(cmd);
1056 silc_pkcs_public_key_free(founder_key);
1058 silc_buffer_free(client_id_list);
1059 if (client_mode_list)
1060 silc_buffer_free(client_mode_list);
1063 /* Received reply to STATS command. */
1065 SILC_SERVER_CMD_REPLY_FUNC(stats)
1067 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1068 SilcServer server = cmd->server;
1069 SilcStatus status, error;
1072 SilcBufferStruct buf;
1074 COMMAND_CHECK_STATUS;
1076 /* Get statistics structure */
1077 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1078 if (server->server_type == SILC_SERVER && tmp) {
1079 silc_buffer_set(&buf, tmp, tmp_len);
1080 silc_buffer_unformat(&buf,
1081 SILC_STR_UI_INT(NULL),
1082 SILC_STR_UI_INT(NULL),
1083 SILC_STR_UI_INT(NULL),
1084 SILC_STR_UI_INT(NULL),
1085 SILC_STR_UI_INT(NULL),
1086 SILC_STR_UI_INT(NULL),
1087 SILC_STR_UI_INT(&server->stat.cell_clients),
1088 SILC_STR_UI_INT(&server->stat.cell_channels),
1089 SILC_STR_UI_INT(&server->stat.cell_servers),
1090 SILC_STR_UI_INT(&server->stat.clients),
1091 SILC_STR_UI_INT(&server->stat.channels),
1092 SILC_STR_UI_INT(&server->stat.servers),
1093 SILC_STR_UI_INT(&server->stat.routers),
1094 SILC_STR_UI_INT(&server->stat.server_ops),
1095 SILC_STR_UI_INT(&server->stat.router_ops),
1100 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
1102 silc_server_command_reply_free(cmd);
1105 SILC_SERVER_CMD_REPLY_FUNC(users)
1107 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1108 SilcServer server = cmd->server;
1109 SilcStatus status, error;
1110 SilcChannelEntry channel;
1111 SilcChannelID *channel_id = NULL;
1112 SilcBuffer client_id_list;
1113 SilcBuffer client_mode_list;
1116 SilcUInt32 list_count;
1118 COMMAND_CHECK_STATUS;
1120 /* Get channel ID */
1121 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1124 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1128 /* Get channel entry */
1129 channel = silc_idlist_find_channel_by_id(server->local_list,
1132 channel = silc_idlist_find_channel_by_id(server->global_list,
1137 if (server->server_type != SILC_SERVER)
1140 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1141 silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
1142 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1143 1, 5, idp->data, idp->len);
1144 silc_buffer_free(idp);
1146 /* Register pending command callback. After we've received the channel
1147 information we will reprocess this command reply by re-calling this
1148 USERS command reply callback. */
1149 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1151 silc_server_command_reply_users, cmd);
1156 /* Get the list count */
1157 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1160 SILC_GET32_MSB(list_count, tmp);
1162 /* Get Client ID list */
1163 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1167 client_id_list = silc_buffer_alloc(tmp_len);
1168 silc_buffer_pull_tail(client_id_list, tmp_len);
1169 silc_buffer_put(client_id_list, tmp, tmp_len);
1171 /* Get client mode list */
1172 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1176 client_mode_list = silc_buffer_alloc(tmp_len);
1177 silc_buffer_pull_tail(client_mode_list, tmp_len);
1178 silc_buffer_put(client_mode_list, tmp, tmp_len);
1180 /* Save the users to the channel */
1181 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1182 client_id_list, client_mode_list,
1185 channel->global_users = silc_server_channel_has_global(channel);
1186 channel->users_resolved = TRUE;
1188 silc_buffer_free(client_id_list);
1189 silc_buffer_free(client_mode_list);
1192 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1193 silc_free(channel_id);
1195 silc_server_command_reply_free(cmd);
1198 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1200 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1201 SilcServer server = cmd->server;
1202 SilcStatus status, error;
1203 SilcClientEntry client = NULL;
1204 SilcServerEntry server_entry = NULL;
1205 SilcClientID *client_id = NULL;
1206 SilcServerID *server_id = NULL;
1208 unsigned char *tmp, *pk;
1211 SilcIDPayload idp = NULL;
1213 SilcPublicKey public_key = NULL;
1215 COMMAND_CHECK_STATUS;
1217 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1220 idp = silc_id_payload_parse(tmp, len);
1224 /* Get the public key payload */
1225 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1229 /* Decode the public key */
1231 SILC_GET16_MSB(pk_len, tmp);
1232 SILC_GET16_MSB(type, tmp + 2);
1235 if (type != SILC_SKE_PK_TYPE_SILC)
1238 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1241 id_type = silc_id_payload_get_type(idp);
1242 if (id_type == SILC_ID_CLIENT) {
1243 client_id = silc_id_payload_get_id(idp);
1245 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1248 client = silc_idlist_find_client_by_id(server->global_list,
1249 client_id, TRUE, NULL);
1254 client->data.public_key = public_key;
1256 } else if (id_type == SILC_ID_SERVER) {
1257 server_id = silc_id_payload_get_id(idp);
1259 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1261 if (!server_entry) {
1262 server_entry = silc_idlist_find_server_by_id(server->global_list,
1263 server_id, TRUE, NULL);
1268 server_entry->data.public_key = public_key;
1275 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1277 silc_id_payload_free(idp);
1278 silc_free(client_id);
1279 silc_free(server_id);
1281 silc_pkcs_public_key_free(public_key);
1283 silc_server_command_reply_free(cmd);
1286 SILC_SERVER_CMD_REPLY_FUNC(list)
1288 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1289 SilcServer server = cmd->server;
1290 SilcStatus status, error;
1291 SilcChannelID *channel_id = NULL;
1292 SilcChannelEntry channel;
1293 SilcIDCacheEntry cache;
1295 unsigned char *tmp, *name, *topic;
1296 SilcUInt32 usercount = 0;
1297 bool global_list = FALSE;
1299 COMMAND_CHECK_STATUS;
1301 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1302 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1306 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1307 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1308 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1310 SILC_GET32_MSB(usercount, tmp);
1312 /* Add the channel entry if we do not have it already */
1313 channel = silc_idlist_find_channel_by_name(server->local_list,
1316 channel = silc_idlist_find_channel_by_name(server->global_list,
1321 /* If router did not find such channel in its lists then this must
1322 be bogus channel or some router in the net is buggy. */
1323 if (server->server_type != SILC_SERVER)
1326 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1327 SILC_CHANNEL_MODE_NONE, channel_id,
1328 server->router, NULL, NULL,
1334 /* Found, update expiry */
1335 if (global_list && server->server_type == SILC_SERVER)
1336 cache->expire = time(NULL) + 60;
1339 channel->user_count = usercount;
1342 silc_free(channel->topic);
1343 channel->topic = strdup(topic);
1346 /* Pending callbacks are not executed if this was an list entry */
1347 if (status != SILC_STATUS_OK &&
1348 status != SILC_STATUS_LIST_END) {
1349 silc_server_command_reply_free(cmd);
1353 /* Now purge all old entries from the global list, otherwise we'll might
1354 have non-existent entries for long periods of time in the cache. */
1355 silc_idcache_purge(server->global_list->channels);
1358 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1359 silc_free(channel_id);
1361 silc_server_command_reply_free(cmd);
1364 SILC_SERVER_CMD_REPLY_FUNC(watch)
1366 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1367 SilcStatus status, error;
1369 COMMAND_CHECK_STATUS;
1372 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1374 silc_server_command_reply_free(cmd);