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);
319 /* Reiceved reply for WHOIS command. We sent the whois request to our
320 primary router, if we are normal server, and thus has now received reply
321 to the command. We will figure out what client originally sent us the
322 command and will send the reply to it. If we are router we will figure
323 out who server sent us the command and send reply to that one. */
325 SILC_SERVER_CMD_REPLY_FUNC(whois)
327 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
328 SilcStatus status, error;
330 COMMAND_CHECK_STATUS;
332 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) {
333 if (!silc_server_command_reply_whois_save(cmd))
336 if (!silc_server_command_reply_whois_save_client(cmd))
340 /* Pending callbacks are not executed if this was an list entry */
341 if (status != SILC_STATUS_OK &&
342 status != SILC_STATUS_LIST_END) {
343 silc_server_command_reply_free(cmd);
348 silc_server_command_process_error(cmd, error);
349 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
350 silc_server_command_reply_free(cmd);
354 silc_server_command_process_error(cmd, error);
355 silc_server_command_reply_free(cmd);
358 /* Caches the received WHOWAS information for a short period of time. */
361 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
363 SilcServer server = cmd->server;
364 SilcUInt32 len, id_len;
365 unsigned char *id_data;
366 char *nickname, *username, *realname, *servername = NULL;
367 SilcClientID *client_id;
368 SilcClientEntry client;
369 SilcIDCacheEntry cache = NULL;
373 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
374 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
375 username = silc_argument_get_arg_type(cmd->args, 4, &len);
376 if (!id_data || !nickname || !username)
379 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
381 client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
385 /* Check if we have this client cached already. */
387 client = silc_idlist_find_client_by_id(server->local_list, client_id,
390 client = silc_idlist_find_client_by_id(server->global_list,
391 client_id, FALSE, &cache);
396 /* If router did not find such Client ID in its lists then this must
397 be bogus client or some router in the net is buggy. */
398 if (server->server_type != SILC_SERVER)
401 /* Take hostname out of nick string if it includes it. */
402 silc_parse_userfqdn(nickname, &nick, &servername);
404 /* We don't have that client anywhere, add it. The client is added
405 to global list since server didn't have it in the lists so it must be
407 client = silc_idlist_add_client(server->global_list, nick,
408 strdup(username), strdup(realname),
409 silc_id_dup(client_id, SILC_ID_CLIENT),
410 cmd->sock->user_data, NULL,
411 SILC_ID_CACHE_EXPIRE_DEF);
413 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
417 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
418 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
419 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
420 client->servername = servername;
422 /* We have the client already, update the data */
424 /* Take hostname out of nick string if it includes it. */
425 silc_parse_userfqdn(nickname, &nick, &servername);
427 silc_free(client->nickname);
428 silc_free(client->username);
429 silc_free(client->servername);
431 client->nickname = nick;
432 client->username = strdup(username);
433 client->servername = servername;
434 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
435 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
437 /* Remove the old cache entry and create a new one */
438 silc_idcache_del_by_context(global ? server->global_list->clients :
439 server->local_list->clients, client);
440 silc_idcache_add(global ? server->global_list->clients :
441 server->local_list->clients, nick, client->id,
445 /* If client is global and is not on any channel then add that we'll
446 expire the entry after a while. */
448 silc_idlist_find_client_by_id(server->global_list, client->id,
450 if (!silc_hash_table_count(client->channels))
451 cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
456 silc_free(client_id);
461 /* Received reply for WHOWAS command. Cache the client information only for
462 a short period of time. */
464 SILC_SERVER_CMD_REPLY_FUNC(whowas)
466 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
467 SilcStatus status, error;
469 COMMAND_CHECK_STATUS;
471 if (!silc_server_command_reply_whowas_save(cmd))
474 /* Pending callbacks are not executed if this was an list entry */
475 if (status != SILC_STATUS_OK &&
476 status != SILC_STATUS_LIST_END) {
477 silc_server_command_reply_free(cmd);
482 silc_server_command_process_error(cmd, error);
483 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
484 silc_server_command_reply_free(cmd);
488 silc_server_command_process_error(cmd, error);
489 silc_server_command_reply_free(cmd);
492 /* Caches the received IDENTIFY information. */
495 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
497 SilcServer server = cmd->server;
498 SilcUInt32 len, id_len;
499 unsigned char *id_data;
501 SilcClientID *client_id = NULL;
502 SilcServerID *server_id = NULL;
503 SilcChannelID *channel_id = NULL;
504 SilcClientEntry client;
505 SilcServerEntry server_entry;
506 SilcChannelEntry channel;
509 SilcIDPayload idp = NULL;
513 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
516 idp = silc_id_payload_parse(id_data, id_len);
520 name = silc_argument_get_arg_type(cmd->args, 3, &len);
521 info = silc_argument_get_arg_type(cmd->args, 4, &len);
523 id_type = silc_id_payload_get_type(idp);
527 client_id = silc_id_payload_get_id(idp);
531 SILC_LOG_DEBUG(("Received client information"));
533 client = silc_idlist_find_client_by_id(server->local_list,
534 client_id, FALSE, NULL);
536 client = silc_idlist_find_client_by_id(server->global_list, client_id,
541 /* If router did not find such Client ID in its lists then this must
542 be bogus client or some router in the net is buggy. */
543 if (server->server_type != SILC_SERVER)
548 silc_parse_userfqdn(name, &nick, NULL);
550 /* We don't have that client anywhere, add it. The client is added
551 to global list since server didn't have it in the lists so it must be
553 client = silc_idlist_add_client(server->global_list, nick,
554 info ? strdup(info) : NULL, NULL,
555 client_id, cmd->sock->user_data,
556 NULL, time(NULL) + 300);
558 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
561 client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
562 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
563 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
565 /* We have the client already, update the data */
567 SILC_LOG_DEBUG(("Updating client data"));
571 silc_parse_userfqdn(name, &nick, NULL);
573 /* Remove the old cache entry */
574 silc_idcache_del_by_context(global ? server->global_list->clients :
575 server->local_list->clients, client);
577 silc_free(client->nickname);
578 client->nickname = nick;
582 silc_free(client->username);
583 client->username = strdup(info);
586 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
587 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
590 /* Add new cache entry */
591 silc_idcache_add(global ? server->global_list->clients :
592 server->local_list->clients, nick, client->id,
593 client, expire, NULL);
596 /* If client is global and is not on any channel then add that we'll
597 expire the entry after a while. */
598 if (global && server->server_type == SILC_SERVER) {
599 SilcIDCacheEntry cache = NULL;
600 silc_idlist_find_client_by_id(server->global_list, client->id,
602 if (!silc_hash_table_count(client->channels))
603 cache->expire = time(NULL) + 300;
608 silc_free(client_id);
617 server_id = silc_id_payload_get_id(idp);
621 SILC_LOG_DEBUG(("Received server information"));
623 server_entry = silc_idlist_find_server_by_id(server->local_list,
624 server_id, FALSE, NULL);
626 server_entry = silc_idlist_find_server_by_id(server->global_list,
627 server_id, FALSE, NULL);
629 /* If router did not find such Server ID in its lists then this must
630 be bogus server or some router in the net is buggy. */
631 if (server->server_type != SILC_SERVER)
634 /* We don't have that server anywhere, add it. */
635 server_entry = silc_idlist_add_server(server->global_list,
637 server_id, server->router,
638 SILC_PRIMARY_ROUTE(server));
640 silc_free(server_id);
643 server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
644 server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
645 server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
649 silc_free(server_id);
652 case SILC_ID_CHANNEL:
656 channel_id = silc_id_payload_get_id(idp);
660 SILC_LOG_DEBUG(("Received channel information"));
662 channel = silc_idlist_find_channel_by_name(server->local_list,
665 channel = silc_idlist_find_channel_by_name(server->global_list,
668 /* If router did not find such Channel ID in its lists then this must
669 be bogus channel or some router in the net is buggy. */
670 if (server->server_type != SILC_SERVER)
673 /* We don't have that channel anywhere, add it. */
674 channel = silc_idlist_add_channel(server->global_list, strdup(name),
675 SILC_CHANNEL_MODE_NONE, channel_id,
676 server->router, NULL, NULL, 0);
678 silc_free(channel_id);
684 silc_free(channel_id);
688 silc_id_payload_free(idp);
692 silc_id_payload_free(idp);
696 /* Received reply for forwarded IDENTIFY command. We have received the
697 requested identify information now and we will cache it. After this we
698 will call the pending command so that the requestee gets the information
701 SILC_SERVER_CMD_REPLY_FUNC(identify)
703 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
704 SilcStatus status, error;
706 COMMAND_CHECK_STATUS;
708 if (!silc_server_command_reply_identify_save(cmd))
711 /* Pending callbacks are not executed if this was an list entry */
712 if (status != SILC_STATUS_OK &&
713 status != SILC_STATUS_LIST_END) {
714 silc_server_command_reply_free(cmd);
719 silc_server_command_process_error(cmd, error);
720 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
721 silc_server_command_reply_free(cmd);
725 silc_server_command_process_error(cmd, error);
726 silc_server_command_reply_free(cmd);
729 /* Received reply fro INFO command. Cache the server and its information */
731 SILC_SERVER_CMD_REPLY_FUNC(info)
733 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
734 SilcServer server = cmd->server;
735 SilcStatus status, error;
736 SilcServerEntry entry;
737 SilcServerID *server_id;
739 unsigned char *tmp, *name;
741 COMMAND_CHECK_STATUS;
744 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
747 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
752 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
756 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
759 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
762 /* Add the server to global list */
763 server_id = silc_id_dup(server_id, SILC_ID_SERVER);
764 entry = silc_idlist_add_server(server->global_list, name, 0,
765 server_id, cmd->sock->user_data,
768 silc_free(server_id);
771 entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
775 /* Get the info string */
776 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
780 entry->server_info = tmp ? strdup(tmp) : NULL;
783 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
785 silc_server_command_reply_free(cmd);
788 /* Received reply fro MOTD command. */
790 SILC_SERVER_CMD_REPLY_FUNC(motd)
792 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
793 SilcServer server = cmd->server;
794 SilcStatus status, error;
795 SilcServerEntry entry = NULL;
796 SilcServerID *server_id;
800 COMMAND_CHECK_STATUS;
803 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
806 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
810 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
813 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
820 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
827 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
829 silc_server_command_reply_free(cmd);
835 /* Received reply for forwarded JOIN command. Router has created or joined
836 the client to the channel. We save some channel information locally
839 SILC_SERVER_CMD_REPLY_FUNC(join)
841 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
842 SilcServer server = cmd->server;
843 SilcIDCacheEntry cache = NULL;
844 SilcStatus status, error;
846 SilcClientID *client_id = NULL;
847 SilcChannelEntry entry;
848 SilcHmac hmac = NULL;
849 SilcUInt32 id_len, len, list_count;
850 unsigned char *id_string;
851 char *channel_name, *tmp;
852 SilcUInt32 mode, created;
853 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
854 SilcPublicKey founder_key = NULL;
856 COMMAND_CHECK_STATUS;
858 /* Get channel name */
859 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
864 id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
869 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
872 client_id = silc_id_payload_parse_id(tmp, len, NULL);
877 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
880 SILC_GET32_MSB(mode, tmp);
882 /* Get created boolean value */
883 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
886 SILC_GET32_MSB(created, tmp);
887 if (created != 0 && created != 1)
890 /* Get channel key */
891 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
893 keyp = silc_buffer_alloc(len);
894 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
895 silc_buffer_put(keyp, tmp, len);
898 /* Parse the Channel ID */
899 id = silc_id_payload_parse_id(id_string, id_len, NULL);
904 tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
906 if (!silc_hmac_alloc(tmp, NULL, &hmac))
910 /* Get the list count */
911 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
914 SILC_GET32_MSB(list_count, tmp);
916 /* Get Client ID list */
917 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
921 client_id_list = silc_buffer_alloc(len);
922 silc_buffer_pull_tail(client_id_list, len);
923 silc_buffer_put(client_id_list, tmp, len);
925 /* Get client mode list */
926 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
930 client_mode_list = silc_buffer_alloc(len);
931 silc_buffer_pull_tail(client_mode_list, len);
932 silc_buffer_put(client_mode_list, tmp, len);
934 /* Get founder key */
935 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
937 silc_pkcs_public_key_decode(tmp, len, &founder_key);
939 /* See whether we already have the channel. */
940 entry = silc_idlist_find_channel_by_name(server->local_list,
941 channel_name, &cache);
943 /* Add new channel */
945 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
946 (created == 0 ? "existing" : "created"), channel_name,
947 silc_id_render(id, SILC_ID_CHANNEL)));
949 /* If the channel is found from global list we must move it to the
951 entry = silc_idlist_find_channel_by_name(server->global_list,
952 channel_name, &cache);
954 silc_idlist_del_channel(server->global_list, entry);
956 /* Add the channel to our local list. */
957 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
958 SILC_CHANNEL_MODE_NONE, id,
959 server->router, NULL, hmac, 0);
964 server->stat.my_channels++;
965 server->stat.channels++;
967 /* The entry exists. */
969 /* If ID has changed, then update it to the cache too. */
970 if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
971 silc_idlist_replace_channel_id(server->local_list, entry->id, id);
973 entry->disabled = FALSE;
975 /* Remove the founder auth data if the mode is not set but we have
977 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
978 silc_pkcs_public_key_free(entry->founder_key);
979 entry->founder_key = NULL;
984 if (entry->founder_key)
985 silc_pkcs_public_key_free(entry->founder_key);
986 entry->founder_key = founder_key;
990 if (entry->hmac_name && hmac) {
991 silc_free(entry->hmac_name);
992 entry->hmac_name = strdup(silc_hmac_get_name(hmac));
995 /* Get the ban list */
996 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
998 silc_free(entry->ban_list);
999 entry->ban_list = silc_memdup(tmp, len);
1002 /* Get the invite list */
1003 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
1005 silc_free(entry->invite_list);
1006 entry->invite_list = silc_memdup(tmp, len);
1010 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
1012 silc_free(entry->topic);
1013 entry->topic = strdup(tmp);
1016 /* If channel was not created we know there is global users on the
1018 entry->global_users = (created == 0 ? TRUE : FALSE);
1020 /* If channel was just created the mask must be zero */
1021 if (!entry->global_users && mode) {
1022 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
1023 "new channel, forcing it to zero", cmd->sock->hostname));
1027 /* Save channel mode */
1030 /* Save channel key */
1032 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
1033 silc_server_save_channel_key(server, keyp, entry);
1034 silc_buffer_free(keyp);
1037 /* Save the users to the channel */
1038 silc_server_save_users_on_channel(server, cmd->sock, entry,
1039 client_id, client_id_list,
1040 client_mode_list, list_count);
1041 entry->users_resolved = TRUE;
1044 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1046 silc_free(client_id);
1047 silc_server_command_reply_free(cmd);
1049 silc_pkcs_public_key_free(founder_key);
1051 silc_buffer_free(client_id_list);
1052 if (client_mode_list)
1053 silc_buffer_free(client_mode_list);
1056 /* Received reply to STATS command. */
1058 SILC_SERVER_CMD_REPLY_FUNC(stats)
1060 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1061 SilcServer server = cmd->server;
1062 SilcStatus status, error;
1065 SilcBufferStruct buf;
1067 COMMAND_CHECK_STATUS;
1069 /* Get statistics structure */
1070 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1071 if (server->server_type == SILC_SERVER && tmp) {
1072 silc_buffer_set(&buf, tmp, tmp_len);
1073 silc_buffer_unformat(&buf,
1074 SILC_STR_UI_INT(NULL),
1075 SILC_STR_UI_INT(NULL),
1076 SILC_STR_UI_INT(NULL),
1077 SILC_STR_UI_INT(NULL),
1078 SILC_STR_UI_INT(NULL),
1079 SILC_STR_UI_INT(NULL),
1080 SILC_STR_UI_INT(&server->stat.cell_clients),
1081 SILC_STR_UI_INT(&server->stat.cell_channels),
1082 SILC_STR_UI_INT(&server->stat.cell_servers),
1083 SILC_STR_UI_INT(&server->stat.clients),
1084 SILC_STR_UI_INT(&server->stat.channels),
1085 SILC_STR_UI_INT(&server->stat.servers),
1086 SILC_STR_UI_INT(&server->stat.routers),
1087 SILC_STR_UI_INT(&server->stat.server_ops),
1088 SILC_STR_UI_INT(&server->stat.router_ops),
1093 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
1095 silc_server_command_reply_free(cmd);
1098 SILC_SERVER_CMD_REPLY_FUNC(users)
1100 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1101 SilcServer server = cmd->server;
1102 SilcStatus status, error;
1103 SilcChannelEntry channel;
1104 SilcChannelID *channel_id = NULL;
1105 SilcBuffer client_id_list;
1106 SilcBuffer client_mode_list;
1109 SilcUInt32 list_count;
1111 COMMAND_CHECK_STATUS;
1113 /* Get channel ID */
1114 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1117 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1121 /* Get channel entry */
1122 channel = silc_idlist_find_channel_by_id(server->local_list,
1125 channel = silc_idlist_find_channel_by_id(server->global_list,
1130 if (server->server_type != SILC_SERVER)
1133 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1134 silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
1135 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1136 1, 5, idp->data, idp->len);
1137 silc_buffer_free(idp);
1139 /* Register pending command callback. After we've received the channel
1140 information we will reprocess this command reply by re-calling this
1141 USERS command reply callback. */
1142 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1144 silc_server_command_reply_users, cmd);
1149 /* Get the list count */
1150 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1153 SILC_GET32_MSB(list_count, tmp);
1155 /* Get Client ID list */
1156 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1160 client_id_list = silc_buffer_alloc(tmp_len);
1161 silc_buffer_pull_tail(client_id_list, tmp_len);
1162 silc_buffer_put(client_id_list, tmp, tmp_len);
1164 /* Get client mode list */
1165 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1169 client_mode_list = silc_buffer_alloc(tmp_len);
1170 silc_buffer_pull_tail(client_mode_list, tmp_len);
1171 silc_buffer_put(client_mode_list, tmp, tmp_len);
1173 /* Save the users to the channel */
1174 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1175 client_id_list, client_mode_list,
1178 channel->global_users = silc_server_channel_has_global(channel);
1179 channel->users_resolved = TRUE;
1181 silc_buffer_free(client_id_list);
1182 silc_buffer_free(client_mode_list);
1185 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1186 silc_free(channel_id);
1188 silc_server_command_reply_free(cmd);
1191 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1193 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1194 SilcServer server = cmd->server;
1195 SilcStatus status, error;
1196 SilcClientEntry client = NULL;
1197 SilcServerEntry server_entry = NULL;
1198 SilcClientID *client_id = NULL;
1199 SilcServerID *server_id = NULL;
1201 unsigned char *tmp, *pk;
1204 SilcIDPayload idp = NULL;
1206 SilcPublicKey public_key = NULL;
1208 COMMAND_CHECK_STATUS;
1210 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1213 idp = silc_id_payload_parse(tmp, len);
1217 /* Get the public key payload */
1218 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1222 /* Decode the public key */
1224 SILC_GET16_MSB(pk_len, tmp);
1225 SILC_GET16_MSB(type, tmp + 2);
1228 if (type != SILC_SKE_PK_TYPE_SILC)
1231 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1234 id_type = silc_id_payload_get_type(idp);
1235 if (id_type == SILC_ID_CLIENT) {
1236 client_id = silc_id_payload_get_id(idp);
1238 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1241 client = silc_idlist_find_client_by_id(server->global_list,
1242 client_id, TRUE, NULL);
1247 client->data.public_key = public_key;
1249 } else if (id_type == SILC_ID_SERVER) {
1250 server_id = silc_id_payload_get_id(idp);
1252 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1254 if (!server_entry) {
1255 server_entry = silc_idlist_find_server_by_id(server->global_list,
1256 server_id, TRUE, NULL);
1261 server_entry->data.public_key = public_key;
1268 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1270 silc_id_payload_free(idp);
1271 silc_free(client_id);
1272 silc_free(server_id);
1274 silc_pkcs_public_key_free(public_key);
1276 silc_server_command_reply_free(cmd);
1279 SILC_SERVER_CMD_REPLY_FUNC(list)
1281 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1282 SilcServer server = cmd->server;
1283 SilcStatus status, error;
1284 SilcChannelID *channel_id = NULL;
1285 SilcChannelEntry channel;
1286 SilcIDCacheEntry cache;
1288 unsigned char *tmp, *name, *topic;
1289 SilcUInt32 usercount = 0;
1290 bool global_list = FALSE;
1292 COMMAND_CHECK_STATUS;
1294 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1295 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1299 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1300 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1301 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1303 SILC_GET32_MSB(usercount, tmp);
1305 /* Add the channel entry if we do not have it already */
1306 channel = silc_idlist_find_channel_by_name(server->local_list,
1309 channel = silc_idlist_find_channel_by_name(server->global_list,
1314 /* If router did not find such channel in its lists then this must
1315 be bogus channel or some router in the net is buggy. */
1316 if (server->server_type != SILC_SERVER)
1319 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1320 SILC_CHANNEL_MODE_NONE, channel_id,
1321 server->router, NULL, NULL,
1327 /* Found, update expiry */
1328 if (global_list && server->server_type == SILC_SERVER)
1329 cache->expire = time(NULL) + 60;
1332 channel->user_count = usercount;
1335 silc_free(channel->topic);
1336 channel->topic = strdup(topic);
1339 /* Pending callbacks are not executed if this was an list entry */
1340 if (status != SILC_STATUS_OK &&
1341 status != SILC_STATUS_LIST_END) {
1342 silc_server_command_reply_free(cmd);
1346 /* Now purge all old entries from the global list, otherwise we'll might
1347 have non-existent entries for long periods of time in the cache. */
1348 silc_idcache_purge(server->global_list->channels);
1351 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1352 silc_free(channel_id);
1354 silc_server_command_reply_free(cmd);
1357 SILC_SERVER_CMD_REPLY_FUNC(watch)
1359 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1360 SilcStatus status, error;
1362 COMMAND_CHECK_STATUS;
1365 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1367 silc_server_command_reply_free(cmd);