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);
826 id = silc_id_payload_parse_id(id_string, id_len);
831 tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
833 if (!silc_hmac_alloc(tmp, NULL, &hmac))
837 /* Get the list count */
838 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
841 SILC_GET32_MSB(list_count, tmp);
843 /* Get Client ID list */
844 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
848 client_id_list = silc_buffer_alloc(len);
849 silc_buffer_pull_tail(client_id_list, len);
850 silc_buffer_put(client_id_list, tmp, len);
852 /* Get client mode list */
853 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
857 client_mode_list = silc_buffer_alloc(len);
858 silc_buffer_pull_tail(client_mode_list, len);
859 silc_buffer_put(client_mode_list, tmp, len);
861 /* See whether we already have the channel. */
862 entry = silc_idlist_find_channel_by_name(server->local_list,
863 channel_name, &cache);
865 /* Add new channel */
867 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
868 (created == 0 ? "existing" : "created"), channel_name,
869 silc_id_render(id, SILC_ID_CHANNEL)));
871 /* If the channel is found from global list we must move it to the
873 entry = silc_idlist_find_channel_by_name(server->global_list,
874 channel_name, &cache);
877 silc_schedule_task_del_by_context(server->schedule, entry->rekey);
878 SILC_LOG_ERROR(("global_list->channels: entry->rekey != NULL, inform Pekka now!!!"));
880 silc_idlist_del_channel(server->global_list, entry);
883 /* Add the channel to our local list. */
884 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
885 SILC_CHANNEL_MODE_NONE, id,
886 server->router, NULL, hmac, 0);
891 server->stat.my_channels++;
893 /* The entry exists. */
894 silc_free(cache->id);
896 cache->id = entry->id;
897 entry->disabled = FALSE;
899 /* Remove the founder auth data if the mode is not set but we have
901 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
902 silc_pkcs_public_key_free(entry->founder_key);
903 if (entry->founder_passwd) {
904 silc_free(entry->founder_passwd);
905 entry->founder_passwd = NULL;
910 if (entry->hmac_name && hmac) {
911 silc_free(entry->hmac_name);
912 entry->hmac_name = strdup(silc_hmac_get_name(hmac));
915 /* Get the ban list */
916 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
919 silc_free(entry->ban_list);
920 entry->ban_list = silc_calloc(len, sizeof(*entry->ban_list));
921 memcpy(entry->ban_list, tmp, len);
924 /* Get the invite list */
925 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
927 if (entry->invite_list)
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);
937 silc_free(entry->topic);
938 entry->topic = strdup(tmp);
941 /* If channel was not created we know there is global users on the
943 entry->global_users = (created == 0 ? TRUE : FALSE);
945 /* If channel was just created the mask must be zero */
946 if (!entry->global_users && mode) {
947 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
948 "new channel, forcing it to zero", cmd->sock->hostname));
952 /* Save channel mode */
955 /* Save channel key */
957 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
958 silc_server_save_channel_key(server, keyp, entry);
959 silc_buffer_free(keyp);
962 /* Save the users to the channel */
963 silc_server_save_users_on_channel(server, cmd->sock, entry,
964 client_id, client_id_list,
965 client_mode_list, list_count);
968 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
969 silc_free(client_id);
970 silc_server_command_reply_free(cmd);
973 silc_buffer_free(client_id_list);
974 if (client_mode_list)
975 silc_buffer_free(client_mode_list);
978 SILC_SERVER_CMD_REPLY_FUNC(users)
980 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
981 SilcServer server = cmd->server;
982 SilcCommandStatus status;
983 SilcChannelEntry channel;
984 SilcChannelID *channel_id = NULL;
985 SilcBuffer client_id_list;
986 SilcBuffer client_mode_list;
991 COMMAND_CHECK_STATUS;
994 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
997 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
1001 /* Get channel entry */
1002 channel = silc_idlist_find_channel_by_id(server->local_list,
1005 channel = silc_idlist_find_channel_by_id(server->global_list,
1010 if (server->server_type != SILC_SERVER)
1013 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1014 silc_server_send_command(server, server->router->connection,
1015 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1016 1, 5, idp->data, idp->len);
1017 silc_buffer_free(idp);
1019 /* Register pending command callback. After we've received the channel
1020 information we will reprocess this command reply by re-calling this
1021 USERS command reply callback. */
1022 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1024 silc_server_command_reply_users, cmd);
1029 /* Get the list count */
1030 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1033 SILC_GET32_MSB(list_count, tmp);
1035 /* Get Client ID list */
1036 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1040 client_id_list = silc_buffer_alloc(tmp_len);
1041 silc_buffer_pull_tail(client_id_list, tmp_len);
1042 silc_buffer_put(client_id_list, tmp, tmp_len);
1044 /* Get client mode list */
1045 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1049 client_mode_list = silc_buffer_alloc(tmp_len);
1050 silc_buffer_pull_tail(client_mode_list, tmp_len);
1051 silc_buffer_put(client_mode_list, tmp, tmp_len);
1053 /* Save the users to the channel */
1054 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1055 client_id_list, client_mode_list,
1058 silc_buffer_free(client_id_list);
1059 silc_buffer_free(client_mode_list);
1062 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1063 silc_free(channel_id);
1064 silc_server_command_reply_free(cmd);
1067 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1069 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1070 SilcServer server = cmd->server;
1071 SilcCommandStatus status;
1072 SilcClientEntry client = NULL;
1073 SilcServerEntry server_entry = NULL;
1074 SilcClientID *client_id = NULL;
1075 SilcServerID *server_id = NULL;
1077 unsigned char *tmp, *pk;
1080 SilcIDPayload idp = NULL;
1082 SilcPublicKey public_key = NULL;
1084 COMMAND_CHECK_STATUS;
1086 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1089 idp = silc_id_payload_parse(tmp, len);
1093 /* Get the public key payload */
1094 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1098 /* Decode the public key */
1100 SILC_GET16_MSB(pk_len, tmp);
1101 SILC_GET16_MSB(type, tmp + 2);
1104 if (type != SILC_SKE_PK_TYPE_SILC)
1107 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1110 id_type = silc_id_payload_get_type(idp);
1111 if (id_type == SILC_ID_CLIENT) {
1112 client_id = silc_id_payload_get_id(idp);
1114 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1117 client = silc_idlist_find_client_by_id(server->global_list,
1118 client_id, TRUE, NULL);
1123 client->data.public_key = public_key;
1124 } else if (id_type == SILC_ID_SERVER) {
1125 server_id = silc_id_payload_get_id(idp);
1127 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1129 if (!server_entry) {
1130 server_entry = silc_idlist_find_server_by_id(server->global_list,
1131 server_id, TRUE, NULL);
1136 server_entry->data.public_key = public_key;
1142 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1144 silc_id_payload_free(idp);
1145 silc_free(client_id);
1146 silc_free(server_id);
1148 silc_pkcs_public_key_free(public_key);
1149 silc_server_command_reply_free(cmd);
1152 SILC_SERVER_CMD_REPLY_FUNC(list)
1154 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1155 SilcServer server = cmd->server;
1156 SilcCommandStatus status;
1157 SilcChannelID *channel_id = NULL;
1158 SilcChannelEntry channel;
1159 SilcIDCacheEntry cache;
1161 unsigned char *tmp, *name, *topic;
1162 uint32 usercount = 0;
1163 bool global_list = FALSE;
1165 COMMAND_CHECK_STATUS_LIST;
1167 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1168 channel_id = silc_id_payload_parse_id(tmp, len);
1172 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1173 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1174 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1176 SILC_GET32_MSB(usercount, tmp);
1178 /* Add the channel entry if we do not have it already */
1179 channel = silc_idlist_find_channel_by_name(server->local_list,
1182 channel = silc_idlist_find_channel_by_name(server->global_list,
1187 /* If router did not find such channel in its lists then this must
1188 be bogus channel or some router in the net is buggy. */
1189 if (server->server_type != SILC_SERVER)
1192 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1193 SILC_CHANNEL_MODE_NONE, channel_id,
1194 server->router, NULL, NULL,
1200 /* Found, update expiry */
1201 if (global_list && server->server_type == SILC_SERVER)
1202 cache->expire = time(NULL) + 60;
1206 silc_free(channel->topic);
1207 channel->topic = strdup(topic);
1210 /* Pending callbacks are not executed if this was an list entry */
1211 if (status != SILC_STATUS_OK &&
1212 status != SILC_STATUS_LIST_END) {
1213 silc_server_command_reply_free(cmd);
1217 /* Now purge all old entries from the global list, otherwise we'll might
1218 have non-existent entries for long periods of time in the cache. */
1219 silc_idcache_purge(server->global_list->channels);
1222 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1223 silc_free(channel_id);
1224 silc_server_command_reply_free(cmd);