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),
55 SILC_SERVER_CMD_REPLY(watch, WATCH),
60 /* Process received command reply. */
62 void silc_server_command_reply_process(SilcServer server,
63 SilcSocketConnection sock,
66 SilcServerCommandReply *cmd;
67 SilcServerCommandReplyContext ctx;
68 SilcCommandPayload payload;
71 SILC_LOG_DEBUG(("Start"));
73 /* Get command reply payload from packet */
74 payload = silc_command_payload_parse(buffer->data, buffer->len);
76 /* Silently ignore bad reply packet */
77 SILC_LOG_DEBUG(("Bad command reply packet"));
81 /* Allocate command reply context. This must be free'd by the
82 command reply routine receiving it. */
83 ctx = silc_calloc(1, sizeof(*ctx));
85 ctx->sock = silc_socket_dup(sock);
86 ctx->payload = payload;
87 ctx->args = silc_command_get_args(ctx->payload);
88 ctx->ident = silc_command_get_ident(ctx->payload);
89 command = silc_command_get(ctx->payload);
91 /* Client is not allowed to send reply to all commands */
92 if (sock->type == SILC_SOCKET_TYPE_CLIENT &&
93 command != SILC_COMMAND_WHOIS) {
94 silc_server_command_reply_free(ctx);
98 /* Check for pending commands and mark to be exeucted */
100 silc_server_command_pending_check(server, command,
101 ctx->ident, &ctx->callbacks_count);
103 /* Execute command reply */
104 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
105 if (cmd->cmd == command)
108 if (cmd == NULL || !cmd->cb) {
109 silc_server_command_reply_free(ctx);
116 /* Free command reply context and its internals. */
118 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
121 silc_command_payload_free(cmd->payload);
123 silc_socket_free(cmd->sock); /* Decrease the reference counter */
124 silc_free(cmd->callbacks);
130 silc_server_command_process_error(SilcServerCommandReplyContext cmd,
133 SilcServer server = cmd->server;
135 /* If we received notify for invalid ID we'll remove the ID if we
137 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
138 cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
139 SilcClientEntry client;
141 unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
143 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
145 SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
146 "the entry from cache"));
147 client = silc_idlist_find_client_by_id(server->global_list,
148 client_id, FALSE, NULL);
150 silc_server_remove_from_channels(server, NULL, client, TRUE,
152 silc_idlist_del_data(client);
153 silc_idlist_del_client(server->global_list, client);
155 silc_free(client_id);
161 /* Caches the received WHOIS information. */
164 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
166 SilcServer server = cmd->server;
167 unsigned char *tmp, *id_data, *umodes;
168 char *nickname, *username, *realname, *servername = NULL;
169 unsigned char *fingerprint;
170 SilcClientID *client_id;
171 SilcClientEntry client;
172 SilcIDCacheEntry cache = NULL;
175 SilcUInt32 mode = 0, len, len2, id_len, flen;
177 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
178 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
179 username = silc_argument_get_arg_type(cmd->args, 4, &len);
180 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
181 if (!id_data || !nickname || !username || !realname)
184 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
186 SILC_GET32_MSB(mode, tmp);
188 client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
192 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);
194 /* Check if we have this client cached already. */
196 client = silc_idlist_find_client_by_id(server->local_list, client_id,
199 client = silc_idlist_find_client_by_id(server->global_list, client_id,
205 /* If router did not find such Client ID in its lists then this must
206 be bogus client or some router in the net is buggy. */
207 if (server->server_type != SILC_SERVER)
210 /* Take hostname out of nick string if it includes it. */
211 silc_parse_userfqdn(nickname, &nick, &servername);
213 /* We don't have that client anywhere, add it. The client is added
214 to global list since server didn't have it in the lists so it must be
216 client = silc_idlist_add_client(server->global_list, nick,
218 strdup(realname), client_id,
219 cmd->sock->user_data, NULL, 0);
221 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
225 client->data.status |=
226 (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
227 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
229 client->servername = servername;
231 /* We have the client already, update the data */
233 SILC_LOG_DEBUG(("Updating client data"));
235 /* Take hostname out of nick string if it includes it. */
236 silc_parse_userfqdn(nickname, &nick, &servername);
238 /* Remove the old cache entry */
239 silc_idcache_del_by_context(global ? server->global_list->clients :
240 server->local_list->clients, client);
242 silc_free(client->nickname);
243 silc_free(client->username);
244 silc_free(client->userinfo);
245 silc_free(client->servername);
247 client->nickname = nick;
248 client->username = strdup(username);
249 client->userinfo = strdup(realname);
250 client->servername = servername;
252 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
253 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
255 /* Create new cache entry */
256 silc_idcache_add(global ? server->global_list->clients :
257 server->local_list->clients, nick, client->id,
259 silc_free(client_id);
262 /* Save channel list if it was sent to us */
263 if (server->server_type == SILC_SERVER) {
264 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
265 umodes = silc_argument_get_arg_type(cmd->args, 10, &len2);
267 SilcBufferStruct channels_buf, umodes_buf;
268 silc_buffer_set(&channels_buf, tmp, len);
269 silc_buffer_set(&umodes_buf, umodes, len2);
270 silc_server_save_user_channels(server, cmd->sock, client, &channels_buf,
273 silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
276 /* If client is global and is not on any channel then add that we'll
277 expire the entry after a while. */
279 silc_idlist_find_client_by_id(server->global_list, client->id,
281 if (!silc_hash_table_count(client->channels))
282 cache->expire = time(NULL) + 300;
288 if (fingerprint && flen == sizeof(client->data.fingerprint))
289 memcpy(client->data.fingerprint, fingerprint, flen);
291 /* Take Requested Attributes if set. */
292 tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
294 silc_free(client->attrs);
295 client->attrs = silc_memdup(tmp, len);
296 client->attrs_len = len;
302 /* Handle requested attributes reply in WHOIS from client */
305 silc_server_command_reply_whois_save_client(SilcServerCommandReplyContext cmd)
309 SilcClientEntry client = cmd->sock->user_data;
311 /* Take Requested Attributes if set. */
312 tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
314 silc_free(client->attrs);
315 client->attrs = silc_memdup(tmp, len);
316 client->attrs_len = len;
319 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
324 /* Reiceved reply for WHOIS command. We sent the whois request to our
325 primary router, if we are normal server, and thus has now received reply
326 to the command. We will figure out what client originally sent us the
327 command and will send the reply to it. If we are router we will figure
328 out who server sent us the command and send reply to that one. */
330 SILC_SERVER_CMD_REPLY_FUNC(whois)
332 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
333 SilcStatus status, error;
335 COMMAND_CHECK_STATUS;
337 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) {
338 if (!silc_server_command_reply_whois_save(cmd))
341 if (!silc_server_command_reply_whois_save_client(cmd))
345 /* Pending callbacks are not executed if this was an list entry */
346 if (status != SILC_STATUS_OK &&
347 status != SILC_STATUS_LIST_END) {
348 silc_server_command_reply_free(cmd);
353 silc_server_command_process_error(cmd, error);
354 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
355 silc_server_command_reply_free(cmd);
359 silc_server_command_process_error(cmd, error);
360 silc_server_command_reply_free(cmd);
363 /* Caches the received WHOWAS information for a short period of time. */
366 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
368 SilcServer server = cmd->server;
369 SilcUInt32 len, id_len;
370 unsigned char *id_data;
371 char *nickname, *username, *realname, *servername = NULL;
372 SilcClientID *client_id;
373 SilcClientEntry client;
374 SilcIDCacheEntry cache = NULL;
378 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
379 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
380 username = silc_argument_get_arg_type(cmd->args, 4, &len);
381 if (!id_data || !nickname || !username)
384 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
386 client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
390 /* Check if we have this client cached already. */
392 client = silc_idlist_find_client_by_id(server->local_list, client_id,
395 client = silc_idlist_find_client_by_id(server->global_list,
396 client_id, FALSE, &cache);
401 /* If router did not find such Client ID in its lists then this must
402 be bogus client or some router in the net is buggy. */
403 if (server->server_type != SILC_SERVER)
406 /* Take hostname out of nick string if it includes it. */
407 silc_parse_userfqdn(nickname, &nick, &servername);
409 /* We don't have that client anywhere, add it. The client is added
410 to global list since server didn't have it in the lists so it must be
412 client = silc_idlist_add_client(server->global_list, nick,
413 strdup(username), strdup(realname),
414 silc_id_dup(client_id, SILC_ID_CLIENT),
415 cmd->sock->user_data, NULL,
416 SILC_ID_CACHE_EXPIRE_DEF);
418 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
422 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
423 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
424 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
425 client->servername = servername;
427 /* We have the client already, update the data */
429 /* Take hostname out of nick string if it includes it. */
430 silc_parse_userfqdn(nickname, &nick, &servername);
432 silc_free(client->nickname);
433 silc_free(client->username);
434 silc_free(client->servername);
436 client->nickname = nick;
437 client->username = strdup(username);
438 client->servername = servername;
439 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
440 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
442 /* Remove the old cache entry and create a new one */
443 silc_idcache_del_by_context(global ? server->global_list->clients :
444 server->local_list->clients, client);
445 silc_idcache_add(global ? server->global_list->clients :
446 server->local_list->clients, nick, client->id,
450 /* If client is global and is not on any channel then add that we'll
451 expire the entry after a while. */
453 silc_idlist_find_client_by_id(server->global_list, client->id,
455 if (!silc_hash_table_count(client->channels))
456 cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
461 silc_free(client_id);
466 /* Received reply for WHOWAS command. Cache the client information only for
467 a short period of time. */
469 SILC_SERVER_CMD_REPLY_FUNC(whowas)
471 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
472 SilcStatus status, error;
474 COMMAND_CHECK_STATUS;
476 if (!silc_server_command_reply_whowas_save(cmd))
479 /* Pending callbacks are not executed if this was an list entry */
480 if (status != SILC_STATUS_OK &&
481 status != SILC_STATUS_LIST_END) {
482 silc_server_command_reply_free(cmd);
487 silc_server_command_process_error(cmd, error);
488 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
489 silc_server_command_reply_free(cmd);
493 silc_server_command_process_error(cmd, error);
494 silc_server_command_reply_free(cmd);
497 /* Caches the received IDENTIFY information. */
500 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
502 SilcServer server = cmd->server;
503 SilcUInt32 len, id_len;
504 unsigned char *id_data;
506 SilcClientID *client_id = NULL;
507 SilcServerID *server_id = NULL;
508 SilcChannelID *channel_id = NULL;
509 SilcClientEntry client;
510 SilcServerEntry server_entry;
511 SilcChannelEntry channel;
514 SilcIDPayload idp = NULL;
518 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
521 idp = silc_id_payload_parse(id_data, id_len);
525 name = silc_argument_get_arg_type(cmd->args, 3, &len);
526 info = silc_argument_get_arg_type(cmd->args, 4, &len);
528 id_type = silc_id_payload_get_type(idp);
532 client_id = silc_id_payload_get_id(idp);
536 SILC_LOG_DEBUG(("Received client information"));
538 client = silc_idlist_find_client_by_id(server->local_list,
539 client_id, FALSE, NULL);
541 client = silc_idlist_find_client_by_id(server->global_list, client_id,
546 /* If router did not find such Client ID in its lists then this must
547 be bogus client or some router in the net is buggy. */
548 if (server->server_type != SILC_SERVER)
553 silc_parse_userfqdn(name, &nick, NULL);
555 /* We don't have that client anywhere, add it. The client is added
556 to global list since server didn't have it in the lists so it must be
558 client = silc_idlist_add_client(server->global_list, nick,
559 info ? strdup(info) : NULL, NULL,
560 client_id, cmd->sock->user_data,
561 NULL, time(NULL) + 300);
563 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
566 client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
567 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
568 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
570 /* We have the client already, update the data */
572 SILC_LOG_DEBUG(("Updating client data"));
576 silc_parse_userfqdn(name, &nick, NULL);
578 /* Remove the old cache entry */
579 silc_idcache_del_by_context(global ? server->global_list->clients :
580 server->local_list->clients, client);
582 silc_free(client->nickname);
583 client->nickname = nick;
587 silc_free(client->username);
588 client->username = strdup(info);
591 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
592 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
595 /* Add new cache entry */
596 silc_idcache_add(global ? server->global_list->clients :
597 server->local_list->clients, nick, client->id,
598 client, expire, NULL);
601 /* If client is global and is not on any channel then add that we'll
602 expire the entry after a while. */
603 if (global && server->server_type == SILC_SERVER) {
604 SilcIDCacheEntry cache = NULL;
605 silc_idlist_find_client_by_id(server->global_list, client->id,
607 if (!silc_hash_table_count(client->channels))
608 cache->expire = time(NULL) + 300;
613 silc_free(client_id);
622 server_id = silc_id_payload_get_id(idp);
626 SILC_LOG_DEBUG(("Received server information"));
628 server_entry = silc_idlist_find_server_by_id(server->local_list,
629 server_id, FALSE, NULL);
631 server_entry = silc_idlist_find_server_by_id(server->global_list,
632 server_id, FALSE, NULL);
634 /* If router did not find such Server ID in its lists then this must
635 be bogus server or some router in the net is buggy. */
636 if (server->server_type != SILC_SERVER)
639 /* We don't have that server anywhere, add it. */
640 server_entry = silc_idlist_add_server(server->global_list,
642 server_id, server->router,
643 SILC_PRIMARY_ROUTE(server));
645 silc_free(server_id);
648 server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
649 server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
650 server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
654 silc_free(server_id);
657 case SILC_ID_CHANNEL:
661 channel_id = silc_id_payload_get_id(idp);
665 SILC_LOG_DEBUG(("Received channel information"));
667 channel = silc_idlist_find_channel_by_name(server->local_list,
670 channel = silc_idlist_find_channel_by_name(server->global_list,
673 /* If router did not find such Channel ID in its lists then this must
674 be bogus channel or some router in the net is buggy. */
675 if (server->server_type != SILC_SERVER)
678 /* We don't have that channel anywhere, add it. */
679 channel = silc_idlist_add_channel(server->global_list, strdup(name),
680 SILC_CHANNEL_MODE_NONE, channel_id,
681 server->router, NULL, NULL, 0);
683 silc_free(channel_id);
689 silc_free(channel_id);
693 silc_id_payload_free(idp);
697 silc_id_payload_free(idp);
701 /* Received reply for forwarded IDENTIFY command. We have received the
702 requested identify information now and we will cache it. After this we
703 will call the pending command so that the requestee gets the information
706 SILC_SERVER_CMD_REPLY_FUNC(identify)
708 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
709 SilcStatus status, error;
711 COMMAND_CHECK_STATUS;
713 if (!silc_server_command_reply_identify_save(cmd))
716 /* Pending callbacks are not executed if this was an list entry */
717 if (status != SILC_STATUS_OK &&
718 status != SILC_STATUS_LIST_END) {
719 silc_server_command_reply_free(cmd);
724 silc_server_command_process_error(cmd, error);
725 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
726 silc_server_command_reply_free(cmd);
730 silc_server_command_process_error(cmd, error);
731 silc_server_command_reply_free(cmd);
734 /* Received reply fro INFO command. Cache the server and its information */
736 SILC_SERVER_CMD_REPLY_FUNC(info)
738 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
739 SilcServer server = cmd->server;
740 SilcStatus status, error;
741 SilcServerEntry entry;
742 SilcServerID *server_id;
744 unsigned char *tmp, *name;
746 COMMAND_CHECK_STATUS;
749 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
752 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
757 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
761 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
764 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
767 /* Add the server to global list */
768 server_id = silc_id_dup(server_id, SILC_ID_SERVER);
769 entry = silc_idlist_add_server(server->global_list, name, 0,
770 server_id, cmd->sock->user_data,
773 silc_free(server_id);
776 entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
780 /* Get the info string */
781 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
785 entry->server_info = tmp ? strdup(tmp) : NULL;
788 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
790 silc_server_command_reply_free(cmd);
793 /* Received reply fro MOTD command. */
795 SILC_SERVER_CMD_REPLY_FUNC(motd)
797 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
798 SilcServer server = cmd->server;
799 SilcStatus status, error;
800 SilcServerEntry entry = NULL;
801 SilcServerID *server_id;
805 COMMAND_CHECK_STATUS;
808 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
811 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
815 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
818 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
825 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
832 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
834 silc_server_command_reply_free(cmd);
840 /* Received reply for forwarded JOIN command. Router has created or joined
841 the client to the channel. We save some channel information locally
844 SILC_SERVER_CMD_REPLY_FUNC(join)
846 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
847 SilcServer server = cmd->server;
848 SilcIDCacheEntry cache = NULL;
849 SilcStatus status, error;
851 SilcClientID *client_id = NULL;
852 SilcChannelEntry entry;
853 SilcHmac hmac = NULL;
854 SilcUInt32 id_len, len, list_count;
855 unsigned char *id_string;
856 char *channel_name, *tmp;
857 SilcUInt32 mode, created;
858 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
859 SilcPublicKey founder_key = NULL;
861 COMMAND_CHECK_STATUS;
863 /* Get channel name */
864 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
869 id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
874 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
877 client_id = silc_id_payload_parse_id(tmp, len, NULL);
882 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
885 SILC_GET32_MSB(mode, tmp);
887 /* Get created boolean value */
888 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
891 SILC_GET32_MSB(created, tmp);
892 if (created != 0 && created != 1)
895 /* Get channel key */
896 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
898 keyp = silc_buffer_alloc(len);
899 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
900 silc_buffer_put(keyp, tmp, len);
903 /* Parse the Channel ID */
904 id = silc_id_payload_parse_id(id_string, id_len, NULL);
909 tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
911 if (!silc_hmac_alloc(tmp, NULL, &hmac))
915 /* Get the list count */
916 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
919 SILC_GET32_MSB(list_count, tmp);
921 /* Get Client ID list */
922 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
926 client_id_list = silc_buffer_alloc(len);
927 silc_buffer_pull_tail(client_id_list, len);
928 silc_buffer_put(client_id_list, tmp, len);
930 /* Get client mode list */
931 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
935 client_mode_list = silc_buffer_alloc(len);
936 silc_buffer_pull_tail(client_mode_list, len);
937 silc_buffer_put(client_mode_list, tmp, len);
939 /* Get founder key */
940 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
942 silc_pkcs_public_key_payload_decode(tmp, len, &founder_key);
944 /* See whether we already have the channel. */
945 entry = silc_idlist_find_channel_by_name(server->local_list,
946 channel_name, &cache);
948 /* Add new channel */
950 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
951 (created == 0 ? "existing" : "created"), channel_name,
952 silc_id_render(id, SILC_ID_CHANNEL)));
954 /* If the channel is found from global list we must move it to the
956 entry = silc_idlist_find_channel_by_name(server->global_list,
957 channel_name, &cache);
959 silc_idlist_del_channel(server->global_list, entry);
961 /* Add the channel to our local list. */
962 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
963 SILC_CHANNEL_MODE_NONE, id,
964 server->router, NULL, hmac, 0);
970 server->stat.my_channels++;
971 server->stat.channels++;
973 /* The entry exists. */
975 /* If ID has changed, then update it to the cache too. */
976 if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
977 silc_idlist_replace_channel_id(server->local_list, entry->id, id);
979 entry->disabled = FALSE;
981 /* Remove the founder auth data if the mode is not set but we have
983 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
984 silc_pkcs_public_key_free(entry->founder_key);
985 entry->founder_key = NULL;
990 if (entry->founder_key)
991 silc_pkcs_public_key_free(entry->founder_key);
992 entry->founder_key = founder_key;
996 if (entry->hmac_name && (hmac || (!hmac && entry->hmac))) {
997 silc_free(entry->hmac_name);
998 entry->hmac_name = strdup(silc_hmac_get_name(hmac ? hmac : entry->hmac));
1001 /* Get the ban list */
1002 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
1003 if (tmp && len > 2) {
1004 SilcArgumentPayload iargs;
1006 SILC_GET16_MSB(iargc, tmp);
1007 iargs = silc_argument_payload_parse(tmp + 2, len - 2, iargc);
1009 /* Delete old ban list */
1010 if (entry->ban_list)
1011 silc_hash_table_free(entry->ban_list);
1013 silc_hash_table_alloc(0, silc_hash_ptr,
1015 silc_server_inviteban_destruct, entry, TRUE);
1017 /* Add new ban list */
1018 silc_server_inviteban_process(server, entry->ban_list, 0, iargs);
1019 silc_argument_payload_free(iargs);
1023 /* Get the invite list */
1024 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
1025 if (tmp && len > 2) {
1026 SilcArgumentPayload iargs;
1028 SILC_GET16_MSB(iargc, tmp);
1029 iargs = silc_argument_payload_parse(tmp + 2, len - 2, iargc);
1031 /* Delete old invite list */
1032 if (entry->invite_list)
1033 silc_hash_table_free(entry->invite_list);
1034 entry->invite_list =
1035 silc_hash_table_alloc(0, silc_hash_ptr,
1037 silc_server_inviteban_destruct, entry, TRUE);
1039 /* Add new invite list */
1040 silc_server_inviteban_process(server, entry->invite_list, 0, iargs);
1041 silc_argument_payload_free(iargs);
1046 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
1048 silc_free(entry->topic);
1049 entry->topic = strdup(tmp);
1052 /* If channel was not created we know there is global users on the
1054 entry->global_users = (created == 0 ? TRUE : FALSE);
1056 /* If channel was just created the mask must be zero */
1057 if (!entry->global_users && mode) {
1058 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
1059 "new channel, forcing it to zero", cmd->sock->hostname));
1063 /* Save channel mode */
1066 /* Save channel key */
1068 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
1069 silc_server_save_channel_key(server, keyp, entry);
1070 silc_buffer_free(keyp);
1073 /* Save the users to the channel */
1074 silc_server_save_users_on_channel(server, cmd->sock, entry,
1075 client_id, client_id_list,
1076 client_mode_list, list_count);
1077 entry->users_resolved = TRUE;
1080 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1083 silc_hmac_free(hmac);
1084 silc_free(client_id);
1085 silc_server_command_reply_free(cmd);
1087 silc_pkcs_public_key_free(founder_key);
1089 silc_buffer_free(client_id_list);
1090 if (client_mode_list)
1091 silc_buffer_free(client_mode_list);
1094 /* Received reply to STATS command. */
1096 SILC_SERVER_CMD_REPLY_FUNC(stats)
1098 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1099 SilcServer server = cmd->server;
1100 SilcStatus status, error;
1103 SilcBufferStruct buf;
1105 COMMAND_CHECK_STATUS;
1107 /* Get statistics structure */
1108 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1109 if (server->server_type != SILC_ROUTER && tmp) {
1110 silc_buffer_set(&buf, tmp, tmp_len);
1111 silc_buffer_unformat(&buf,
1112 SILC_STR_UI_INT(NULL),
1113 SILC_STR_UI_INT(NULL),
1114 SILC_STR_UI_INT(NULL),
1115 SILC_STR_UI_INT(NULL),
1116 SILC_STR_UI_INT(NULL),
1117 SILC_STR_UI_INT(NULL),
1118 SILC_STR_UI_INT(&server->stat.cell_clients),
1119 SILC_STR_UI_INT(&server->stat.cell_channels),
1120 SILC_STR_UI_INT(&server->stat.cell_servers),
1121 SILC_STR_UI_INT(&server->stat.clients),
1122 SILC_STR_UI_INT(&server->stat.channels),
1123 SILC_STR_UI_INT(&server->stat.servers),
1124 SILC_STR_UI_INT(&server->stat.routers),
1125 SILC_STR_UI_INT(&server->stat.server_ops),
1126 SILC_STR_UI_INT(&server->stat.router_ops),
1131 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
1133 silc_server_command_reply_free(cmd);
1136 SILC_SERVER_CMD_REPLY_FUNC(users)
1138 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1139 SilcServer server = cmd->server;
1140 SilcStatus status, error;
1141 SilcChannelEntry channel;
1142 SilcChannelID *channel_id = NULL;
1143 SilcBuffer client_id_list;
1144 SilcBuffer client_mode_list;
1147 SilcUInt32 list_count;
1149 COMMAND_CHECK_STATUS;
1151 /* Get channel ID */
1152 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1155 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1159 /* Get channel entry */
1160 channel = silc_idlist_find_channel_by_id(server->local_list,
1163 channel = silc_idlist_find_channel_by_id(server->global_list,
1168 if (server->server_type != SILC_SERVER)
1171 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1172 silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
1173 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1174 1, 5, idp->data, idp->len);
1175 silc_buffer_free(idp);
1177 /* Register pending command callback. After we've received the channel
1178 information we will reprocess this command reply by re-calling this
1179 USERS command reply callback. */
1180 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1182 silc_server_command_reply_users, cmd);
1187 /* Get the list count */
1188 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1191 SILC_GET32_MSB(list_count, tmp);
1193 /* Get Client ID list */
1194 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1198 client_id_list = silc_buffer_alloc(tmp_len);
1199 silc_buffer_pull_tail(client_id_list, tmp_len);
1200 silc_buffer_put(client_id_list, tmp, tmp_len);
1202 /* Get client mode list */
1203 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1207 client_mode_list = silc_buffer_alloc(tmp_len);
1208 silc_buffer_pull_tail(client_mode_list, tmp_len);
1209 silc_buffer_put(client_mode_list, tmp, tmp_len);
1211 /* Save the users to the channel */
1212 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1213 client_id_list, client_mode_list,
1216 channel->global_users = silc_server_channel_has_global(channel);
1217 channel->users_resolved = TRUE;
1219 silc_buffer_free(client_id_list);
1220 silc_buffer_free(client_mode_list);
1223 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1224 silc_free(channel_id);
1226 silc_server_command_reply_free(cmd);
1229 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1231 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1232 SilcServer server = cmd->server;
1233 SilcStatus status, error;
1234 SilcClientEntry client = NULL;
1235 SilcServerEntry server_entry = NULL;
1236 SilcClientID *client_id = NULL;
1237 SilcServerID *server_id = NULL;
1240 SilcIDPayload idp = NULL;
1242 SilcPublicKey public_key = NULL;
1244 COMMAND_CHECK_STATUS;
1246 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1249 idp = silc_id_payload_parse(tmp, len);
1253 /* Get the public key payload */
1254 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1258 /* Decode the public key payload */
1259 if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
1262 id_type = silc_id_payload_get_type(idp);
1263 if (id_type == SILC_ID_CLIENT) {
1264 client_id = silc_id_payload_get_id(idp);
1266 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1269 client = silc_idlist_find_client_by_id(server->global_list,
1270 client_id, TRUE, NULL);
1275 client->data.public_key = public_key;
1277 } else if (id_type == SILC_ID_SERVER) {
1278 server_id = silc_id_payload_get_id(idp);
1280 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1282 if (!server_entry) {
1283 server_entry = silc_idlist_find_server_by_id(server->global_list,
1284 server_id, TRUE, NULL);
1289 server_entry->data.public_key = public_key;
1296 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1298 silc_id_payload_free(idp);
1299 silc_free(client_id);
1300 silc_free(server_id);
1302 silc_pkcs_public_key_free(public_key);
1304 silc_server_command_reply_free(cmd);
1307 SILC_SERVER_CMD_REPLY_FUNC(list)
1309 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1310 SilcServer server = cmd->server;
1311 SilcStatus status, error;
1312 SilcChannelID *channel_id = NULL;
1313 SilcChannelEntry channel;
1314 SilcIDCacheEntry cache;
1316 unsigned char *tmp, *name, *topic;
1317 SilcUInt32 usercount = 0;
1318 bool global_list = FALSE;
1320 COMMAND_CHECK_STATUS;
1322 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1323 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1327 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1328 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1329 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1331 SILC_GET32_MSB(usercount, tmp);
1333 /* Add the channel entry if we do not have it already */
1334 channel = silc_idlist_find_channel_by_name(server->local_list,
1337 channel = silc_idlist_find_channel_by_name(server->global_list,
1342 /* If router did not find such channel in its lists then this must
1343 be bogus channel or some router in the net is buggy. */
1344 if (server->server_type != SILC_SERVER)
1347 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1348 SILC_CHANNEL_MODE_NONE, channel_id,
1349 server->router, NULL, NULL,
1355 /* Found, update expiry */
1356 if (global_list && server->server_type == SILC_SERVER)
1357 cache->expire = time(NULL) + 60;
1360 channel->user_count = usercount;
1363 silc_free(channel->topic);
1364 channel->topic = strdup(topic);
1367 /* Pending callbacks are not executed if this was an list entry */
1368 if (status != SILC_STATUS_OK &&
1369 status != SILC_STATUS_LIST_END) {
1370 silc_server_command_reply_free(cmd);
1374 /* Now purge all old entries from the global list, otherwise we'll might
1375 have non-existent entries for long periods of time in the cache. */
1376 silc_idcache_purge(server->global_list->channels);
1379 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1380 silc_free(channel_id);
1382 silc_server_command_reply_free(cmd);
1385 SILC_SERVER_CMD_REPLY_FUNC(watch)
1387 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1388 SilcStatus status, error;
1390 COMMAND_CHECK_STATUS;
1393 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1395 silc_server_command_reply_free(cmd);