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);
89 /* Check for pending commands and mark to be exeucted */
91 silc_server_command_pending_check(server, silc_command_get(ctx->payload),
92 ctx->ident, &ctx->callbacks_count);
94 /* Execute command reply */
95 command = silc_command_get(ctx->payload);
96 for (cmd = silc_command_reply_list; cmd->cb; cmd++)
97 if (cmd->cmd == command)
100 if (cmd == NULL || !cmd->cb) {
101 silc_server_command_reply_free(ctx);
108 /* Free command reply context and its internals. */
110 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
113 silc_command_payload_free(cmd->payload);
115 silc_socket_free(cmd->sock); /* Decrease the reference counter */
116 silc_free(cmd->callbacks);
122 silc_server_command_process_error(SilcServerCommandReplyContext cmd,
125 SilcServer server = cmd->server;
127 /* If we received notify for invalid ID we'll remove the ID if we
129 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
130 cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
131 SilcClientEntry client;
133 unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
135 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
137 SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
138 "the entry from cache"));
139 client = silc_idlist_find_client_by_id(server->global_list,
140 client_id, FALSE, NULL);
142 silc_server_remove_from_channels(server, NULL, client, TRUE,
144 silc_idlist_del_data(client);
145 silc_idlist_del_client(server->global_list, client);
147 silc_free(client_id);
153 /* Caches the received WHOIS information. */
156 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
158 SilcServer server = cmd->server;
159 unsigned char *tmp, *id_data, *umodes;
160 char *nickname, *username, *realname, *servername = NULL;
161 unsigned char *fingerprint;
162 SilcClientID *client_id;
163 SilcClientEntry client;
164 SilcIDCacheEntry cache = NULL;
167 SilcUInt32 mode = 0, len, len2, id_len, flen;
169 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
170 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
171 username = silc_argument_get_arg_type(cmd->args, 4, &len);
172 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
173 if (!id_data || !nickname || !username || !realname)
176 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
178 SILC_GET32_MSB(mode, tmp);
180 client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
184 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);
186 /* Check if we have this client cached already. */
188 client = silc_idlist_find_client_by_id(server->local_list, client_id,
191 client = silc_idlist_find_client_by_id(server->global_list, client_id,
197 /* If router did not find such Client ID in its lists then this must
198 be bogus client or some router in the net is buggy. */
199 if (server->server_type != SILC_SERVER)
202 /* Take hostname out of nick string if it includes it. */
203 silc_parse_userfqdn(nickname, &nick, &servername);
205 /* We don't have that client anywhere, add it. The client is added
206 to global list since server didn't have it in the lists so it must be
208 client = silc_idlist_add_client(server->global_list, nick,
210 strdup(realname), client_id,
211 cmd->sock->user_data, NULL, 0);
213 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
217 client->data.status |=
218 (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
219 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
221 client->servername = servername;
223 /* We have the client already, update the data */
225 SILC_LOG_DEBUG(("Updating client data"));
227 /* Take hostname out of nick string if it includes it. */
228 silc_parse_userfqdn(nickname, &nick, &servername);
230 /* Remove the old cache entry */
231 silc_idcache_del_by_context(global ? server->global_list->clients :
232 server->local_list->clients, client);
234 silc_free(client->nickname);
235 silc_free(client->username);
236 silc_free(client->userinfo);
237 silc_free(client->servername);
239 client->nickname = nick;
240 client->username = strdup(username);
241 client->userinfo = strdup(realname);
242 client->servername = servername;
244 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
245 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
247 /* Create new cache entry */
248 silc_idcache_add(global ? server->global_list->clients :
249 server->local_list->clients, nick, client->id,
251 silc_free(client_id);
254 /* Save channel list if it was sent to us */
255 if (server->server_type == SILC_SERVER) {
256 tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
257 umodes = silc_argument_get_arg_type(cmd->args, 10, &len2);
259 SilcBufferStruct channels_buf, umodes_buf;
260 silc_buffer_set(&channels_buf, tmp, len);
261 silc_buffer_set(&umodes_buf, umodes, len2);
262 silc_server_save_user_channels(server, cmd->sock, client, &channels_buf,
265 silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
268 /* If client is global and is not on any channel then add that we'll
269 expire the entry after a while. */
271 silc_idlist_find_client_by_id(server->global_list, client->id,
273 if (!silc_hash_table_count(client->channels))
274 cache->expire = time(NULL) + 300;
280 if (fingerprint && flen == sizeof(client->data.fingerprint))
281 memcpy(client->data.fingerprint, fingerprint, flen);
286 /* Reiceved reply for WHOIS command. We sent the whois request to our
287 primary router, if we are normal server, and thus has now received reply
288 to the command. We will figure out what client originally sent us the
289 command and will send the reply to it. If we are router we will figure
290 out who server sent us the command and send reply to that one. */
292 SILC_SERVER_CMD_REPLY_FUNC(whois)
294 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
295 SilcStatus status, error;
297 COMMAND_CHECK_STATUS;
299 if (!silc_server_command_reply_whois_save(cmd))
302 /* Pending callbacks are not executed if this was an list entry */
303 if (status != SILC_STATUS_OK &&
304 status != SILC_STATUS_LIST_END) {
305 silc_server_command_reply_free(cmd);
310 silc_server_command_process_error(cmd, error);
311 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
312 silc_server_command_reply_free(cmd);
316 silc_server_command_process_error(cmd, error);
317 silc_server_command_reply_free(cmd);
320 /* Caches the received WHOWAS information for a short period of time. */
323 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
325 SilcServer server = cmd->server;
326 SilcUInt32 len, id_len;
327 unsigned char *id_data;
328 char *nickname, *username, *realname, *servername = NULL;
329 SilcClientID *client_id;
330 SilcClientEntry client;
331 SilcIDCacheEntry cache = NULL;
335 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
336 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
337 username = silc_argument_get_arg_type(cmd->args, 4, &len);
338 if (!id_data || !nickname || !username)
341 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
343 client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
347 /* Check if we have this client cached already. */
349 client = silc_idlist_find_client_by_id(server->local_list, client_id,
352 client = silc_idlist_find_client_by_id(server->global_list,
353 client_id, FALSE, &cache);
358 /* If router did not find such Client ID in its lists then this must
359 be bogus client or some router in the net is buggy. */
360 if (server->server_type != SILC_SERVER)
363 /* Take hostname out of nick string if it includes it. */
364 silc_parse_userfqdn(nickname, &nick, &servername);
366 /* We don't have that client anywhere, add it. The client is added
367 to global list since server didn't have it in the lists so it must be
369 client = silc_idlist_add_client(server->global_list, nick,
370 strdup(username), strdup(realname),
371 silc_id_dup(client_id, SILC_ID_CLIENT),
372 cmd->sock->user_data, NULL,
373 SILC_ID_CACHE_EXPIRE_DEF);
375 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
379 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
380 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
381 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
382 client->servername = servername;
384 /* We have the client already, update the data */
386 /* Take hostname out of nick string if it includes it. */
387 silc_parse_userfqdn(nickname, &nick, &servername);
389 silc_free(client->nickname);
390 silc_free(client->username);
391 silc_free(client->servername);
393 client->nickname = nick;
394 client->username = strdup(username);
395 client->servername = servername;
396 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
397 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
399 /* Remove the old cache entry and create a new one */
400 silc_idcache_del_by_context(global ? server->global_list->clients :
401 server->local_list->clients, client);
402 silc_idcache_add(global ? server->global_list->clients :
403 server->local_list->clients, nick, client->id,
407 /* If client is global and is not on any channel then add that we'll
408 expire the entry after a while. */
410 silc_idlist_find_client_by_id(server->global_list, client->id,
412 if (!silc_hash_table_count(client->channels))
413 cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
418 silc_free(client_id);
423 /* Received reply for WHOWAS command. Cache the client information only for
424 a short period of time. */
426 SILC_SERVER_CMD_REPLY_FUNC(whowas)
428 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
429 SilcStatus status, error;
431 COMMAND_CHECK_STATUS;
433 if (!silc_server_command_reply_whowas_save(cmd))
436 /* Pending callbacks are not executed if this was an list entry */
437 if (status != SILC_STATUS_OK &&
438 status != SILC_STATUS_LIST_END) {
439 silc_server_command_reply_free(cmd);
444 silc_server_command_process_error(cmd, error);
445 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
446 silc_server_command_reply_free(cmd);
450 silc_server_command_process_error(cmd, error);
451 silc_server_command_reply_free(cmd);
454 /* Caches the received IDENTIFY information. */
457 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
459 SilcServer server = cmd->server;
460 SilcUInt32 len, id_len;
461 unsigned char *id_data;
463 SilcClientID *client_id = NULL;
464 SilcServerID *server_id = NULL;
465 SilcChannelID *channel_id = NULL;
466 SilcClientEntry client;
467 SilcServerEntry server_entry;
468 SilcChannelEntry channel;
471 SilcIDPayload idp = NULL;
475 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
478 idp = silc_id_payload_parse(id_data, id_len);
482 name = silc_argument_get_arg_type(cmd->args, 3, &len);
483 info = silc_argument_get_arg_type(cmd->args, 4, &len);
485 id_type = silc_id_payload_get_type(idp);
489 client_id = silc_id_payload_get_id(idp);
493 SILC_LOG_DEBUG(("Received client information"));
495 client = silc_idlist_find_client_by_id(server->local_list,
496 client_id, FALSE, NULL);
498 client = silc_idlist_find_client_by_id(server->global_list, client_id,
503 /* If router did not find such Client ID in its lists then this must
504 be bogus client or some router in the net is buggy. */
505 if (server->server_type != SILC_SERVER)
510 silc_parse_userfqdn(name, &nick, NULL);
512 /* We don't have that client anywhere, add it. The client is added
513 to global list since server didn't have it in the lists so it must be
515 client = silc_idlist_add_client(server->global_list, nick,
516 info ? strdup(info) : NULL, NULL,
517 client_id, cmd->sock->user_data,
518 NULL, time(NULL) + 300);
520 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
523 client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
524 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
525 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
527 /* We have the client already, update the data */
529 SILC_LOG_DEBUG(("Updating client data"));
533 silc_parse_userfqdn(name, &nick, NULL);
535 /* Remove the old cache entry */
536 silc_idcache_del_by_context(global ? server->global_list->clients :
537 server->local_list->clients, client);
539 silc_free(client->nickname);
540 client->nickname = nick;
544 silc_free(client->username);
545 client->username = strdup(info);
548 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
549 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
552 /* Add new cache entry */
553 silc_idcache_add(global ? server->global_list->clients :
554 server->local_list->clients, nick, client->id,
555 client, expire, NULL);
558 /* If client is global and is not on any channel then add that we'll
559 expire the entry after a while. */
560 if (global && server->server_type == SILC_SERVER) {
561 SilcIDCacheEntry cache = NULL;
562 silc_idlist_find_client_by_id(server->global_list, client->id,
564 if (!silc_hash_table_count(client->channels))
565 cache->expire = time(NULL) + 300;
570 silc_free(client_id);
579 server_id = silc_id_payload_get_id(idp);
583 SILC_LOG_DEBUG(("Received server information"));
585 server_entry = silc_idlist_find_server_by_id(server->local_list,
586 server_id, FALSE, NULL);
588 server_entry = silc_idlist_find_server_by_id(server->global_list,
589 server_id, FALSE, NULL);
591 /* If router did not find such Server ID in its lists then this must
592 be bogus server or some router in the net is buggy. */
593 if (server->server_type != SILC_SERVER)
596 /* We don't have that server anywhere, add it. */
597 server_entry = silc_idlist_add_server(server->global_list,
599 server_id, server->router,
600 SILC_PRIMARY_ROUTE(server));
602 silc_free(server_id);
605 server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
606 server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
607 server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
611 silc_free(server_id);
614 case SILC_ID_CHANNEL:
618 channel_id = silc_id_payload_get_id(idp);
622 SILC_LOG_DEBUG(("Received channel information"));
624 channel = silc_idlist_find_channel_by_name(server->local_list,
627 channel = silc_idlist_find_channel_by_name(server->global_list,
630 /* If router did not find such Channel ID in its lists then this must
631 be bogus channel or some router in the net is buggy. */
632 if (server->server_type != SILC_SERVER)
635 /* We don't have that channel anywhere, add it. */
636 channel = silc_idlist_add_channel(server->global_list, strdup(name),
637 SILC_CHANNEL_MODE_NONE, channel_id,
638 server->router, NULL, NULL, 0);
640 silc_free(channel_id);
646 silc_free(channel_id);
650 silc_id_payload_free(idp);
654 silc_id_payload_free(idp);
658 /* Received reply for forwarded IDENTIFY command. We have received the
659 requested identify information now and we will cache it. After this we
660 will call the pending command so that the requestee gets the information
663 SILC_SERVER_CMD_REPLY_FUNC(identify)
665 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
666 SilcStatus status, error;
668 COMMAND_CHECK_STATUS;
670 if (!silc_server_command_reply_identify_save(cmd))
673 /* Pending callbacks are not executed if this was an list entry */
674 if (status != SILC_STATUS_OK &&
675 status != SILC_STATUS_LIST_END) {
676 silc_server_command_reply_free(cmd);
681 silc_server_command_process_error(cmd, error);
682 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
683 silc_server_command_reply_free(cmd);
687 silc_server_command_process_error(cmd, error);
688 silc_server_command_reply_free(cmd);
691 /* Received reply fro INFO command. Cache the server and its information */
693 SILC_SERVER_CMD_REPLY_FUNC(info)
695 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
696 SilcServer server = cmd->server;
697 SilcStatus status, error;
698 SilcServerEntry entry;
699 SilcServerID *server_id;
701 unsigned char *tmp, *name;
703 COMMAND_CHECK_STATUS;
706 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
709 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
714 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
718 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
721 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
724 /* Add the server to global list */
725 server_id = silc_id_dup(server_id, SILC_ID_SERVER);
726 entry = silc_idlist_add_server(server->global_list, name, 0,
727 server_id, cmd->sock->user_data,
730 silc_free(server_id);
733 entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
737 /* Get the info string */
738 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
742 entry->server_info = tmp ? strdup(tmp) : NULL;
745 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
747 silc_server_command_reply_free(cmd);
750 /* Received reply fro MOTD command. */
752 SILC_SERVER_CMD_REPLY_FUNC(motd)
754 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
755 SilcServer server = cmd->server;
756 SilcStatus status, error;
757 SilcServerEntry entry = NULL;
758 SilcServerID *server_id;
762 COMMAND_CHECK_STATUS;
765 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
768 server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
772 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
775 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
782 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
789 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
791 silc_server_command_reply_free(cmd);
797 /* Received reply for forwarded JOIN command. Router has created or joined
798 the client to the channel. We save some channel information locally
801 SILC_SERVER_CMD_REPLY_FUNC(join)
803 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
804 SilcServer server = cmd->server;
805 SilcIDCacheEntry cache = NULL;
806 SilcStatus status, error;
808 SilcClientID *client_id = NULL;
809 SilcChannelEntry entry;
810 SilcHmac hmac = NULL;
811 SilcUInt32 id_len, len, list_count;
812 unsigned char *id_string;
813 char *channel_name, *tmp;
814 SilcUInt32 mode, created;
815 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
816 SilcPublicKey founder_key = NULL;
818 COMMAND_CHECK_STATUS;
820 /* Get channel name */
821 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
826 id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
831 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
834 client_id = silc_id_payload_parse_id(tmp, len, NULL);
839 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
842 SILC_GET32_MSB(mode, tmp);
844 /* Get created boolean value */
845 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
848 SILC_GET32_MSB(created, tmp);
849 if (created != 0 && created != 1)
852 /* Get channel key */
853 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
855 keyp = silc_buffer_alloc(len);
856 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
857 silc_buffer_put(keyp, tmp, len);
860 /* Parse the Channel ID */
861 id = silc_id_payload_parse_id(id_string, id_len, NULL);
866 tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
868 if (!silc_hmac_alloc(tmp, NULL, &hmac))
872 /* Get the list count */
873 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
876 SILC_GET32_MSB(list_count, tmp);
878 /* Get Client ID list */
879 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
883 client_id_list = silc_buffer_alloc(len);
884 silc_buffer_pull_tail(client_id_list, len);
885 silc_buffer_put(client_id_list, tmp, len);
887 /* Get client mode list */
888 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
892 client_mode_list = silc_buffer_alloc(len);
893 silc_buffer_pull_tail(client_mode_list, len);
894 silc_buffer_put(client_mode_list, tmp, len);
896 /* Get founder key */
897 tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
899 silc_pkcs_public_key_decode(tmp, len, &founder_key);
901 /* See whether we already have the channel. */
902 entry = silc_idlist_find_channel_by_name(server->local_list,
903 channel_name, &cache);
905 /* Add new channel */
907 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
908 (created == 0 ? "existing" : "created"), channel_name,
909 silc_id_render(id, SILC_ID_CHANNEL)));
911 /* If the channel is found from global list we must move it to the
913 entry = silc_idlist_find_channel_by_name(server->global_list,
914 channel_name, &cache);
916 silc_idlist_del_channel(server->global_list, entry);
918 /* Add the channel to our local list. */
919 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
920 SILC_CHANNEL_MODE_NONE, id,
921 server->router, NULL, hmac, 0);
926 server->stat.my_channels++;
927 server->stat.channels++;
929 /* The entry exists. */
931 /* If ID has changed, then update it to the cache too. */
932 if (!SILC_ID_CHANNEL_COMPARE(entry->id, id))
933 silc_idlist_replace_channel_id(server->local_list, entry->id, id);
935 entry->disabled = FALSE;
937 /* Remove the founder auth data if the mode is not set but we have
939 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
940 silc_pkcs_public_key_free(entry->founder_key);
941 entry->founder_key = NULL;
946 if (entry->founder_key)
947 silc_pkcs_public_key_free(entry->founder_key);
948 entry->founder_key = founder_key;
952 if (entry->hmac_name && hmac) {
953 silc_free(entry->hmac_name);
954 entry->hmac_name = strdup(silc_hmac_get_name(hmac));
957 /* Get the ban list */
958 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
960 silc_free(entry->ban_list);
961 entry->ban_list = silc_memdup(tmp, len);
964 /* Get the invite list */
965 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
967 silc_free(entry->invite_list);
968 entry->invite_list = silc_memdup(tmp, len);
972 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
974 silc_free(entry->topic);
975 entry->topic = strdup(tmp);
978 /* If channel was not created we know there is global users on the
980 entry->global_users = (created == 0 ? TRUE : FALSE);
982 /* If channel was just created the mask must be zero */
983 if (!entry->global_users && mode) {
984 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
985 "new channel, forcing it to zero", cmd->sock->hostname));
989 /* Save channel mode */
992 /* Save channel key */
994 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
995 silc_server_save_channel_key(server, keyp, entry);
996 silc_buffer_free(keyp);
999 /* Save the users to the channel */
1000 silc_server_save_users_on_channel(server, cmd->sock, entry,
1001 client_id, client_id_list,
1002 client_mode_list, list_count);
1003 entry->users_resolved = TRUE;
1006 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
1008 silc_free(client_id);
1009 silc_server_command_reply_free(cmd);
1011 silc_pkcs_public_key_free(founder_key);
1013 silc_buffer_free(client_id_list);
1014 if (client_mode_list)
1015 silc_buffer_free(client_mode_list);
1018 /* Received reply to STATS command. */
1020 SILC_SERVER_CMD_REPLY_FUNC(stats)
1022 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1023 SilcServer server = cmd->server;
1024 SilcStatus status, error;
1027 SilcBufferStruct buf;
1029 COMMAND_CHECK_STATUS;
1031 /* Get statistics structure */
1032 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1033 if (server->server_type == SILC_SERVER && tmp) {
1034 silc_buffer_set(&buf, tmp, tmp_len);
1035 silc_buffer_unformat(&buf,
1036 SILC_STR_UI_INT(NULL),
1037 SILC_STR_UI_INT(NULL),
1038 SILC_STR_UI_INT(NULL),
1039 SILC_STR_UI_INT(NULL),
1040 SILC_STR_UI_INT(NULL),
1041 SILC_STR_UI_INT(NULL),
1042 SILC_STR_UI_INT(&server->stat.cell_clients),
1043 SILC_STR_UI_INT(&server->stat.cell_channels),
1044 SILC_STR_UI_INT(&server->stat.cell_servers),
1045 SILC_STR_UI_INT(&server->stat.clients),
1046 SILC_STR_UI_INT(&server->stat.channels),
1047 SILC_STR_UI_INT(&server->stat.servers),
1048 SILC_STR_UI_INT(&server->stat.routers),
1049 SILC_STR_UI_INT(&server->stat.server_ops),
1050 SILC_STR_UI_INT(&server->stat.router_ops),
1055 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_STATS);
1057 silc_server_command_reply_free(cmd);
1060 SILC_SERVER_CMD_REPLY_FUNC(users)
1062 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1063 SilcServer server = cmd->server;
1064 SilcStatus status, error;
1065 SilcChannelEntry channel;
1066 SilcChannelID *channel_id = NULL;
1067 SilcBuffer client_id_list;
1068 SilcBuffer client_mode_list;
1071 SilcUInt32 list_count;
1073 COMMAND_CHECK_STATUS;
1075 /* Get channel ID */
1076 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
1079 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1083 /* Get channel entry */
1084 channel = silc_idlist_find_channel_by_id(server->local_list,
1087 channel = silc_idlist_find_channel_by_id(server->global_list,
1092 if (server->server_type != SILC_SERVER)
1095 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1096 silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
1097 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1098 1, 5, idp->data, idp->len);
1099 silc_buffer_free(idp);
1101 /* Register pending command callback. After we've received the channel
1102 information we will reprocess this command reply by re-calling this
1103 USERS command reply callback. */
1104 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1106 silc_server_command_reply_users, cmd);
1111 /* Get the list count */
1112 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1115 SILC_GET32_MSB(list_count, tmp);
1117 /* Get Client ID list */
1118 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1122 client_id_list = silc_buffer_alloc(tmp_len);
1123 silc_buffer_pull_tail(client_id_list, tmp_len);
1124 silc_buffer_put(client_id_list, tmp, tmp_len);
1126 /* Get client mode list */
1127 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1131 client_mode_list = silc_buffer_alloc(tmp_len);
1132 silc_buffer_pull_tail(client_mode_list, tmp_len);
1133 silc_buffer_put(client_mode_list, tmp, tmp_len);
1135 /* Save the users to the channel */
1136 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1137 client_id_list, client_mode_list,
1140 channel->global_users = silc_server_channel_has_global(channel);
1141 channel->users_resolved = TRUE;
1143 silc_buffer_free(client_id_list);
1144 silc_buffer_free(client_mode_list);
1147 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1148 silc_free(channel_id);
1150 silc_server_command_reply_free(cmd);
1153 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1155 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1156 SilcServer server = cmd->server;
1157 SilcStatus status, error;
1158 SilcClientEntry client = NULL;
1159 SilcServerEntry server_entry = NULL;
1160 SilcClientID *client_id = NULL;
1161 SilcServerID *server_id = NULL;
1163 unsigned char *tmp, *pk;
1166 SilcIDPayload idp = NULL;
1168 SilcPublicKey public_key = NULL;
1170 COMMAND_CHECK_STATUS;
1172 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1175 idp = silc_id_payload_parse(tmp, len);
1179 /* Get the public key payload */
1180 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1184 /* Decode the public key */
1186 SILC_GET16_MSB(pk_len, tmp);
1187 SILC_GET16_MSB(type, tmp + 2);
1190 if (type != SILC_SKE_PK_TYPE_SILC)
1193 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1196 id_type = silc_id_payload_get_type(idp);
1197 if (id_type == SILC_ID_CLIENT) {
1198 client_id = silc_id_payload_get_id(idp);
1200 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1203 client = silc_idlist_find_client_by_id(server->global_list,
1204 client_id, TRUE, NULL);
1209 client->data.public_key = public_key;
1211 } else if (id_type == SILC_ID_SERVER) {
1212 server_id = silc_id_payload_get_id(idp);
1214 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1216 if (!server_entry) {
1217 server_entry = silc_idlist_find_server_by_id(server->global_list,
1218 server_id, TRUE, NULL);
1223 server_entry->data.public_key = public_key;
1230 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1232 silc_id_payload_free(idp);
1233 silc_free(client_id);
1234 silc_free(server_id);
1236 silc_pkcs_public_key_free(public_key);
1238 silc_server_command_reply_free(cmd);
1241 SILC_SERVER_CMD_REPLY_FUNC(list)
1243 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1244 SilcServer server = cmd->server;
1245 SilcStatus status, error;
1246 SilcChannelID *channel_id = NULL;
1247 SilcChannelEntry channel;
1248 SilcIDCacheEntry cache;
1250 unsigned char *tmp, *name, *topic;
1251 SilcUInt32 usercount = 0;
1252 bool global_list = FALSE;
1254 COMMAND_CHECK_STATUS;
1256 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1257 channel_id = silc_id_payload_parse_id(tmp, len, NULL);
1261 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1262 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1263 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1265 SILC_GET32_MSB(usercount, tmp);
1267 /* Add the channel entry if we do not have it already */
1268 channel = silc_idlist_find_channel_by_name(server->local_list,
1271 channel = silc_idlist_find_channel_by_name(server->global_list,
1276 /* If router did not find such channel in its lists then this must
1277 be bogus channel or some router in the net is buggy. */
1278 if (server->server_type != SILC_SERVER)
1281 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1282 SILC_CHANNEL_MODE_NONE, channel_id,
1283 server->router, NULL, NULL,
1289 /* Found, update expiry */
1290 if (global_list && server->server_type == SILC_SERVER)
1291 cache->expire = time(NULL) + 60;
1294 channel->user_count = usercount;
1297 silc_free(channel->topic);
1298 channel->topic = strdup(topic);
1301 /* Pending callbacks are not executed if this was an list entry */
1302 if (status != SILC_STATUS_OK &&
1303 status != SILC_STATUS_LIST_END) {
1304 silc_server_command_reply_free(cmd);
1308 /* Now purge all old entries from the global list, otherwise we'll might
1309 have non-existent entries for long periods of time in the cache. */
1310 silc_idcache_purge(server->global_list->channels);
1313 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1314 silc_free(channel_id);
1316 silc_server_command_reply_free(cmd);
1319 SILC_SERVER_CMD_REPLY_FUNC(watch)
1321 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1322 SilcStatus status, error;
1324 COMMAND_CHECK_STATUS;
1327 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WATCH);
1329 silc_server_command_reply_free(cmd);