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_idlist_del_client(server->global_list, client);
289 silc_free(client_id);
294 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
295 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
296 silc_server_command_reply_free(cmd);
299 /* Caches the received WHOWAS information for a short period of time. */
302 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
304 SilcServer server = cmd->server;
306 unsigned char *id_data;
307 char *nickname, *username, *realname, *servername = NULL;
308 SilcClientID *client_id;
309 SilcClientEntry client;
310 SilcIDCacheEntry cache = NULL;
314 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
315 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
316 username = silc_argument_get_arg_type(cmd->args, 4, &len);
317 if (!id_data || !nickname || !username)
320 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
322 client_id = silc_id_payload_parse_id(id_data, id_len);
326 /* Check if we have this client cached already. */
328 client = silc_idlist_find_client_by_id(server->local_list, client_id,
331 client = silc_idlist_find_client_by_id(server->global_list,
332 client_id, FALSE, &cache);
337 /* If router did not find such Client ID in its lists then this must
338 be bogus client or some router in the net is buggy. */
339 if (server->server_type != SILC_SERVER)
342 /* Take hostname out of nick string if it includes it. */
343 silc_parse_userfqdn(nickname, &nick, &servername);
345 /* We don't have that client anywhere, add it. The client is added
346 to global list since server didn't have it in the lists so it must be
348 client = silc_idlist_add_client(server->global_list, nick,
349 strdup(username), strdup(realname),
350 silc_id_dup(client_id, SILC_ID_CLIENT),
351 cmd->sock->user_data, NULL,
352 SILC_ID_CACHE_EXPIRE_DEF);
354 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
358 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
359 client->servername = servername;
361 /* We have the client already, update the data */
363 /* Take hostname out of nick string if it includes it. */
364 silc_parse_userfqdn(nickname, &nick, &servername);
366 silc_free(client->nickname);
367 silc_free(client->username);
369 client->nickname = nick;
370 client->username = strdup(username);
371 client->servername = servername;
373 /* Remove the old cache entry and create a new one */
374 silc_idcache_del_by_context(global ? server->global_list->clients :
375 server->local_list->clients, client);
376 silc_idcache_add(global ? server->global_list->clients :
377 server->local_list->clients, nick, client->id,
381 silc_free(client_id);
386 /* Received reply for WHOWAS command. Cache the client information only for
387 a short period of time. */
389 SILC_SERVER_CMD_REPLY_FUNC(whowas)
391 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
392 SilcCommandStatus status;
394 COMMAND_CHECK_STATUS_LIST;
396 if (!silc_server_command_reply_whowas_save(cmd))
399 /* Pending callbacks are not executed if this was an list entry */
400 if (status != SILC_STATUS_OK &&
401 status != SILC_STATUS_LIST_END) {
402 silc_server_command_reply_free(cmd);
407 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
408 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS);
409 silc_server_command_reply_free(cmd);
412 /* Caches the received IDENTIFY information. */
415 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
417 SilcServer server = cmd->server;
419 unsigned char *id_data;
421 SilcClientID *client_id = NULL;
422 SilcServerID *server_id = NULL;
423 SilcChannelID *channel_id = NULL;
424 SilcClientEntry client;
425 SilcServerEntry server_entry;
426 SilcChannelEntry channel;
429 SilcIDPayload idp = NULL;
433 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
436 idp = silc_id_payload_parse(id_data, id_len);
440 name = silc_argument_get_arg_type(cmd->args, 3, &len);
441 info = silc_argument_get_arg_type(cmd->args, 4, &len);
443 id_type = silc_id_payload_get_type(idp);
447 client_id = silc_id_payload_get_id(idp);
451 SILC_LOG_DEBUG(("Received client information"));
453 client = silc_idlist_find_client_by_id(server->local_list,
454 client_id, FALSE, NULL);
456 client = silc_idlist_find_client_by_id(server->global_list, client_id,
461 /* If router did not find such Client ID in its lists then this must
462 be bogus client or some router in the net is buggy. */
463 if (server->server_type != SILC_SERVER)
468 silc_parse_userfqdn(name, &nick, NULL);
470 /* We don't have that client anywhere, add it. The client is added
471 to global list since server didn't have it in the lists so it must be
473 client = silc_idlist_add_client(server->global_list, nick,
474 info ? strdup(info) : NULL, NULL,
475 client_id, cmd->sock->user_data, NULL,
478 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
481 client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
482 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
483 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
485 /* We have the client already, update the data */
487 SILC_LOG_DEBUG(("Updating client data"));
491 silc_parse_userfqdn(name, &nick, NULL);
493 /* Remove the old cache entry */
494 silc_idcache_del_by_context(global ? server->global_list->clients :
495 server->local_list->clients, client);
497 silc_free(client->nickname);
498 client->nickname = nick;
502 silc_free(client->username);
503 client->username = strdup(info);
506 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
507 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
510 /* If client is global and is not on any channel then add that we'll
511 expire the entry after a while. */
512 if (global && !silc_hash_table_count(client->channels) &&
513 server->server_type == SILC_SERVER)
514 expire = time(NULL) + 300;
516 /* Add new cache entry */
517 silc_idcache_add(global ? server->global_list->clients :
518 server->local_list->clients, nick, client->id,
519 client, expire, NULL);
522 silc_free(client_id);
531 server_id = silc_id_payload_get_id(idp);
535 SILC_LOG_DEBUG(("Received server information"));
537 server_entry = silc_idlist_find_server_by_id(server->local_list,
538 server_id, FALSE, NULL);
540 server_entry = silc_idlist_find_server_by_id(server->global_list,
541 server_id, FALSE, NULL);
543 /* If router did not find such Server ID in its lists then this must
544 be bogus server or some router in the net is buggy. */
545 if (server->server_type != SILC_SERVER)
548 /* We don't have that server anywhere, add it. */
549 server_entry = silc_idlist_add_server(server->global_list,
551 server_id, NULL, NULL);
553 silc_free(server_id);
556 server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
557 server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
558 server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
562 silc_free(server_id);
565 case SILC_ID_CHANNEL:
569 channel_id = silc_id_payload_get_id(idp);
573 SILC_LOG_DEBUG(("Received channel information"));
575 channel = silc_idlist_find_channel_by_name(server->local_list,
578 channel = silc_idlist_find_channel_by_name(server->global_list,
581 /* If router did not find such Channel ID in its lists then this must
582 be bogus channel or some router in the net is buggy. */
583 if (server->server_type != SILC_SERVER)
586 /* We don't have that server anywhere, add it. */
587 channel = silc_idlist_add_channel(server->global_list, strdup(name),
588 SILC_CHANNEL_MODE_NONE, channel_id,
589 server->router, NULL, NULL, 0);
591 silc_free(channel_id);
597 silc_free(channel_id);
601 silc_id_payload_free(idp);
605 silc_id_payload_free(idp);
609 /* Received reply for forwarded IDENTIFY command. We have received the
610 requested identify information now and we will cache it. After this we
611 will call the pending command so that the requestee gets the information
614 SILC_SERVER_CMD_REPLY_FUNC(identify)
616 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
617 SilcServer server = cmd->server;
618 SilcCommandStatus status;
620 COMMAND_CHECK_STATUS_LIST;
622 if (!silc_server_command_reply_identify_save(cmd))
625 /* Pending callbacks are not executed if this was an list entry */
626 if (status != SILC_STATUS_OK &&
627 status != SILC_STATUS_LIST_END) {
628 silc_server_command_reply_free(cmd);
633 /* If we received notify for invalid ID we'll remove the ID if we
635 if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
636 cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
637 SilcClientEntry client;
639 unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
641 SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len);
643 SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
644 "the entry from cache"));
645 client = silc_idlist_find_client_by_id(server->global_list,
646 client_id, FALSE, NULL);
648 silc_idlist_del_client(server->global_list, client);
649 silc_free(client_id);
654 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
655 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
656 silc_server_command_reply_free(cmd);
659 /* Received reply fro INFO command. Cache the server and its information */
661 SILC_SERVER_CMD_REPLY_FUNC(info)
663 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
664 SilcServer server = cmd->server;
665 SilcCommandStatus status;
666 SilcServerEntry entry;
667 SilcServerID *server_id;
669 unsigned char *tmp, *name;
671 COMMAND_CHECK_STATUS;
674 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
677 server_id = silc_id_payload_parse_id(tmp, tmp_len);
682 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
686 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
689 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
692 /* Add the server to global list */
693 server_id = silc_id_dup(server_id, SILC_ID_SERVER);
694 entry = silc_idlist_add_server(server->global_list, name, 0,
695 server_id, NULL, NULL);
697 silc_free(server_id);
700 entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
704 /* Get the info string */
705 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
709 entry->server_info = tmp ? strdup(tmp) : NULL;
712 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
713 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
714 silc_server_command_reply_free(cmd);
717 /* Received reply fro MOTD command. */
719 SILC_SERVER_CMD_REPLY_FUNC(motd)
721 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
722 SilcServer server = cmd->server;
723 SilcCommandStatus status;
724 SilcServerEntry entry = NULL;
725 SilcServerID *server_id;
729 COMMAND_CHECK_STATUS;
732 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
735 server_id = silc_id_payload_parse_id(tmp, tmp_len);
739 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
742 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
749 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
756 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
757 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
758 silc_server_command_reply_free(cmd);
764 /* Received reply for forwarded JOIN command. Router has created or joined
765 the client to the channel. We save some channel information locally
768 SILC_SERVER_CMD_REPLY_FUNC(join)
770 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
771 SilcServer server = cmd->server;
772 SilcIDCacheEntry cache = NULL;
773 SilcCommandStatus status;
775 SilcClientID *client_id = NULL;
776 SilcChannelEntry entry;
777 SilcHmac hmac = NULL;
778 uint32 id_len, len, list_count;
779 unsigned char *id_string;
780 char *channel_name, *tmp;
781 uint32 mode, created;
782 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
784 COMMAND_CHECK_STATUS;
786 /* Get channel name */
787 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
792 id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
797 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
800 client_id = silc_id_payload_parse_id(tmp, len);
805 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
808 SILC_GET32_MSB(mode, tmp);
810 /* Get created boolean value */
811 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
814 SILC_GET32_MSB(created, tmp);
815 if (created != 0 && created != 1)
818 /* Get channel key */
819 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
821 keyp = silc_buffer_alloc(len);
822 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
823 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);
876 silc_idlist_del_channel(server->global_list, entry);
878 /* Add the channel to our local list. */
879 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
880 SILC_CHANNEL_MODE_NONE, id,
881 server->router, NULL, hmac, 0);
886 server->stat.my_channels++;
888 /* The entry exists. */
889 silc_free(cache->id);
891 cache->id = entry->id;
892 entry->disabled = FALSE;
894 /* Remove the founder auth data if the mode is not set but we have
896 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
897 silc_pkcs_public_key_free(entry->founder_key);
898 if (entry->founder_passwd) {
899 silc_free(entry->founder_passwd);
900 entry->founder_passwd = NULL;
905 if (entry->hmac_name && hmac) {
906 silc_free(entry->hmac_name);
907 entry->hmac_name = strdup(silc_hmac_get_name(hmac));
910 /* Get the ban list */
911 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
914 silc_free(entry->ban_list);
915 entry->ban_list = silc_calloc(len, sizeof(*entry->ban_list));
916 memcpy(entry->ban_list, tmp, len);
919 /* Get the invite list */
920 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
922 if (entry->invite_list)
923 silc_free(entry->invite_list);
924 entry->invite_list = silc_calloc(len, sizeof(*entry->invite_list));
925 memcpy(entry->invite_list, tmp, len);
929 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
932 silc_free(entry->topic);
933 entry->topic = strdup(tmp);
936 /* If channel was not created we know there is global users on the
938 entry->global_users = (created == 0 ? TRUE : FALSE);
940 /* If channel was just created the mask must be zero */
941 if (!entry->global_users && mode) {
942 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
943 "new channel, forcing it to zero", cmd->sock->hostname));
947 /* Save channel mode */
950 /* Save channel key */
951 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
952 silc_server_save_channel_key(server, keyp, entry);
954 silc_buffer_free(keyp);
956 /* Save the users to the channel */
957 silc_server_save_users_on_channel(server, cmd->sock, entry,
958 client_id, client_id_list,
959 client_mode_list, list_count);
962 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
963 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
964 silc_free(client_id);
965 silc_server_command_reply_free(cmd);
968 silc_buffer_free(client_id_list);
969 if (client_mode_list)
970 silc_buffer_free(client_mode_list);
973 SILC_SERVER_CMD_REPLY_FUNC(users)
975 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
976 SilcServer server = cmd->server;
977 SilcCommandStatus status;
978 SilcChannelEntry channel;
979 SilcChannelID *channel_id = NULL;
980 SilcBuffer client_id_list;
981 SilcBuffer client_mode_list;
986 COMMAND_CHECK_STATUS;
989 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
992 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
996 /* Get channel entry */
997 channel = silc_idlist_find_channel_by_id(server->local_list,
1000 channel = silc_idlist_find_channel_by_id(server->global_list,
1005 if (server->server_type != SILC_SERVER)
1008 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
1009 silc_server_send_command(server, server->router->connection,
1010 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
1011 1, 5, idp->data, idp->len);
1012 silc_buffer_free(idp);
1014 /* Register pending command callback. After we've received the channel
1015 information we will reprocess this command reply by re-calling this
1016 USERS command reply callback. */
1017 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
1019 NULL, silc_server_command_reply_users, cmd);
1024 /* Get the list count */
1025 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
1028 SILC_GET32_MSB(list_count, tmp);
1030 /* Get Client ID list */
1031 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
1035 client_id_list = silc_buffer_alloc(tmp_len);
1036 silc_buffer_pull_tail(client_id_list, tmp_len);
1037 silc_buffer_put(client_id_list, tmp, tmp_len);
1039 /* Get client mode list */
1040 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
1044 client_mode_list = silc_buffer_alloc(tmp_len);
1045 silc_buffer_pull_tail(client_mode_list, tmp_len);
1046 silc_buffer_put(client_mode_list, tmp, tmp_len);
1048 /* Save the users to the channel */
1049 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
1050 client_id_list, client_mode_list,
1053 silc_buffer_free(client_id_list);
1054 silc_buffer_free(client_mode_list);
1057 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1058 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1059 silc_free(channel_id);
1060 silc_server_command_reply_free(cmd);
1063 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1065 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1066 SilcServer server = cmd->server;
1067 SilcCommandStatus status;
1068 SilcClientEntry client = NULL;
1069 SilcServerEntry server_entry = NULL;
1070 SilcClientID *client_id = NULL;
1071 SilcServerID *server_id = NULL;
1073 unsigned char *tmp, *pk;
1076 SilcIDPayload idp = NULL;
1078 SilcPublicKey public_key = NULL;
1080 COMMAND_CHECK_STATUS;
1082 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1085 idp = silc_id_payload_parse(tmp, len);
1089 /* Get the public key payload */
1090 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1094 /* Decode the public key */
1096 SILC_GET16_MSB(pk_len, tmp);
1097 SILC_GET16_MSB(type, tmp + 2);
1100 if (type != SILC_SKE_PK_TYPE_SILC)
1103 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1106 id_type = silc_id_payload_get_type(idp);
1107 if (id_type == SILC_ID_CLIENT) {
1108 client_id = silc_id_payload_get_id(idp);
1110 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1113 client = silc_idlist_find_client_by_id(server->global_list,
1114 client_id, TRUE, NULL);
1119 client->data.public_key = public_key;
1120 } else if (id_type == SILC_ID_SERVER) {
1121 server_id = silc_id_payload_get_id(idp);
1123 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1125 if (!server_entry) {
1126 server_entry = silc_idlist_find_server_by_id(server->global_list,
1127 server_id, TRUE, NULL);
1132 server_entry->data.public_key = public_key;
1138 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1139 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1141 silc_id_payload_free(idp);
1142 silc_free(client_id);
1143 silc_free(server_id);
1145 silc_pkcs_public_key_free(public_key);
1146 silc_server_command_reply_free(cmd);
1149 SILC_SERVER_CMD_REPLY_FUNC(list)
1151 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1152 SilcServer server = cmd->server;
1153 SilcCommandStatus status;
1154 SilcChannelID *channel_id = NULL;
1155 SilcChannelEntry channel;
1156 SilcIDCacheEntry cache;
1158 unsigned char *tmp, *name, *topic;
1159 uint32 usercount = 0;
1160 bool global_list = FALSE;
1162 COMMAND_CHECK_STATUS_LIST;
1164 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1165 channel_id = silc_id_payload_parse_id(tmp, len);
1169 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1170 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1171 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1173 SILC_GET32_MSB(usercount, tmp);
1175 /* Add the channel entry if we do not have it already */
1176 channel = silc_idlist_find_channel_by_name(server->local_list,
1179 channel = silc_idlist_find_channel_by_name(server->global_list,
1184 /* If router did not find such channel in its lists then this must
1185 be bogus channel or some router in the net is buggy. */
1186 if (server->server_type != SILC_SERVER)
1189 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1190 SILC_CHANNEL_MODE_NONE, channel_id,
1191 server->router, NULL, NULL,
1197 /* Found, update expiry */
1198 if (global_list && server->server_type == SILC_SERVER)
1199 cache->expire = time(NULL) + 60;
1203 silc_free(channel->topic);
1204 channel->topic = strdup(topic);
1207 /* Pending callbacks are not executed if this was an list entry */
1208 if (status != SILC_STATUS_OK &&
1209 status != SILC_STATUS_LIST_END) {
1210 silc_server_command_reply_free(cmd);
1214 /* Now purge all old entries from the global list, otherwise we'll might
1215 have non-existent entries for long periods of time in the cache. */
1216 silc_idcache_purge(server->global_list->channels);
1219 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1220 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
1221 silc_free(channel_id);
1222 silc_server_command_reply_free(cmd);