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);
316 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
321 /* Reiceved reply for WHOIS command. We sent the whois request to our
322 primary router, if we are normal server, and thus has now received reply
323 to the command. We will figure out what client originally sent us the
324 command and will send the reply to it. If we are router we will figure
325 out who server sent us the command and send reply to that one. */
327 SILC_SERVER_CMD_REPLY_FUNC(whois)
329 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
330 SilcStatus status, error;
332 COMMAND_CHECK_STATUS;
334 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) {
335 if (!silc_server_command_reply_whois_save(cmd))
338 if (!silc_server_command_reply_whois_save_client(cmd))
342 /* Pending callbacks are not executed if this was an list entry */
343 if (status != SILC_STATUS_OK &&
344 status != SILC_STATUS_LIST_END) {
345 silc_server_command_reply_free(cmd);
350 silc_server_command_process_error(cmd, error);
351 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
352 silc_server_command_reply_free(cmd);
356 silc_server_command_process_error(cmd, error);
357 silc_server_command_reply_free(cmd);
360 /* Caches the received WHOWAS information for a short period of time. */
363 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
365 SilcServer server = cmd->server;
366 SilcUInt32 len, id_len;
367 unsigned char *id_data;
368 char *nickname, *username, *realname, *servername = NULL;
369 SilcClientID *client_id;
370 SilcClientEntry client;
371 SilcIDCacheEntry cache = NULL;
375 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
376 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
377 username = silc_argument_get_arg_type(cmd->args, 4, &len);
378 if (!id_data || !nickname || !username)
381 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
383 client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
387 /* Check if we have this client cached already. */
389 client = silc_idlist_find_client_by_id(server->local_list, client_id,
392 client = silc_idlist_find_client_by_id(server->global_list,
393 client_id, FALSE, &cache);
398 /* If router did not find such Client ID in its lists then this must
399 be bogus client or some router in the net is buggy. */
400 if (server->server_type != SILC_SERVER)
403 /* Take hostname out of nick string if it includes it. */
404 silc_parse_userfqdn(nickname, &nick, &servername);
406 /* We don't have that client anywhere, add it. The client is added
407 to global list since server didn't have it in the lists so it must be
409 client = silc_idlist_add_client(server->global_list, nick,
410 strdup(username), strdup(realname),
411 silc_id_dup(client_id, SILC_ID_CLIENT),
412 cmd->sock->user_data, NULL,
413 SILC_ID_CACHE_EXPIRE_DEF);
415 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
419 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
420 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
421 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
422 client->servername = servername;
424 /* We have the client already, update the data */
426 /* Take hostname out of nick string if it includes it. */
427 silc_parse_userfqdn(nickname, &nick, &servername);
429 silc_free(client->nickname);
430 silc_free(client->username);
431 silc_free(client->servername);
433 client->nickname = nick;
434 client->username = strdup(username);
435 client->servername = servername;
436 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
437 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
439 /* Remove the old cache entry and create a new one */
440 silc_idcache_del_by_context(global ? server->global_list->clients :
441 server->local_list->clients, client);
442 silc_idcache_add(global ? server->global_list->clients :
443 server->local_list->clients, nick, client->id,
447 /* If client is global and is not on any channel then add that we'll
448 expire the entry after a while. */
450 silc_idlist_find_client_by_id(server->global_list, client->id,
452 if (!silc_hash_table_count(client->channels))
453 cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
458 silc_free(client_id);
463 /* Received reply for WHOWAS command. Cache the client information only for
464 a short period of time. */
466 SILC_SERVER_CMD_REPLY_FUNC(whowas)
468 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
469 SilcStatus status, error;
471 COMMAND_CHECK_STATUS;
473 if (!silc_server_command_reply_whowas_save(cmd))
476 /* Pending callbacks are not executed if this was an list entry */
477 if (status != SILC_STATUS_OK &&
478 status != SILC_STATUS_LIST_END) {
479 silc_server_command_reply_free(cmd);
484 silc_server_command_process_error(cmd, error);
485 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
486 silc_server_command_reply_free(cmd);
490 silc_server_command_process_error(cmd, error);
491 silc_server_command_reply_free(cmd);
494 /* Caches the received IDENTIFY information. */
497 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
499 SilcServer server = cmd->server;
500 SilcUInt32 len, id_len;
501 unsigned char *id_data;
503 SilcClientID *client_id = NULL;
504 SilcServerID *server_id = NULL;
505 SilcChannelID *channel_id = NULL;
506 SilcClientEntry client;
507 SilcServerEntry server_entry;
508 SilcChannelEntry channel;
511 SilcIDPayload idp = NULL;
515 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
518 idp = silc_id_payload_parse(id_data, id_len);
522 name = silc_argument_get_arg_type(cmd->args, 3, &len);
523 info = silc_argument_get_arg_type(cmd->args, 4, &len);
525 id_type = silc_id_payload_get_type(idp);
529 client_id = silc_id_payload_get_id(idp);
533 SILC_LOG_DEBUG(("Received client information"));
535 client = silc_idlist_find_client_by_id(server->local_list,
536 client_id, FALSE, NULL);
538 client = silc_idlist_find_client_by_id(server->global_list, client_id,
543 /* If router did not find such Client ID in its lists then this must
544 be bogus client or some router in the net is buggy. */
545 if (server->server_type != SILC_SERVER)
550 silc_parse_userfqdn(name, &nick, NULL);
552 /* We don't have that client anywhere, add it. The client is added
553 to global list since server didn't have it in the lists so it must be
555 client = silc_idlist_add_client(server->global_list, nick,
556 info ? strdup(info) : NULL, NULL,
557 client_id, cmd->sock->user_data,
558 NULL, time(NULL) + 300);
560 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
563 client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
564 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
565 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
567 /* We have the client already, update the data */
569 SILC_LOG_DEBUG(("Updating client data"));
573 silc_parse_userfqdn(name, &nick, NULL);
575 /* Remove the old cache entry */
576 silc_idcache_del_by_context(global ? server->global_list->clients :
577 server->local_list->clients, client);
579 silc_free(client->nickname);
580 client->nickname = nick;
584 silc_free(client->username);
585 client->username = strdup(info);
588 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
589 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
592 /* Add new cache entry */
593 silc_idcache_add(global ? server->global_list->clients :
594 server->local_list->clients, nick, client->id,
595 client, expire, NULL);
598 /* If client is global and is not on any channel then add that we'll
599 expire the entry after a while. */
600 if (global && server->server_type == SILC_SERVER) {
601 SilcIDCacheEntry cache = NULL;
602 silc_idlist_find_client_by_id(server->global_list, client->id,
604 if (!silc_hash_table_count(client->channels))
605 cache->expire = time(NULL) + 300;
610 silc_free(client_id);
619 server_id = silc_id_payload_get_id(idp);
623 SILC_LOG_DEBUG(("Received server information"));
625 server_entry = silc_idlist_find_server_by_id(server->local_list,
626 server_id, FALSE, NULL);
628 server_entry = silc_idlist_find_server_by_id(server->global_list,
629 server_id, FALSE, NULL);
631 /* If router did not find such Server ID in its lists then this must
632 be bogus server or some router in the net is buggy. */
633 if (server->server_type != SILC_SERVER)
636 /* We don't have that server anywhere, add it. */
637 server_entry = silc_idlist_add_server(server->global_list,
639 server_id, server->router,
640 SILC_PRIMARY_ROUTE(server));
642 silc_free(server_id);
645 server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
646 server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
647 server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
651 silc_free(server_id);
654 case SILC_ID_CHANNEL:
658 channel_id = silc_id_payload_get_id(idp);
662 SILC_LOG_DEBUG(("Received channel information"));
664 channel = silc_idlist_find_channel_by_name(server->local_list,
667 channel = silc_idlist_find_channel_by_name(server->global_list,
670 /* If router did not find such Channel ID in its lists then this must
671 be bogus channel or some router in the net is buggy. */
672 if (server->server_type != SILC_SERVER)
675 /* We don't have that channel anywhere, add it. */
676 channel = silc_idlist_add_channel(server->global_list, strdup(name),
677 SILC_CHANNEL_MODE_NONE, channel_id,
678 server->router, NULL, NULL, 0);
680 silc_free(channel_id);
686 silc_free(channel_id);
690 silc_id_payload_free(idp);
694 silc_id_payload_free(idp);
698 /* Received reply for forwarded IDENTIFY command. We have received the
699 requested identify information now and we will cache it. After this we
700 will call the pending command so that the requestee gets the information
703 SILC_SERVER_CMD_REPLY_FUNC(identify)
705 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
706 SilcStatus status, error;
708 COMMAND_CHECK_STATUS;
710 if (!silc_server_command_reply_identify_save(cmd))
713 /* Pending callbacks are not executed if this was an list entry */
714 if (status != SILC_STATUS_OK &&
715 status != SILC_STATUS_LIST_END) {
716 silc_server_command_reply_free(cmd);
721 silc_server_command_process_error(cmd, error);
722 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
723 silc_server_command_reply_free(cmd);
727 silc_server_command_process_error(cmd, error);
728 silc_server_command_reply_free(cmd);
731 /* Received reply fro INFO command. Cache the server and its information */
733 SILC_SERVER_CMD_REPLY_FUNC(info)
735 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
736 SilcServer server = cmd->server;
737 SilcStatus status, error;
738 SilcServerEntry entry;
739 SilcServerID *server_id;
741 unsigned char *tmp, *name;
743 COMMAND_CHECK_STATUS;
746 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
749 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
754 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
758 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
761 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
764 /* Add the server to global list */
765 server_id = silc_id_dup(server_id, SILC_ID_SERVER);
766 entry = silc_idlist_add_server(server->global_list, name, 0,
767 server_id, cmd->sock->user_data,
770 silc_free(server_id);
773 entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
777 /* Get the info string */
778 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
782 entry->server_info = tmp ? strdup(tmp) : NULL;
785 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
787 silc_server_command_reply_free(cmd);
790 /* Received reply fro MOTD command. */
792 SILC_SERVER_CMD_REPLY_FUNC(motd)
794 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
795 SilcServer server = cmd->server;
796 SilcStatus status, error;
797 SilcServerEntry entry = NULL;
798 SilcServerID *server_id;
802 COMMAND_CHECK_STATUS;
805 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
808 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
812 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
815 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
822 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
829 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
831 silc_server_command_reply_free(cmd);
837 /* Received reply for forwarded JOIN command. Router has created or joined
838 the client to the channel. We save some channel information locally
841 SILC_SERVER_CMD_REPLY_FUNC(join)
843 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
844 SilcServer server = cmd->server;
845 SilcIDCacheEntry cache = NULL;
846 SilcStatus status, error;
848 SilcClientID *client_id = NULL;
849 SilcChannelEntry entry;
850 SilcHmac hmac = NULL;
851 SilcUInt32 id_len, len, list_count;
852 unsigned char *id_string;
853 char *channel_name, *tmp;
854 SilcUInt32 mode, created;
855 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
856 SilcPublicKey founder_key = NULL;
858 COMMAND_CHECK_STATUS;
860 /* Get channel name */
861 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
866 id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
871 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
874 client_id = silc_id_payload_parse_id(tmp, len, NULL);
879 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
882 SILC_GET32_MSB(mode, tmp);
884 /* Get created boolean value */
885 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
888 SILC_GET32_MSB(created, tmp);
889 if (created != 0 && created != 1)
892 /* Get channel key */
893 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
895 keyp = silc_buffer_alloc(len);
896 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
897 silc_buffer_put(keyp, tmp, len);
900 /* Parse the Channel ID */
901 id = silc_id_payload_parse_id(id_string, id_len, NULL);
906 tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
908 if (!silc_hmac_alloc(tmp, NULL, &hmac))
912 /* Get the list count */
913 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
916 SILC_GET32_MSB(list_count, tmp);
918 /* Get Client ID list */
919 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
923 client_id_list = silc_buffer_alloc(len);
924 silc_buffer_pull_tail(client_id_list, len);
925 silc_buffer_put(client_id_list, tmp, len);
927 /* Get client mode list */
928 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
932 client_mode_list = silc_buffer_alloc(len);
933 silc_buffer_pull_tail(client_mode_list, len);
934 silc_buffer_put(client_mode_list, tmp, len);
936 /* Get founder key */
937 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
939 silc_pkcs_public_key_decode(tmp, len, &founder_key);
941 /* See whether we already have the channel. */
942 entry = silc_idlist_find_channel_by_name(server->local_list,
943 channel_name, &cache);
945 /* Add new channel */
947 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
948 (created == 0 ? "existing" : "created"), channel_name,
949 silc_id_render(id, SILC_ID_CHANNEL)));
951 /* If the channel is found from global list we must move it to the
953 entry = silc_idlist_find_channel_by_name(server->global_list,
954 channel_name, &cache);
956 silc_idlist_del_channel(server->global_list, entry);
958 /* Add the channel to our local list. */
959 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
960 SILC_CHANNEL_MODE_NONE, id,
961 server->router, NULL, hmac, 0);
966 server->stat.my_channels++;
967 server->stat.channels++;
969 /* The entry exists. */
971 /* If ID has changed, then update it to the cache too. */
972 if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
973 silc_idlist_replace_channel_id(server->local_list, entry->id, id);
975 entry->disabled = FALSE;
977 /* Remove the founder auth data if the mode is not set but we have
979 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
980 silc_pkcs_public_key_free(entry->founder_key);
981 entry->founder_key = NULL;
986 if (entry->founder_key)
987 silc_pkcs_public_key_free(entry->founder_key);
988 entry->founder_key = founder_key;
992 if (entry->hmac_name && hmac) {
993 silc_free(entry->hmac_name);
994 entry->hmac_name = strdup(silc_hmac_get_name(hmac));
997 /* Get the ban list */
998 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
1000 silc_free(entry->ban_list);
1001 entry->ban_list = silc_memdup(tmp, len);
1004 /* Get the invite list */
1005 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
1007 silc_free(entry->invite_list);
1008 entry->invite_list = silc_memdup(tmp, len);
1012 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
1014 silc_free(entry->topic);
1015 entry->topic = strdup(tmp);
1018 /* If channel was not created we know there is global users on the
1020 entry->global_users = (created == 0 ? TRUE : FALSE);
1022 /* If channel was just created the mask must be zero */
1023 if (!entry->global_users && mode) {
1024 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
1025 "new channel, forcing it to zero", cmd->sock->hostname));
1029 /* Save channel mode */
1032 /* Save channel key */
1034 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
1035 silc_server_save_channel_key(server, keyp, entry);
1036 silc_buffer_free(keyp);
1039 /* Save the users to the channel */
1040 silc_server_save_users_on_channel(server, cmd->sock, entry,
1041 client_id, client_id_list,
1042 client_mode_list, list_count);
1043 entry->users_resolved = TRUE;
1046 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1048 silc_free(client_id);
1049 silc_server_command_reply_free(cmd);
1051 silc_pkcs_public_key_free(founder_key);
1053 silc_buffer_free(client_id_list);
1054 if (client_mode_list)
1055 silc_buffer_free(client_mode_list);
1058 /* Received reply to STATS command. */
1060 SILC_SERVER_CMD_REPLY_FUNC(stats)
1062 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1063 SilcServer server = cmd->server;
1064 SilcStatus status, error;
1067 SilcBufferStruct buf;
1069 COMMAND_CHECK_STATUS;
1071 /* Get statistics structure */
1072 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1073 if (server->server_type == SILC_SERVER && tmp) {
1074 silc_buffer_set(&buf, tmp, tmp_len);
1075 silc_buffer_unformat(&buf,
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(NULL),
1081 SILC_STR_UI_INT(NULL),
1082 SILC_STR_UI_INT(&server->stat.cell_clients),
1083 SILC_STR_UI_INT(&server->stat.cell_channels),
1084 SILC_STR_UI_INT(&server->stat.cell_servers),
1085 SILC_STR_UI_INT(&server->stat.clients),
1086 SILC_STR_UI_INT(&server->stat.channels),
1087 SILC_STR_UI_INT(&server->stat.servers),
1088 SILC_STR_UI_INT(&server->stat.routers),
1089 SILC_STR_UI_INT(&server->stat.server_ops),
1090 SILC_STR_UI_INT(&server->stat.router_ops),
1095 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
1097 silc_server_command_reply_free(cmd);
1100 SILC_SERVER_CMD_REPLY_FUNC(users)
1102 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1103 SilcServer server = cmd->server;
1104 SilcStatus status, error;
1105 SilcChannelEntry channel;
1106 SilcChannelID *channel_id = NULL;
1107 SilcBuffer client_id_list;
1108 SilcBuffer client_mode_list;
1111 SilcUInt32 list_count;
1113 COMMAND_CHECK_STATUS;
1115 /* Get channel ID */
1116 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1119 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1123 /* Get channel entry */
1124 channel = silc_idlist_find_channel_by_id(server->local_list,
1127 channel = silc_idlist_find_channel_by_id(server->global_list,
1132 if (server->server_type != SILC_SERVER)
1135 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1136 silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
1137 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1138 1, 5, idp->data, idp->len);
1139 silc_buffer_free(idp);
1141 /* Register pending command callback. After we've received the channel
1142 information we will reprocess this command reply by re-calling this
1143 USERS command reply callback. */
1144 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1146 silc_server_command_reply_users, cmd);
1151 /* Get the list count */
1152 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1155 SILC_GET32_MSB(list_count, tmp);
1157 /* Get Client ID list */
1158 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1162 client_id_list = silc_buffer_alloc(tmp_len);
1163 silc_buffer_pull_tail(client_id_list, tmp_len);
1164 silc_buffer_put(client_id_list, tmp, tmp_len);
1166 /* Get client mode list */
1167 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1171 client_mode_list = silc_buffer_alloc(tmp_len);
1172 silc_buffer_pull_tail(client_mode_list, tmp_len);
1173 silc_buffer_put(client_mode_list, tmp, tmp_len);
1175 /* Save the users to the channel */
1176 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1177 client_id_list, client_mode_list,
1180 channel->global_users = silc_server_channel_has_global(channel);
1181 channel->users_resolved = TRUE;
1183 silc_buffer_free(client_id_list);
1184 silc_buffer_free(client_mode_list);
1187 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1188 silc_free(channel_id);
1190 silc_server_command_reply_free(cmd);
1193 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1195 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1196 SilcServer server = cmd->server;
1197 SilcStatus status, error;
1198 SilcClientEntry client = NULL;
1199 SilcServerEntry server_entry = NULL;
1200 SilcClientID *client_id = NULL;
1201 SilcServerID *server_id = NULL;
1203 unsigned char *tmp, *pk;
1206 SilcIDPayload idp = NULL;
1208 SilcPublicKey public_key = NULL;
1210 COMMAND_CHECK_STATUS;
1212 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1215 idp = silc_id_payload_parse(tmp, len);
1219 /* Get the public key payload */
1220 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1224 /* Decode the public key */
1226 SILC_GET16_MSB(pk_len, tmp);
1227 SILC_GET16_MSB(type, tmp + 2);
1230 if (type != SILC_SKE_PK_TYPE_SILC)
1233 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1236 id_type = silc_id_payload_get_type(idp);
1237 if (id_type == SILC_ID_CLIENT) {
1238 client_id = silc_id_payload_get_id(idp);
1240 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1243 client = silc_idlist_find_client_by_id(server->global_list,
1244 client_id, TRUE, NULL);
1249 client->data.public_key = public_key;
1251 } else if (id_type == SILC_ID_SERVER) {
1252 server_id = silc_id_payload_get_id(idp);
1254 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1256 if (!server_entry) {
1257 server_entry = silc_idlist_find_server_by_id(server->global_list,
1258 server_id, TRUE, NULL);
1263 server_entry->data.public_key = public_key;
1270 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1272 silc_id_payload_free(idp);
1273 silc_free(client_id);
1274 silc_free(server_id);
1276 silc_pkcs_public_key_free(public_key);
1278 silc_server_command_reply_free(cmd);
1281 SILC_SERVER_CMD_REPLY_FUNC(list)
1283 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1284 SilcServer server = cmd->server;
1285 SilcStatus status, error;
1286 SilcChannelID *channel_id = NULL;
1287 SilcChannelEntry channel;
1288 SilcIDCacheEntry cache;
1290 unsigned char *tmp, *name, *topic;
1291 SilcUInt32 usercount = 0;
1292 bool global_list = FALSE;
1294 COMMAND_CHECK_STATUS;
1296 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1297 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1301 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1302 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1303 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1305 SILC_GET32_MSB(usercount, tmp);
1307 /* Add the channel entry if we do not have it already */
1308 channel = silc_idlist_find_channel_by_name(server->local_list,
1311 channel = silc_idlist_find_channel_by_name(server->global_list,
1316 /* If router did not find such channel in its lists then this must
1317 be bogus channel or some router in the net is buggy. */
1318 if (server->server_type != SILC_SERVER)
1321 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1322 SILC_CHANNEL_MODE_NONE, channel_id,
1323 server->router, NULL, NULL,
1329 /* Found, update expiry */
1330 if (global_list && server->server_type == SILC_SERVER)
1331 cache->expire = time(NULL) + 60;
1334 channel->user_count = usercount;
1337 silc_free(channel->topic);
1338 channel->topic = strdup(topic);
1341 /* Pending callbacks are not executed if this was an list entry */
1342 if (status != SILC_STATUS_OK &&
1343 status != SILC_STATUS_LIST_END) {
1344 silc_server_command_reply_free(cmd);
1348 /* Now purge all old entries from the global list, otherwise we'll might
1349 have non-existent entries for long periods of time in the cache. */
1350 silc_idcache_purge(server->global_list->channels);
1353 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1354 silc_free(channel_id);
1356 silc_server_command_reply_free(cmd);
1359 SILC_SERVER_CMD_REPLY_FUNC(watch)
1361 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1362 SilcStatus status, error;
1364 COMMAND_CHECK_STATUS;
1367 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1369 silc_server_command_reply_free(cmd);