5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2001 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 or the
27 COMMAND_CHECK_STATUS_LIST macros must have out: goto label. */
29 #define COMMAND_CHECK_STATUS \
31 SILC_LOG_DEBUG(("Start")); \
32 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
33 if (status != SILC_STATUS_OK) \
37 #define COMMAND_CHECK_STATUS_LIST \
39 SILC_LOG_DEBUG(("Start")); \
40 SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); \
41 if (status != SILC_STATUS_OK && \
42 status != SILC_STATUS_LIST_START && \
43 status != SILC_STATUS_LIST_ITEM && \
44 status != SILC_STATUS_LIST_END) \
48 /* Server command reply list. Not all commands have reply function as
49 they are never sent by server. More maybe added later if need appears. */
50 SilcServerCommandReply silc_command_reply_list[] =
52 SILC_SERVER_CMD_REPLY(whois, WHOIS),
53 SILC_SERVER_CMD_REPLY(whowas, WHOWAS),
54 SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
55 SILC_SERVER_CMD_REPLY(info, INFO),
56 SILC_SERVER_CMD_REPLY(motd, MOTD),
57 SILC_SERVER_CMD_REPLY(join, JOIN),
58 SILC_SERVER_CMD_REPLY(users, USERS),
59 SILC_SERVER_CMD_REPLY(getkey, GETKEY),
60 SILC_SERVER_CMD_REPLY(list, LIST),
65 /* Process received command reply. */
67 void silc_server_command_reply_process(SilcServer server,
68 SilcSocketConnection sock,
71 SilcServerCommandReply *cmd;
72 SilcServerCommandReplyContext ctx;
73 SilcCommandPayload payload;
77 SILC_LOG_DEBUG(("Start"));
79 /* Get command reply payload from packet */
80 payload = silc_command_payload_parse(buffer->data, buffer->len);
82 /* Silently ignore bad reply packet */
83 SILC_LOG_DEBUG(("Bad command reply packet"));
87 /* Allocate command reply context. This must be free'd by the
88 command reply routine receiving it. */
89 ctx = silc_calloc(1, sizeof(*ctx));
91 ctx->sock = silc_socket_dup(sock);
92 ctx->payload = payload;
93 ctx->args = silc_command_get_args(ctx->payload);
94 ident = silc_command_get_ident(ctx->payload);
96 /* Check for pending commands and mark to be exeucted */
98 silc_server_command_pending_check(server, ctx,
99 silc_command_get(ctx->payload),
100 ident, &ctx->callbacks_count);
102 /* Execute command reply */
103 command = silc_command_get(ctx->payload);
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);
129 /* Caches the received WHOIS information. */
132 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
134 SilcServer server = cmd->server;
135 unsigned char *tmp, *id_data;
136 char *nickname, *username, *realname, *servername = NULL;
137 unsigned char *fingerprint;
138 SilcClientID *client_id;
139 SilcClientEntry client;
142 uint32 mode = 0, len, id_len, flen;
145 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
146 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
147 username = silc_argument_get_arg_type(cmd->args, 4, &len);
148 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
149 if (!id_data || !nickname || !username || !realname) {
150 SILC_LOG_ERROR(("Incomplete WHOIS info: %s %s %s",
151 nickname ? nickname : "",
152 username ? username : "",
153 realname ? realname : ""));
157 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
159 SILC_GET32_MSB(mode, tmp);
161 client_id = silc_id_payload_parse_id(id_data, id_len);
165 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);
167 /* Check if we have this client cached already. */
169 client = silc_idlist_find_client_by_id(server->local_list, client_id,
172 client = silc_idlist_find_client_by_id(server->global_list, client_id,
178 /* If router did not find such Client ID in its lists then this must
179 be bogus client or some router in the net is buggy. */
180 if (server->server_type != SILC_SERVER)
183 /* Take hostname out of nick string if it includes it. */
184 silc_parse_userfqdn(nickname, &nick, &servername);
186 /* We don't have that client anywhere, add it. The client is added
187 to global list since server didn't have it in the lists so it must be
189 client = silc_idlist_add_client(server->global_list, nick,
191 strdup(realname), client_id,
192 cmd->sock->user_data, NULL,
195 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
199 client->data.status |=
200 (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
201 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
203 client->servername = servername;
205 /* We have the client already, update the data */
207 SILC_LOG_DEBUG(("Updating client data"));
209 /* Take hostname out of nick string if it includes it. */
210 silc_parse_userfqdn(nickname, &nick, &servername);
212 /* Remove the old cache entry */
213 silc_idcache_del_by_context(global ? server->global_list->clients :
214 server->local_list->clients, client);
216 silc_free(client->nickname);
217 silc_free(client->username);
218 silc_free(client->userinfo);
219 silc_free(client->servername);
221 client->nickname = nick;
222 client->username = strdup(username);
223 client->userinfo = strdup(realname);
224 client->servername = servername;
226 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
227 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
229 /* If client is global and is not on any channel then add that we'll
230 expire the entry after a while. */
231 if (global && !silc_hash_table_count(client->channels) &&
232 server->server_type == SILC_SERVER)
233 expire = time(NULL) + 300;
235 /* Create new cache entry */
236 silc_idcache_add(global ? server->global_list->clients :
237 server->local_list->clients, nick, client->id,
238 client, expire, NULL);
239 silc_free(client_id);
242 if (fingerprint && flen == sizeof(client->data.fingerprint))
243 memcpy(client->data.fingerprint, fingerprint, flen);
248 /* Reiceved reply for WHOIS command. We sent the whois request to our
249 primary router, if we are normal server, and thus has now received reply
250 to the command. We will figure out what client originally sent us the
251 command and will send the reply to it. If we are router we will figure
252 out who server sent us the command and send reply to that one. */
254 SILC_SERVER_CMD_REPLY_FUNC(whois)
256 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
257 SilcServer server = cmd->server;
258 SilcCommandStatus status;
260 COMMAND_CHECK_STATUS_LIST;
262 if (!silc_server_command_reply_whois_save(cmd))
265 /* Pending callbacks are not executed if this was an list entry */
266 if (status != SILC_STATUS_OK &&
267 status != SILC_STATUS_LIST_END) {
268 silc_server_command_reply_free(cmd);
273 /* If we received notify for invalid ID we'll remove the ID if we
275 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
276 cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
277 SilcClientEntry client;
279 unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
281 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
283 SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
284 "the entry from cache"));
285 client = silc_idlist_find_client_by_id(server->global_list,
286 client_id, FALSE, NULL);
288 silc_server_remove_from_channels(server, NULL, client, TRUE,
290 silc_idlist_del_client(server->global_list, client);
292 silc_free(client_id);
297 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
298 silc_server_command_reply_free(cmd);
301 /* Caches the received WHOWAS information for a short period of time. */
304 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
306 SilcServer server = cmd->server;
308 unsigned char *id_data;
309 char *nickname, *username, *realname, *servername = NULL;
310 SilcClientID *client_id;
311 SilcClientEntry client;
312 SilcIDCacheEntry cache = NULL;
316 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
317 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
318 username = silc_argument_get_arg_type(cmd->args, 4, &len);
319 if (!id_data || !nickname || !username)
322 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
324 client_id = silc_id_payload_parse_id(id_data, id_len);
328 /* Check if we have this client cached already. */
330 client = silc_idlist_find_client_by_id(server->local_list, client_id,
333 client = silc_idlist_find_client_by_id(server->global_list,
334 client_id, FALSE, &cache);
339 /* If router did not find such Client ID in its lists then this must
340 be bogus client or some router in the net is buggy. */
341 if (server->server_type != SILC_SERVER)
344 /* Take hostname out of nick string if it includes it. */
345 silc_parse_userfqdn(nickname, &nick, &servername);
347 /* We don't have that client anywhere, add it. The client is added
348 to global list since server didn't have it in the lists so it must be
350 client = silc_idlist_add_client(server->global_list, nick,
351 strdup(username), strdup(realname),
352 silc_id_dup(client_id, SILC_ID_CLIENT),
353 cmd->sock->user_data, NULL,
354 SILC_ID_CACHE_EXPIRE_DEF);
356 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
360 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
361 client->servername = servername;
363 /* We have the client already, update the data */
365 /* Take hostname out of nick string if it includes it. */
366 silc_parse_userfqdn(nickname, &nick, &servername);
368 silc_free(client->nickname);
369 silc_free(client->username);
371 client->nickname = nick;
372 client->username = strdup(username);
373 client->servername = servername;
375 /* Remove the old cache entry and create a new one */
376 silc_idcache_del_by_context(global ? server->global_list->clients :
377 server->local_list->clients, client);
378 silc_idcache_add(global ? server->global_list->clients :
379 server->local_list->clients, nick, client->id,
383 silc_free(client_id);
388 /* Received reply for WHOWAS command. Cache the client information only for
389 a short period of time. */
391 SILC_SERVER_CMD_REPLY_FUNC(whowas)
393 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
394 SilcCommandStatus status;
396 COMMAND_CHECK_STATUS_LIST;
398 if (!silc_server_command_reply_whowas_save(cmd))
401 /* Pending callbacks are not executed if this was an list entry */
402 if (status != SILC_STATUS_OK &&
403 status != SILC_STATUS_LIST_END) {
404 silc_server_command_reply_free(cmd);
409 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
410 silc_server_command_reply_free(cmd);
413 /* Caches the received IDENTIFY information. */
416 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
418 SilcServer server = cmd->server;
420 unsigned char *id_data;
422 SilcClientID *client_id = NULL;
423 SilcServerID *server_id = NULL;
424 SilcChannelID *channel_id = NULL;
425 SilcClientEntry client;
426 SilcServerEntry server_entry;
427 SilcChannelEntry channel;
430 SilcIDPayload idp = NULL;
434 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
437 idp = silc_id_payload_parse(id_data, id_len);
441 name = silc_argument_get_arg_type(cmd->args, 3, &len);
442 info = silc_argument_get_arg_type(cmd->args, 4, &len);
444 id_type = silc_id_payload_get_type(idp);
448 client_id = silc_id_payload_get_id(idp);
452 SILC_LOG_DEBUG(("Received client information"));
454 client = silc_idlist_find_client_by_id(server->local_list,
455 client_id, FALSE, NULL);
457 client = silc_idlist_find_client_by_id(server->global_list, client_id,
462 /* If router did not find such Client ID in its lists then this must
463 be bogus client or some router in the net is buggy. */
464 if (server->server_type != SILC_SERVER)
469 silc_parse_userfqdn(name, &nick, NULL);
471 /* We don't have that client anywhere, add it. The client is added
472 to global list since server didn't have it in the lists so it must be
474 client = silc_idlist_add_client(server->global_list, nick,
475 info ? strdup(info) : NULL, NULL,
476 client_id, cmd->sock->user_data, NULL,
479 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
482 client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
483 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
484 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
486 /* We have the client already, update the data */
488 SILC_LOG_DEBUG(("Updating client data"));
492 silc_parse_userfqdn(name, &nick, NULL);
494 /* Remove the old cache entry */
495 silc_idcache_del_by_context(global ? server->global_list->clients :
496 server->local_list->clients, client);
498 silc_free(client->nickname);
499 client->nickname = nick;
503 silc_free(client->username);
504 client->username = strdup(info);
507 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
508 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
511 /* If client is global and is not on any channel then add that we'll
512 expire the entry after a while. */
513 if (global && !silc_hash_table_count(client->channels) &&
514 server->server_type == SILC_SERVER)
515 expire = time(NULL) + 300;
517 /* Add new cache entry */
518 silc_idcache_add(global ? server->global_list->clients :
519 server->local_list->clients, nick, client->id,
520 client, expire, NULL);
523 silc_free(client_id);
532 server_id = silc_id_payload_get_id(idp);
536 SILC_LOG_DEBUG(("Received server information"));
538 server_entry = silc_idlist_find_server_by_id(server->local_list,
539 server_id, FALSE, NULL);
541 server_entry = silc_idlist_find_server_by_id(server->global_list,
542 server_id, FALSE, NULL);
544 /* If router did not find such Server ID in its lists then this must
545 be bogus server or some router in the net is buggy. */
546 if (server->server_type != SILC_SERVER)
549 /* We don't have that server anywhere, add it. */
550 server_entry = silc_idlist_add_server(server->global_list,
552 server_id, NULL, NULL);
554 silc_free(server_id);
557 server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
558 server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
559 server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
563 silc_free(server_id);
566 case SILC_ID_CHANNEL:
570 channel_id = silc_id_payload_get_id(idp);
574 SILC_LOG_DEBUG(("Received channel information"));
576 channel = silc_idlist_find_channel_by_name(server->local_list,
579 channel = silc_idlist_find_channel_by_name(server->global_list,
582 /* If router did not find such Channel ID in its lists then this must
583 be bogus channel or some router in the net is buggy. */
584 if (server->server_type != SILC_SERVER)
587 /* We don't have that server anywhere, add it. */
588 channel = silc_idlist_add_channel(server->global_list, strdup(name),
589 SILC_CHANNEL_MODE_NONE, channel_id,
590 server->router, NULL, NULL, 0);
592 silc_free(channel_id);
598 silc_free(channel_id);
602 silc_id_payload_free(idp);
606 silc_id_payload_free(idp);
610 /* Received reply for forwarded IDENTIFY command. We have received the
611 requested identify information now and we will cache it. After this we
612 will call the pending command so that the requestee gets the information
615 SILC_SERVER_CMD_REPLY_FUNC(identify)
617 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
618 SilcServer server = cmd->server;
619 SilcCommandStatus status;
621 COMMAND_CHECK_STATUS_LIST;
623 if (!silc_server_command_reply_identify_save(cmd))
626 /* Pending callbacks are not executed if this was an list entry */
627 if (status != SILC_STATUS_OK &&
628 status != SILC_STATUS_LIST_END) {
629 silc_server_command_reply_free(cmd);
634 /* If we received notify for invalid ID we'll remove the ID if we
636 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
637 cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
638 SilcClientEntry client;
640 unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
642 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
644 SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
645 "the entry from cache"));
646 client = silc_idlist_find_client_by_id(server->global_list,
647 client_id, FALSE, NULL);
649 silc_server_remove_from_channels(server, NULL, client, TRUE,
651 silc_idlist_del_client(server->global_list, client);
653 silc_free(client_id);
658 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
659 silc_server_command_reply_free(cmd);
662 /* Received reply fro INFO command. Cache the server and its information */
664 SILC_SERVER_CMD_REPLY_FUNC(info)
666 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
667 SilcServer server = cmd->server;
668 SilcCommandStatus status;
669 SilcServerEntry entry;
670 SilcServerID *server_id;
672 unsigned char *tmp, *name;
674 COMMAND_CHECK_STATUS;
677 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
680 server_id = silc_id_payload_parse_id(tmp, tmp_len);
685 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
689 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
692 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
695 /* Add the server to global list */
696 server_id = silc_id_dup(server_id, SILC_ID_SERVER);
697 entry = silc_idlist_add_server(server->global_list, name, 0,
698 server_id, NULL, NULL);
700 silc_free(server_id);
703 entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
707 /* Get the info string */
708 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
712 entry->server_info = tmp ? strdup(tmp) : NULL;
715 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
716 silc_server_command_reply_free(cmd);
719 /* Received reply fro MOTD command. */
721 SILC_SERVER_CMD_REPLY_FUNC(motd)
723 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
724 SilcServer server = cmd->server;
725 SilcCommandStatus status;
726 SilcServerEntry entry = NULL;
727 SilcServerID *server_id;
731 COMMAND_CHECK_STATUS;
734 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
737 server_id = silc_id_payload_parse_id(tmp, tmp_len);
741 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
744 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
751 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
758 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
759 silc_server_command_reply_free(cmd);
765 /* Received reply for forwarded JOIN command. Router has created or joined
766 the client to the channel. We save some channel information locally
769 SILC_SERVER_CMD_REPLY_FUNC(join)
771 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
772 SilcServer server = cmd->server;
773 SilcIDCacheEntry cache = NULL;
774 SilcCommandStatus status;
776 SilcClientID *client_id = NULL;
777 SilcChannelEntry entry;
778 SilcHmac hmac = NULL;
779 uint32 id_len, len, list_count;
780 unsigned char *id_string;
781 char *channel_name, *tmp;
782 uint32 mode, created;
783 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
785 COMMAND_CHECK_STATUS;
787 /* Get channel name */
788 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
793 id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
798 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
801 client_id = silc_id_payload_parse_id(tmp, len);
806 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
809 SILC_GET32_MSB(mode, tmp);
811 /* Get created boolean value */
812 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
815 SILC_GET32_MSB(created, tmp);
816 if (created != 0 && created != 1)
819 /* Get channel key */
820 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
822 keyp = silc_buffer_alloc(len);
823 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
824 silc_buffer_put(keyp, tmp, len);
827 /* Parse the Channel ID */
828 id = silc_id_payload_parse_id(id_string, id_len);
833 tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
835 if (!silc_hmac_alloc(tmp, NULL, &hmac))
839 /* Get the list count */
840 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
843 SILC_GET32_MSB(list_count, tmp);
845 /* Get Client ID list */
846 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
850 client_id_list = silc_buffer_alloc(len);
851 silc_buffer_pull_tail(client_id_list, len);
852 silc_buffer_put(client_id_list, tmp, len);
854 /* Get client mode list */
855 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
859 client_mode_list = silc_buffer_alloc(len);
860 silc_buffer_pull_tail(client_mode_list, len);
861 silc_buffer_put(client_mode_list, tmp, len);
863 /* See whether we already have the channel. */
864 entry = silc_idlist_find_channel_by_name(server->local_list,
865 channel_name, &cache);
867 /* Add new channel */
869 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
870 (created == 0 ? "existing" : "created"), channel_name,
871 silc_id_render(id, SILC_ID_CHANNEL)));
873 /* If the channel is found from global list we must move it to the
875 entry = silc_idlist_find_channel_by_name(server->global_list,
876 channel_name, &cache);
879 silc_schedule_task_del_by_context(server->schedule, entry->rekey);
880 SILC_LOG_ERROR(("global_list->channels: entry->rekey != NULL, inform Pekka now!!!"));
882 silc_idlist_del_channel(server->global_list, entry);
885 /* Add the channel to our local list. */
886 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
887 SILC_CHANNEL_MODE_NONE, id,
888 server->router, NULL, hmac, 0);
893 server->stat.my_channels++;
895 /* The entry exists. */
897 /* If ID has changed, then update it to the cache too. */
898 if (!SILC_ID_CHANNEL_COMPARE(channel->id, id))
899 silc_idlist_replace_channel_id(server->local_list, channel->id, id);
901 entry->disabled = FALSE;
903 /* Remove the founder auth data if the mode is not set but we have
905 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
906 silc_pkcs_public_key_free(entry->founder_key);
907 silc_free(entry->founder_passwd);
908 entry->founder_passwd = NULL;
912 if (entry->hmac_name && hmac) {
913 silc_free(entry->hmac_name);
914 entry->hmac_name = strdup(silc_hmac_get_name(hmac));
917 /* Get the ban list */
918 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
921 silc_free(entry->ban_list);
922 entry->ban_list = silc_calloc(len, sizeof(*entry->ban_list));
923 memcpy(entry->ban_list, tmp, len);
926 /* Get the invite list */
927 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
929 if (entry->invite_list)
930 silc_free(entry->invite_list);
931 entry->invite_list = silc_calloc(len, sizeof(*entry->invite_list));
932 memcpy(entry->invite_list, tmp, len);
936 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
939 silc_free(entry->topic);
940 entry->topic = strdup(tmp);
943 /* If channel was not created we know there is global users on the
945 entry->global_users = (created == 0 ? TRUE : FALSE);
947 /* If channel was just created the mask must be zero */
948 if (!entry->global_users && mode) {
949 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
950 "new channel, forcing it to zero", cmd->sock->hostname));
954 /* Save channel mode */
957 /* Save channel key */
959 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
960 silc_server_save_channel_key(server, keyp, entry);
961 silc_buffer_free(keyp);
964 /* Save the users to the channel */
965 silc_server_save_users_on_channel(server, cmd->sock, entry,
966 client_id, client_id_list,
967 client_mode_list, list_count);
970 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
971 silc_free(client_id);
972 silc_server_command_reply_free(cmd);
975 silc_buffer_free(client_id_list);
976 if (client_mode_list)
977 silc_buffer_free(client_mode_list);
980 SILC_SERVER_CMD_REPLY_FUNC(users)
982 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
983 SilcServer server = cmd->server;
984 SilcCommandStatus status;
985 SilcChannelEntry channel;
986 SilcChannelID *channel_id = NULL;
987 SilcBuffer client_id_list;
988 SilcBuffer client_mode_list;
993 COMMAND_CHECK_STATUS;
996 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
999 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1003 /* Get channel entry */
1004 channel = silc_idlist_find_channel_by_id(server->local_list,
1007 channel = silc_idlist_find_channel_by_id(server->global_list,
1012 if (server->server_type != SILC_SERVER)
1015 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1016 silc_server_send_command(server, server->router->connection,
1017 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1018 1, 5, idp->data, idp->len);
1019 silc_buffer_free(idp);
1021 /* Register pending command callback. After we've received the channel
1022 information we will reprocess this command reply by re-calling this
1023 USERS command reply callback. */
1024 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1026 silc_server_command_reply_users, cmd);
1031 /* Get the list count */
1032 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1035 SILC_GET32_MSB(list_count, tmp);
1037 /* Get Client ID list */
1038 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1042 client_id_list = silc_buffer_alloc(tmp_len);
1043 silc_buffer_pull_tail(client_id_list, tmp_len);
1044 silc_buffer_put(client_id_list, tmp, tmp_len);
1046 /* Get client mode list */
1047 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1051 client_mode_list = silc_buffer_alloc(tmp_len);
1052 silc_buffer_pull_tail(client_mode_list, tmp_len);
1053 silc_buffer_put(client_mode_list, tmp, tmp_len);
1055 /* Save the users to the channel */
1056 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1057 client_id_list, client_mode_list,
1060 silc_buffer_free(client_id_list);
1061 silc_buffer_free(client_mode_list);
1064 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1065 silc_free(channel_id);
1066 silc_server_command_reply_free(cmd);
1069 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1071 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1072 SilcServer server = cmd->server;
1073 SilcCommandStatus status;
1074 SilcClientEntry client = NULL;
1075 SilcServerEntry server_entry = NULL;
1076 SilcClientID *client_id = NULL;
1077 SilcServerID *server_id = NULL;
1079 unsigned char *tmp, *pk;
1082 SilcIDPayload idp = NULL;
1084 SilcPublicKey public_key = NULL;
1086 COMMAND_CHECK_STATUS;
1088 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1091 idp = silc_id_payload_parse(tmp, len);
1095 /* Get the public key payload */
1096 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1100 /* Decode the public key */
1102 SILC_GET16_MSB(pk_len, tmp);
1103 SILC_GET16_MSB(type, tmp + 2);
1106 if (type != SILC_SKE_PK_TYPE_SILC)
1109 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1112 id_type = silc_id_payload_get_type(idp);
1113 if (id_type == SILC_ID_CLIENT) {
1114 client_id = silc_id_payload_get_id(idp);
1116 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1119 client = silc_idlist_find_client_by_id(server->global_list,
1120 client_id, TRUE, NULL);
1125 client->data.public_key = public_key;
1126 } else if (id_type == SILC_ID_SERVER) {
1127 server_id = silc_id_payload_get_id(idp);
1129 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1131 if (!server_entry) {
1132 server_entry = silc_idlist_find_server_by_id(server->global_list,
1133 server_id, TRUE, NULL);
1138 server_entry->data.public_key = public_key;
1144 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1146 silc_id_payload_free(idp);
1147 silc_free(client_id);
1148 silc_free(server_id);
1150 silc_pkcs_public_key_free(public_key);
1151 silc_server_command_reply_free(cmd);
1154 SILC_SERVER_CMD_REPLY_FUNC(list)
1156 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1157 SilcServer server = cmd->server;
1158 SilcCommandStatus status;
1159 SilcChannelID *channel_id = NULL;
1160 SilcChannelEntry channel;
1161 SilcIDCacheEntry cache;
1163 unsigned char *tmp, *name, *topic;
1164 uint32 usercount = 0;
1165 bool global_list = FALSE;
1167 COMMAND_CHECK_STATUS_LIST;
1169 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1170 channel_id = silc_id_payload_parse_id(tmp, len);
1174 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1175 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1176 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1178 SILC_GET32_MSB(usercount, tmp);
1180 /* Add the channel entry if we do not have it already */
1181 channel = silc_idlist_find_channel_by_name(server->local_list,
1184 channel = silc_idlist_find_channel_by_name(server->global_list,
1189 /* If router did not find such channel in its lists then this must
1190 be bogus channel or some router in the net is buggy. */
1191 if (server->server_type != SILC_SERVER)
1194 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1195 SILC_CHANNEL_MODE_NONE, channel_id,
1196 server->router, NULL, NULL,
1202 /* Found, update expiry */
1203 if (global_list && server->server_type == SILC_SERVER)
1204 cache->expire = time(NULL) + 60;
1208 silc_free(channel->topic);
1209 channel->topic = strdup(topic);
1212 /* Pending callbacks are not executed if this was an list entry */
1213 if (status != SILC_STATUS_OK &&
1214 status != SILC_STATUS_LIST_END) {
1215 silc_server_command_reply_free(cmd);
1219 /* Now purge all old entries from the global list, otherwise we'll might
1220 have non-existent entries for long periods of time in the cache. */
1221 silc_idcache_purge(server->global_list->channels);
1224 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1225 silc_free(channel_id);
1226 silc_server_command_reply_free(cmd);