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(entry->id, id))
899 silc_idlist_replace_channel_id(server->local_list, entry->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);
920 silc_free(entry->ban_list);
921 entry->ban_list = silc_calloc(len, sizeof(*entry->ban_list));
922 memcpy(entry->ban_list, tmp, len);
925 /* Get the invite list */
926 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
928 silc_free(entry->invite_list);
929 entry->invite_list = silc_calloc(len, sizeof(*entry->invite_list));
930 memcpy(entry->invite_list, tmp, len);
934 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
936 silc_free(entry->topic);
937 entry->topic = strdup(tmp);
940 /* If channel was not created we know there is global users on the
942 entry->global_users = (created == 0 ? TRUE : FALSE);
944 /* If channel was just created the mask must be zero */
945 if (!entry->global_users && mode) {
946 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
947 "new channel, forcing it to zero", cmd->sock->hostname));
951 /* Save channel mode */
954 /* Save channel key */
956 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
957 silc_server_save_channel_key(server, keyp, entry);
958 silc_buffer_free(keyp);
961 /* Save the users to the channel */
962 silc_server_save_users_on_channel(server, cmd->sock, entry,
963 client_id, client_id_list,
964 client_mode_list, list_count);
967 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
968 silc_free(client_id);
969 silc_server_command_reply_free(cmd);
972 silc_buffer_free(client_id_list);
973 if (client_mode_list)
974 silc_buffer_free(client_mode_list);
977 SILC_SERVER_CMD_REPLY_FUNC(users)
979 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
980 SilcServer server = cmd->server;
981 SilcCommandStatus status;
982 SilcChannelEntry channel;
983 SilcChannelID *channel_id = NULL;
984 SilcBuffer client_id_list;
985 SilcBuffer client_mode_list;
990 COMMAND_CHECK_STATUS;
993 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
996 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1000 /* Get channel entry */
1001 channel = silc_idlist_find_channel_by_id(server->local_list,
1004 channel = silc_idlist_find_channel_by_id(server->global_list,
1009 if (server->server_type != SILC_SERVER)
1012 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1013 silc_server_send_command(server, server->router->connection,
1014 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1015 1, 5, idp->data, idp->len);
1016 silc_buffer_free(idp);
1018 /* Register pending command callback. After we've received the channel
1019 information we will reprocess this command reply by re-calling this
1020 USERS command reply callback. */
1021 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1023 silc_server_command_reply_users, cmd);
1028 /* Get the list count */
1029 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1032 SILC_GET32_MSB(list_count, tmp);
1034 /* Get Client ID list */
1035 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1039 client_id_list = silc_buffer_alloc(tmp_len);
1040 silc_buffer_pull_tail(client_id_list, tmp_len);
1041 silc_buffer_put(client_id_list, tmp, tmp_len);
1043 /* Get client mode list */
1044 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1048 client_mode_list = silc_buffer_alloc(tmp_len);
1049 silc_buffer_pull_tail(client_mode_list, tmp_len);
1050 silc_buffer_put(client_mode_list, tmp, tmp_len);
1052 /* Save the users to the channel */
1053 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1054 client_id_list, client_mode_list,
1057 silc_buffer_free(client_id_list);
1058 silc_buffer_free(client_mode_list);
1061 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1062 silc_free(channel_id);
1063 silc_server_command_reply_free(cmd);
1066 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1068 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1069 SilcServer server = cmd->server;
1070 SilcCommandStatus status;
1071 SilcClientEntry client = NULL;
1072 SilcServerEntry server_entry = NULL;
1073 SilcClientID *client_id = NULL;
1074 SilcServerID *server_id = NULL;
1076 unsigned char *tmp, *pk;
1079 SilcIDPayload idp = NULL;
1081 SilcPublicKey public_key = NULL;
1083 COMMAND_CHECK_STATUS;
1085 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1088 idp = silc_id_payload_parse(tmp, len);
1092 /* Get the public key payload */
1093 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1097 /* Decode the public key */
1099 SILC_GET16_MSB(pk_len, tmp);
1100 SILC_GET16_MSB(type, tmp + 2);
1103 if (type != SILC_SKE_PK_TYPE_SILC)
1106 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1109 id_type = silc_id_payload_get_type(idp);
1110 if (id_type == SILC_ID_CLIENT) {
1111 client_id = silc_id_payload_get_id(idp);
1113 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1116 client = silc_idlist_find_client_by_id(server->global_list,
1117 client_id, TRUE, NULL);
1122 client->data.public_key = public_key;
1123 } else if (id_type == SILC_ID_SERVER) {
1124 server_id = silc_id_payload_get_id(idp);
1126 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1128 if (!server_entry) {
1129 server_entry = silc_idlist_find_server_by_id(server->global_list,
1130 server_id, TRUE, NULL);
1135 server_entry->data.public_key = public_key;
1141 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1143 silc_id_payload_free(idp);
1144 silc_free(client_id);
1145 silc_free(server_id);
1147 silc_pkcs_public_key_free(public_key);
1148 silc_server_command_reply_free(cmd);
1151 SILC_SERVER_CMD_REPLY_FUNC(list)
1153 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1154 SilcServer server = cmd->server;
1155 SilcCommandStatus status;
1156 SilcChannelID *channel_id = NULL;
1157 SilcChannelEntry channel;
1158 SilcIDCacheEntry cache;
1160 unsigned char *tmp, *name, *topic;
1161 uint32 usercount = 0;
1162 bool global_list = FALSE;
1164 COMMAND_CHECK_STATUS_LIST;
1166 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1167 channel_id = silc_id_payload_parse_id(tmp, len);
1171 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1172 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1173 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1175 SILC_GET32_MSB(usercount, tmp);
1177 /* Add the channel entry if we do not have it already */
1178 channel = silc_idlist_find_channel_by_name(server->local_list,
1181 channel = silc_idlist_find_channel_by_name(server->global_list,
1186 /* If router did not find such channel in its lists then this must
1187 be bogus channel or some router in the net is buggy. */
1188 if (server->server_type != SILC_SERVER)
1191 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1192 SILC_CHANNEL_MODE_NONE, channel_id,
1193 server->router, NULL, NULL,
1199 /* Found, update expiry */
1200 if (global_list && server->server_type == SILC_SERVER)
1201 cache->expire = time(NULL) + 60;
1204 channel->user_count = usercount;
1207 silc_free(channel->topic);
1208 channel->topic = strdup(topic);
1211 /* Pending callbacks are not executed if this was an list entry */
1212 if (status != SILC_STATUS_OK &&
1213 status != SILC_STATUS_LIST_END) {
1214 silc_server_command_reply_free(cmd);
1218 /* Now purge all old entries from the global list, otherwise we'll might
1219 have non-existent entries for long periods of time in the cache. */
1220 silc_idcache_purge(server->global_list->channels);
1223 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1224 silc_free(channel_id);
1225 silc_server_command_reply_free(cmd);