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);
300 /* Handle requested attributes reply in WHOIS from client */
303 silc_server_command_reply_whois_save_client(SilcServerCommandReplyContext cmd)
307 SilcClientEntry client = cmd->sock->user_data;
309 /* Take Requested Attributes if set. */
310 tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
312 silc_free(client->attrs);
313 client->attrs = silc_memdup(tmp, len);
314 client->attrs_len = len;
317 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
322 /* Reiceved reply for WHOIS command. We sent the whois request to our
323 primary router, if we are normal server, and thus has now received reply
324 to the command. We will figure out what client originally sent us the
325 command and will send the reply to it. If we are router we will figure
326 out who server sent us the command and send reply to that one. */
328 SILC_SERVER_CMD_REPLY_FUNC(whois)
330 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
331 SilcStatus status, error;
333 COMMAND_CHECK_STATUS;
335 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) {
336 if (!silc_server_command_reply_whois_save(cmd))
339 if (!silc_server_command_reply_whois_save_client(cmd))
343 /* Pending callbacks are not executed if this was an list entry */
344 if (status != SILC_STATUS_OK &&
345 status != SILC_STATUS_LIST_END) {
346 silc_server_command_reply_free(cmd);
351 silc_server_command_process_error(cmd, error);
352 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
353 silc_server_command_reply_free(cmd);
357 silc_server_command_process_error(cmd, error);
358 silc_server_command_reply_free(cmd);
361 /* Caches the received WHOWAS information for a short period of time. */
364 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
366 SilcServer server = cmd->server;
367 SilcUInt32 len, id_len;
368 unsigned char *id_data;
369 char *nickname, *username, *realname, *servername = NULL;
370 SilcClientID *client_id;
371 SilcClientEntry client;
372 SilcIDCacheEntry cache = NULL;
376 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
377 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
378 username = silc_argument_get_arg_type(cmd->args, 4, &len);
379 if (!id_data || !nickname || !username)
382 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
384 client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
388 /* Check if we have this client cached already. */
390 client = silc_idlist_find_client_by_id(server->local_list, client_id,
393 client = silc_idlist_find_client_by_id(server->global_list,
394 client_id, FALSE, &cache);
399 /* If router did not find such Client ID in its lists then this must
400 be bogus client or some router in the net is buggy. */
401 if (server->server_type != SILC_SERVER)
404 /* Take hostname out of nick string if it includes it. */
405 silc_parse_userfqdn(nickname, &nick, &servername);
407 /* We don't have that client anywhere, add it. The client is added
408 to global list since server didn't have it in the lists so it must be
410 client = silc_idlist_add_client(server->global_list, nick,
411 strdup(username), strdup(realname),
412 silc_id_dup(client_id, SILC_ID_CLIENT),
413 cmd->sock->user_data, NULL,
414 SILC_ID_CACHE_EXPIRE_DEF);
416 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
420 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
421 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
422 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
423 client->servername = servername;
425 /* We have the client already, update the data */
427 /* Take hostname out of nick string if it includes it. */
428 silc_parse_userfqdn(nickname, &nick, &servername);
430 silc_free(client->nickname);
431 silc_free(client->username);
432 silc_free(client->servername);
434 client->nickname = nick;
435 client->username = strdup(username);
436 client->servername = servername;
437 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
438 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
440 /* Remove the old cache entry and create a new one */
441 silc_idcache_del_by_context(global ? server->global_list->clients :
442 server->local_list->clients, client);
443 silc_idcache_add(global ? server->global_list->clients :
444 server->local_list->clients, nick, client->id,
448 /* If client is global and is not on any channel then add that we'll
449 expire the entry after a while. */
451 silc_idlist_find_client_by_id(server->global_list, client->id,
453 if (!silc_hash_table_count(client->channels))
454 cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
459 silc_free(client_id);
464 /* Received reply for WHOWAS command. Cache the client information only for
465 a short period of time. */
467 SILC_SERVER_CMD_REPLY_FUNC(whowas)
469 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
470 SilcStatus status, error;
472 COMMAND_CHECK_STATUS;
474 if (!silc_server_command_reply_whowas_save(cmd))
477 /* Pending callbacks are not executed if this was an list entry */
478 if (status != SILC_STATUS_OK &&
479 status != SILC_STATUS_LIST_END) {
480 silc_server_command_reply_free(cmd);
485 silc_server_command_process_error(cmd, error);
486 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
487 silc_server_command_reply_free(cmd);
491 silc_server_command_process_error(cmd, error);
492 silc_server_command_reply_free(cmd);
495 /* Caches the received IDENTIFY information. */
498 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
500 SilcServer server = cmd->server;
501 SilcUInt32 len, id_len;
502 unsigned char *id_data;
504 SilcClientID *client_id = NULL;
505 SilcServerID *server_id = NULL;
506 SilcChannelID *channel_id = NULL;
507 SilcClientEntry client;
508 SilcServerEntry server_entry;
509 SilcChannelEntry channel;
512 SilcIDPayload idp = NULL;
516 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
519 idp = silc_id_payload_parse(id_data, id_len);
523 name = silc_argument_get_arg_type(cmd->args, 3, &len);
524 info = silc_argument_get_arg_type(cmd->args, 4, &len);
526 id_type = silc_id_payload_get_type(idp);
530 client_id = silc_id_payload_get_id(idp);
534 SILC_LOG_DEBUG(("Received client information"));
536 client = silc_idlist_find_client_by_id(server->local_list,
537 client_id, FALSE, NULL);
539 client = silc_idlist_find_client_by_id(server->global_list, client_id,
544 /* If router did not find such Client ID in its lists then this must
545 be bogus client or some router in the net is buggy. */
546 if (server->server_type != SILC_SERVER)
551 silc_parse_userfqdn(name, &nick, NULL);
553 /* We don't have that client anywhere, add it. The client is added
554 to global list since server didn't have it in the lists so it must be
556 client = silc_idlist_add_client(server->global_list, nick,
557 info ? strdup(info) : NULL, NULL,
558 client_id, cmd->sock->user_data,
559 NULL, time(NULL) + 300);
561 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
564 client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
565 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
566 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
568 /* We have the client already, update the data */
570 SILC_LOG_DEBUG(("Updating client data"));
574 silc_parse_userfqdn(name, &nick, NULL);
576 /* Remove the old cache entry */
577 silc_idcache_del_by_context(global ? server->global_list->clients :
578 server->local_list->clients, client);
580 silc_free(client->nickname);
581 client->nickname = nick;
585 silc_free(client->username);
586 client->username = strdup(info);
589 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
590 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
593 /* Add new cache entry */
594 silc_idcache_add(global ? server->global_list->clients :
595 server->local_list->clients, nick, client->id,
596 client, expire, NULL);
599 /* If client is global and is not on any channel then add that we'll
600 expire the entry after a while. */
601 if (global && server->server_type == SILC_SERVER) {
602 SilcIDCacheEntry cache = NULL;
603 silc_idlist_find_client_by_id(server->global_list, client->id,
605 if (!silc_hash_table_count(client->channels))
606 cache->expire = time(NULL) + 300;
611 silc_free(client_id);
620 server_id = silc_id_payload_get_id(idp);
624 SILC_LOG_DEBUG(("Received server information"));
626 server_entry = silc_idlist_find_server_by_id(server->local_list,
627 server_id, FALSE, NULL);
629 server_entry = silc_idlist_find_server_by_id(server->global_list,
630 server_id, FALSE, NULL);
632 /* If router did not find such Server ID in its lists then this must
633 be bogus server or some router in the net is buggy. */
634 if (server->server_type != SILC_SERVER)
637 /* We don't have that server anywhere, add it. */
638 server_entry = silc_idlist_add_server(server->global_list,
640 server_id, server->router,
641 SILC_PRIMARY_ROUTE(server));
643 silc_free(server_id);
646 server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
647 server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
648 server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
652 silc_free(server_id);
655 case SILC_ID_CHANNEL:
659 channel_id = silc_id_payload_get_id(idp);
663 SILC_LOG_DEBUG(("Received channel information"));
665 channel = silc_idlist_find_channel_by_name(server->local_list,
668 channel = silc_idlist_find_channel_by_name(server->global_list,
671 /* If router did not find such Channel ID in its lists then this must
672 be bogus channel or some router in the net is buggy. */
673 if (server->server_type != SILC_SERVER)
676 /* We don't have that channel anywhere, add it. */
677 channel = silc_idlist_add_channel(server->global_list, strdup(name),
678 SILC_CHANNEL_MODE_NONE, channel_id,
679 server->router, NULL, NULL, 0);
681 silc_free(channel_id);
687 silc_free(channel_id);
691 silc_id_payload_free(idp);
695 silc_id_payload_free(idp);
699 /* Received reply for forwarded IDENTIFY command. We have received the
700 requested identify information now and we will cache it. After this we
701 will call the pending command so that the requestee gets the information
704 SILC_SERVER_CMD_REPLY_FUNC(identify)
706 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
707 SilcStatus status, error;
709 COMMAND_CHECK_STATUS;
711 if (!silc_server_command_reply_identify_save(cmd))
714 /* Pending callbacks are not executed if this was an list entry */
715 if (status != SILC_STATUS_OK &&
716 status != SILC_STATUS_LIST_END) {
717 silc_server_command_reply_free(cmd);
722 silc_server_command_process_error(cmd, error);
723 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
724 silc_server_command_reply_free(cmd);
728 silc_server_command_process_error(cmd, error);
729 silc_server_command_reply_free(cmd);
732 /* Received reply fro INFO command. Cache the server and its information */
734 SILC_SERVER_CMD_REPLY_FUNC(info)
736 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
737 SilcServer server = cmd->server;
738 SilcStatus status, error;
739 SilcServerEntry entry;
740 SilcServerID *server_id;
742 unsigned char *tmp, *name;
744 COMMAND_CHECK_STATUS;
747 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
750 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
755 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
759 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
762 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
765 /* Add the server to global list */
766 server_id = silc_id_dup(server_id, SILC_ID_SERVER);
767 entry = silc_idlist_add_server(server->global_list, name, 0,
768 server_id, cmd->sock->user_data,
771 silc_free(server_id);
774 entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
778 /* Get the info string */
779 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
783 entry->server_info = tmp ? strdup(tmp) : NULL;
786 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
788 silc_server_command_reply_free(cmd);
791 /* Received reply fro MOTD command. */
793 SILC_SERVER_CMD_REPLY_FUNC(motd)
795 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
796 SilcServer server = cmd->server;
797 SilcStatus status, error;
798 SilcServerEntry entry = NULL;
799 SilcServerID *server_id;
803 COMMAND_CHECK_STATUS;
806 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
809 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
813 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
816 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
823 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
830 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
832 silc_server_command_reply_free(cmd);
838 /* Received reply for forwarded JOIN command. Router has created or joined
839 the client to the channel. We save some channel information locally
842 SILC_SERVER_CMD_REPLY_FUNC(join)
844 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
845 SilcServer server = cmd->server;
846 SilcIDCacheEntry cache = NULL;
847 SilcStatus status, error;
849 SilcClientID *client_id = NULL;
850 SilcChannelEntry entry;
851 SilcHmac hmac = NULL;
852 SilcUInt32 id_len, len, list_count;
853 unsigned char *id_string;
854 char *channel_name, *tmp;
855 SilcUInt32 mode, created;
856 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
857 SilcPublicKey founder_key = NULL;
859 COMMAND_CHECK_STATUS;
861 /* Get channel name */
862 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
867 id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
872 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
875 client_id = silc_id_payload_parse_id(tmp, len, NULL);
880 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
883 SILC_GET32_MSB(mode, tmp);
885 /* Get created boolean value */
886 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
889 SILC_GET32_MSB(created, tmp);
890 if (created != 0 && created != 1)
893 /* Get channel key */
894 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
896 keyp = silc_buffer_alloc(len);
897 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
898 silc_buffer_put(keyp, tmp, len);
901 /* Parse the Channel ID */
902 id = silc_id_payload_parse_id(id_string, id_len, NULL);
907 tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
909 if (!silc_hmac_alloc(tmp, NULL, &hmac))
913 /* Get the list count */
914 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
917 SILC_GET32_MSB(list_count, tmp);
919 /* Get Client ID list */
920 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
924 client_id_list = silc_buffer_alloc(len);
925 silc_buffer_pull_tail(client_id_list, len);
926 silc_buffer_put(client_id_list, tmp, len);
928 /* Get client mode list */
929 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
933 client_mode_list = silc_buffer_alloc(len);
934 silc_buffer_pull_tail(client_mode_list, len);
935 silc_buffer_put(client_mode_list, tmp, len);
937 /* Get founder key */
938 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
940 silc_pkcs_public_key_decode(tmp, len, &founder_key);
942 /* See whether we already have the channel. */
943 entry = silc_idlist_find_channel_by_name(server->local_list,
944 channel_name, &cache);
946 /* Add new channel */
948 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
949 (created == 0 ? "existing" : "created"), channel_name,
950 silc_id_render(id, SILC_ID_CHANNEL)));
952 /* If the channel is found from global list we must move it to the
954 entry = silc_idlist_find_channel_by_name(server->global_list,
955 channel_name, &cache);
957 silc_idlist_del_channel(server->global_list, entry);
959 /* Add the channel to our local list. */
960 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
961 SILC_CHANNEL_MODE_NONE, id,
962 server->router, NULL, hmac, 0);
967 server->stat.my_channels++;
968 server->stat.channels++;
970 /* The entry exists. */
972 /* If ID has changed, then update it to the cache too. */
973 if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
974 silc_idlist_replace_channel_id(server->local_list, entry->id, id);
976 entry->disabled = FALSE;
978 /* Remove the founder auth data if the mode is not set but we have
980 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
981 silc_pkcs_public_key_free(entry->founder_key);
982 entry->founder_key = NULL;
987 if (entry->founder_key)
988 silc_pkcs_public_key_free(entry->founder_key);
989 entry->founder_key = founder_key;
993 if (entry->hmac_name && hmac) {
994 silc_free(entry->hmac_name);
995 entry->hmac_name = strdup(silc_hmac_get_name(hmac));
998 /* Get the ban list */
999 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
1001 silc_free(entry->ban_list);
1002 entry->ban_list = silc_memdup(tmp, len);
1005 /* Get the invite list */
1006 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
1008 silc_free(entry->invite_list);
1009 entry->invite_list = silc_memdup(tmp, len);
1013 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
1015 silc_free(entry->topic);
1016 entry->topic = strdup(tmp);
1019 /* If channel was not created we know there is global users on the
1021 entry->global_users = (created == 0 ? TRUE : FALSE);
1023 /* If channel was just created the mask must be zero */
1024 if (!entry->global_users && mode) {
1025 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
1026 "new channel, forcing it to zero", cmd->sock->hostname));
1030 /* Save channel mode */
1033 /* Save channel key */
1035 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
1036 silc_server_save_channel_key(server, keyp, entry);
1037 silc_buffer_free(keyp);
1040 /* Save the users to the channel */
1041 silc_server_save_users_on_channel(server, cmd->sock, entry,
1042 client_id, client_id_list,
1043 client_mode_list, list_count);
1044 entry->users_resolved = TRUE;
1047 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1049 silc_free(client_id);
1050 silc_server_command_reply_free(cmd);
1052 silc_pkcs_public_key_free(founder_key);
1054 silc_buffer_free(client_id_list);
1055 if (client_mode_list)
1056 silc_buffer_free(client_mode_list);
1059 /* Received reply to STATS command. */
1061 SILC_SERVER_CMD_REPLY_FUNC(stats)
1063 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1064 SilcServer server = cmd->server;
1065 SilcStatus status, error;
1068 SilcBufferStruct buf;
1070 COMMAND_CHECK_STATUS;
1072 /* Get statistics structure */
1073 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1074 if (server->server_type == SILC_SERVER && tmp) {
1075 silc_buffer_set(&buf, tmp, tmp_len);
1076 silc_buffer_unformat(&buf,
1077 SILC_STR_UI_INT(NULL),
1078 SILC_STR_UI_INT(NULL),
1079 SILC_STR_UI_INT(NULL),
1080 SILC_STR_UI_INT(NULL),
1081 SILC_STR_UI_INT(NULL),
1082 SILC_STR_UI_INT(NULL),
1083 SILC_STR_UI_INT(&server->stat.cell_clients),
1084 SILC_STR_UI_INT(&server->stat.cell_channels),
1085 SILC_STR_UI_INT(&server->stat.cell_servers),
1086 SILC_STR_UI_INT(&server->stat.clients),
1087 SILC_STR_UI_INT(&server->stat.channels),
1088 SILC_STR_UI_INT(&server->stat.servers),
1089 SILC_STR_UI_INT(&server->stat.routers),
1090 SILC_STR_UI_INT(&server->stat.server_ops),
1091 SILC_STR_UI_INT(&server->stat.router_ops),
1096 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
1098 silc_server_command_reply_free(cmd);
1101 SILC_SERVER_CMD_REPLY_FUNC(users)
1103 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1104 SilcServer server = cmd->server;
1105 SilcStatus status, error;
1106 SilcChannelEntry channel;
1107 SilcChannelID *channel_id = NULL;
1108 SilcBuffer client_id_list;
1109 SilcBuffer client_mode_list;
1112 SilcUInt32 list_count;
1114 COMMAND_CHECK_STATUS;
1116 /* Get channel ID */
1117 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1120 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1124 /* Get channel entry */
1125 channel = silc_idlist_find_channel_by_id(server->local_list,
1128 channel = silc_idlist_find_channel_by_id(server->global_list,
1133 if (server->server_type != SILC_SERVER)
1136 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1137 silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
1138 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1139 1, 5, idp->data, idp->len);
1140 silc_buffer_free(idp);
1142 /* Register pending command callback. After we've received the channel
1143 information we will reprocess this command reply by re-calling this
1144 USERS command reply callback. */
1145 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1147 silc_server_command_reply_users, cmd);
1152 /* Get the list count */
1153 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1156 SILC_GET32_MSB(list_count, tmp);
1158 /* Get Client ID list */
1159 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1163 client_id_list = silc_buffer_alloc(tmp_len);
1164 silc_buffer_pull_tail(client_id_list, tmp_len);
1165 silc_buffer_put(client_id_list, tmp, tmp_len);
1167 /* Get client mode list */
1168 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1172 client_mode_list = silc_buffer_alloc(tmp_len);
1173 silc_buffer_pull_tail(client_mode_list, tmp_len);
1174 silc_buffer_put(client_mode_list, tmp, tmp_len);
1176 /* Save the users to the channel */
1177 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1178 client_id_list, client_mode_list,
1181 channel->global_users = silc_server_channel_has_global(channel);
1182 channel->users_resolved = TRUE;
1184 silc_buffer_free(client_id_list);
1185 silc_buffer_free(client_mode_list);
1188 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1189 silc_free(channel_id);
1191 silc_server_command_reply_free(cmd);
1194 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1196 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1197 SilcServer server = cmd->server;
1198 SilcStatus status, error;
1199 SilcClientEntry client = NULL;
1200 SilcServerEntry server_entry = NULL;
1201 SilcClientID *client_id = NULL;
1202 SilcServerID *server_id = NULL;
1204 unsigned char *tmp, *pk;
1207 SilcIDPayload idp = NULL;
1209 SilcPublicKey public_key = NULL;
1211 COMMAND_CHECK_STATUS;
1213 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1216 idp = silc_id_payload_parse(tmp, len);
1220 /* Get the public key payload */
1221 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1225 /* Decode the public key */
1227 SILC_GET16_MSB(pk_len, tmp);
1228 SILC_GET16_MSB(type, tmp + 2);
1231 if (type != SILC_SKE_PK_TYPE_SILC)
1234 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1237 id_type = silc_id_payload_get_type(idp);
1238 if (id_type == SILC_ID_CLIENT) {
1239 client_id = silc_id_payload_get_id(idp);
1241 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1244 client = silc_idlist_find_client_by_id(server->global_list,
1245 client_id, TRUE, NULL);
1250 client->data.public_key = public_key;
1252 } else if (id_type == SILC_ID_SERVER) {
1253 server_id = silc_id_payload_get_id(idp);
1255 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1257 if (!server_entry) {
1258 server_entry = silc_idlist_find_server_by_id(server->global_list,
1259 server_id, TRUE, NULL);
1264 server_entry->data.public_key = public_key;
1271 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1273 silc_id_payload_free(idp);
1274 silc_free(client_id);
1275 silc_free(server_id);
1277 silc_pkcs_public_key_free(public_key);
1279 silc_server_command_reply_free(cmd);
1282 SILC_SERVER_CMD_REPLY_FUNC(list)
1284 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1285 SilcServer server = cmd->server;
1286 SilcStatus status, error;
1287 SilcChannelID *channel_id = NULL;
1288 SilcChannelEntry channel;
1289 SilcIDCacheEntry cache;
1291 unsigned char *tmp, *name, *topic;
1292 SilcUInt32 usercount = 0;
1293 bool global_list = FALSE;
1295 COMMAND_CHECK_STATUS;
1297 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1298 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1302 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1303 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1304 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1306 SILC_GET32_MSB(usercount, tmp);
1308 /* Add the channel entry if we do not have it already */
1309 channel = silc_idlist_find_channel_by_name(server->local_list,
1312 channel = silc_idlist_find_channel_by_name(server->global_list,
1317 /* If router did not find such channel in its lists then this must
1318 be bogus channel or some router in the net is buggy. */
1319 if (server->server_type != SILC_SERVER)
1322 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1323 SILC_CHANNEL_MODE_NONE, channel_id,
1324 server->router, NULL, NULL,
1330 /* Found, update expiry */
1331 if (global_list && server->server_type == SILC_SERVER)
1332 cache->expire = time(NULL) + 60;
1335 channel->user_count = usercount;
1338 silc_free(channel->topic);
1339 channel->topic = strdup(topic);
1342 /* Pending callbacks are not executed if this was an list entry */
1343 if (status != SILC_STATUS_OK &&
1344 status != SILC_STATUS_LIST_END) {
1345 silc_server_command_reply_free(cmd);
1349 /* Now purge all old entries from the global list, otherwise we'll might
1350 have non-existent entries for long periods of time in the cache. */
1351 silc_idcache_purge(server->global_list->channels);
1354 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1355 silc_free(channel_id);
1357 silc_server_command_reply_free(cmd);
1360 SILC_SERVER_CMD_REPLY_FUNC(watch)
1362 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1363 SilcStatus status, error;
1365 COMMAND_CHECK_STATUS;
1368 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1370 silc_server_command_reply_free(cmd);