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;
144 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
145 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
146 username = silc_argument_get_arg_type(cmd->args, 4, &len);
147 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
148 if (!id_data || !nickname || !username || !realname) {
149 SILC_LOG_ERROR(("Incomplete WHOIS info: %s %s %s",
150 nickname ? nickname : "",
151 username ? username : "",
152 realname ? realname : ""));
156 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
158 SILC_GET32_MSB(mode, tmp);
160 client_id = silc_id_payload_parse_id(id_data, id_len);
164 fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);
166 /* Check if we have this client cached already. */
168 client = silc_idlist_find_client_by_id(server->local_list, client_id,
171 client = silc_idlist_find_client_by_id(server->global_list, client_id,
177 /* If router did not find such Client ID in its lists then this must
178 be bogus client or some router in the net is buggy. */
179 if (server->server_type != SILC_SERVER)
182 /* Take hostname out of nick string if it includes it. */
183 silc_parse_userfqdn(nickname, &nick, &servername);
185 /* We don't have that client anywhere, add it. The client is added
186 to global list since server didn't have it in the lists so it must be
188 client = silc_idlist_add_client(server->global_list, nick,
190 strdup(realname), client_id,
191 cmd->sock->user_data, NULL);
193 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
197 client->data.status |=
198 (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
199 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
201 client->servername = servername;
203 /* We have the client already, update the data */
205 SILC_LOG_DEBUG(("Updating client data"));
207 /* Take hostname out of nick string if it includes it. */
208 silc_parse_userfqdn(nickname, &nick, &servername);
210 /* Remove the old cache entry */
211 silc_idcache_del_by_context(global ? server->global_list->clients :
212 server->local_list->clients, client);
214 silc_free(client->nickname);
215 silc_free(client->username);
216 silc_free(client->userinfo);
217 silc_free(client->servername);
219 client->nickname = nick;
220 client->username = strdup(username);
221 client->userinfo = strdup(realname);
222 client->servername = servername;
224 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
225 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
227 /* Create new cache entry */
228 silc_idcache_add(global ? server->global_list->clients :
229 server->local_list->clients, nick, client->id,
231 silc_free(client_id);
234 if (fingerprint && flen == sizeof(client->data.fingerprint))
235 memcpy(client->data.fingerprint, fingerprint, flen);
240 /* Reiceved reply for WHOIS command. We sent the whois request to our
241 primary router, if we are normal server, and thus has now received reply
242 to the command. We will figure out what client originally sent us the
243 command and will send the reply to it. If we are router we will figure
244 out who server sent us the command and send reply to that one. */
246 SILC_SERVER_CMD_REPLY_FUNC(whois)
248 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
249 SilcCommandStatus status;
251 COMMAND_CHECK_STATUS_LIST;
253 if (!silc_server_command_reply_whois_save(cmd))
256 /* Pending callbacks are not executed if this was an list entry */
257 if (status != SILC_STATUS_OK &&
258 status != SILC_STATUS_LIST_END) {
259 silc_server_command_reply_free(cmd);
264 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
265 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOIS);
266 silc_server_command_reply_free(cmd);
269 /* Caches the received WHOWAS information for a short period of time. */
272 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
274 SilcServer server = cmd->server;
276 unsigned char *id_data;
277 char *nickname, *username, *realname, *servername = NULL;
278 SilcClientID *client_id;
279 SilcClientEntry client;
280 SilcIDCacheEntry cache = NULL;
284 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
285 nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
286 username = silc_argument_get_arg_type(cmd->args, 4, &len);
287 if (!id_data || !nickname || !username)
290 realname = silc_argument_get_arg_type(cmd->args, 5, &len);
292 client_id = silc_id_payload_parse_id(id_data, id_len);
296 /* Check if we have this client cached already. */
298 client = silc_idlist_find_client_by_id(server->local_list, client_id,
301 client = silc_idlist_find_client_by_id(server->global_list,
302 client_id, FALSE, &cache);
307 /* If router did not find such Client ID in its lists then this must
308 be bogus client or some router in the net is buggy. */
309 if (server->server_type != SILC_SERVER)
312 /* Take hostname out of nick string if it includes it. */
313 silc_parse_userfqdn(nickname, &nick, &servername);
315 /* We don't have that client anywhere, add it. The client is added
316 to global list since server didn't have it in the lists so it must be
318 client = silc_idlist_add_client(server->global_list, nick,
319 strdup(username), strdup(realname),
320 silc_id_dup(client_id, SILC_ID_CLIENT),
321 cmd->sock->user_data, NULL);
323 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
327 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
328 client = silc_idlist_find_client_by_id(server->global_list,
329 client_id, TRUE, &cache);
330 cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
331 client->servername = servername;
333 /* We have the client already, update the data */
335 /* Take hostname out of nick string if it includes it. */
336 silc_parse_userfqdn(nickname, &nick, &servername);
338 silc_free(client->nickname);
339 silc_free(client->username);
341 client->nickname = nick;
342 client->username = strdup(username);
343 client->servername = servername;
345 /* Remove the old cache entry and create a new one */
346 silc_idcache_del_by_context(global ? server->global_list->clients :
347 server->local_list->clients, client);
348 silc_idcache_add(global ? server->global_list->clients :
349 server->local_list->clients, nick, client->id,
353 silc_free(client_id);
358 /* Received reply for WHOWAS command. Cache the client information only for
359 a short period of time. */
361 SILC_SERVER_CMD_REPLY_FUNC(whowas)
363 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
364 SilcCommandStatus status;
366 COMMAND_CHECK_STATUS_LIST;
368 if (!silc_server_command_reply_whowas_save(cmd))
371 /* Pending callbacks are not executed if this was an list entry */
372 if (status != SILC_STATUS_OK &&
373 status != SILC_STATUS_LIST_END) {
374 silc_server_command_reply_free(cmd);
379 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
380 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_WHOWAS);
381 silc_server_command_reply_free(cmd);
384 /* Caches the received IDENTIFY information. */
387 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
389 SilcServer server = cmd->server;
391 unsigned char *id_data;
393 SilcClientID *client_id = NULL;
394 SilcServerID *server_id = NULL;
395 SilcChannelID *channel_id = NULL;
396 SilcClientEntry client;
397 SilcServerEntry server_entry;
398 SilcChannelEntry channel;
401 SilcIDPayload idp = NULL;
404 id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
407 idp = silc_id_payload_parse(id_data, id_len);
411 name = silc_argument_get_arg_type(cmd->args, 3, &len);
412 info = silc_argument_get_arg_type(cmd->args, 4, &len);
414 id_type = silc_id_payload_get_type(idp);
418 client_id = silc_id_payload_get_id(idp);
422 SILC_LOG_DEBUG(("Received client information"));
424 client = silc_idlist_find_client_by_id(server->local_list,
425 client_id, FALSE, NULL);
427 client = silc_idlist_find_client_by_id(server->global_list, client_id,
432 /* If router did not find such Client ID in its lists then this must
433 be bogus client or some router in the net is buggy. */
434 if (server->server_type != SILC_SERVER)
439 silc_parse_userfqdn(name, &nick, NULL);
441 /* We don't have that client anywhere, add it. The client is added
442 to global list since server didn't have it in the lists so it must be
444 client = silc_idlist_add_client(server->global_list, nick,
445 info ? strdup(info) : NULL, NULL,
446 client_id, cmd->sock->user_data, NULL);
448 SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
451 client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
452 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
453 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
455 /* We have the client already, update the data */
457 SILC_LOG_DEBUG(("Updating client data"));
461 silc_parse_userfqdn(name, &nick, NULL);
463 /* Remove the old cache entry */
464 silc_idcache_del_by_context(global ? server->global_list->clients :
465 server->local_list->clients, client);
467 silc_free(client->nickname);
468 client->nickname = nick;
472 silc_free(client->username);
473 client->username = strdup(info);
476 client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
477 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
480 /* Add new cache entry */
481 silc_idcache_add(global ? server->global_list->clients :
482 server->local_list->clients, nick, client->id,
486 silc_free(client_id);
495 server_id = silc_id_payload_get_id(idp);
499 SILC_LOG_DEBUG(("Received server information"));
501 server_entry = silc_idlist_find_server_by_id(server->local_list,
502 server_id, FALSE, NULL);
504 server_entry = silc_idlist_find_server_by_id(server->global_list,
505 server_id, FALSE, NULL);
507 /* If router did not find such Server ID in its lists then this must
508 be bogus server or some router in the net is buggy. */
509 if (server->server_type != SILC_SERVER)
512 /* We don't have that server anywhere, add it. */
513 server_entry = silc_idlist_add_server(server->global_list,
515 server_id, NULL, NULL);
517 silc_free(server_id);
520 server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
521 server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
522 server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
526 silc_free(server_id);
529 case SILC_ID_CHANNEL:
533 channel_id = silc_id_payload_get_id(idp);
537 SILC_LOG_DEBUG(("Received channel information"));
539 channel = silc_idlist_find_channel_by_name(server->local_list,
542 channel = silc_idlist_find_channel_by_name(server->global_list,
545 /* If router did not find such Channel ID in its lists then this must
546 be bogus channel or some router in the net is buggy. */
547 if (server->server_type != SILC_SERVER)
550 /* We don't have that server anywhere, add it. */
551 channel = silc_idlist_add_channel(server->global_list, strdup(name),
552 SILC_CHANNEL_MODE_NONE, channel_id,
556 silc_free(channel_id);
562 silc_free(channel_id);
566 silc_id_payload_free(idp);
570 silc_id_payload_free(idp);
574 /* Received reply for forwarded IDENTIFY command. We have received the
575 requested identify information now and we will cache it. After this we
576 will call the pending command so that the requestee gets the information
579 SILC_SERVER_CMD_REPLY_FUNC(identify)
581 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
582 SilcCommandStatus status;
584 COMMAND_CHECK_STATUS_LIST;
586 if (!silc_server_command_reply_identify_save(cmd))
589 /* Pending callbacks are not executed if this was an list entry */
590 if (status != SILC_STATUS_OK &&
591 status != SILC_STATUS_LIST_END) {
592 silc_server_command_reply_free(cmd);
597 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
598 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_IDENTIFY);
599 silc_server_command_reply_free(cmd);
602 /* Received reply fro INFO command. Cache the server and its information */
604 SILC_SERVER_CMD_REPLY_FUNC(info)
606 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
607 SilcServer server = cmd->server;
608 SilcCommandStatus status;
609 SilcServerEntry entry;
610 SilcServerID *server_id;
612 unsigned char *tmp, *name;
614 COMMAND_CHECK_STATUS;
617 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
620 server_id = silc_id_payload_parse_id(tmp, tmp_len);
625 name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
629 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
632 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
635 /* Add the server to global list */
636 server_id = silc_id_dup(server_id, SILC_ID_SERVER);
637 entry = silc_idlist_add_server(server->global_list, name, 0,
638 server_id, NULL, NULL);
640 silc_free(server_id);
643 entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
647 /* Get the info string */
648 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
652 entry->server_info = tmp ? strdup(tmp) : NULL;
655 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
656 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INFO);
657 silc_server_command_reply_free(cmd);
660 /* Received reply fro MOTD command. */
662 SILC_SERVER_CMD_REPLY_FUNC(motd)
664 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
665 SilcServer server = cmd->server;
666 SilcCommandStatus status;
667 SilcServerEntry entry = NULL;
668 SilcServerID *server_id;
672 COMMAND_CHECK_STATUS;
675 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
678 server_id = silc_id_payload_parse_id(tmp, tmp_len);
682 entry = silc_idlist_find_server_by_id(server->local_list, server_id,
685 entry = silc_idlist_find_server_by_id(server->global_list, server_id,
692 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
699 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
700 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
701 silc_server_command_reply_free(cmd);
707 /* Received reply for forwarded JOIN command. Router has created or joined
708 the client to the channel. We save some channel information locally
711 SILC_SERVER_CMD_REPLY_FUNC(join)
713 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
714 SilcServer server = cmd->server;
715 SilcIDCacheEntry cache = NULL;
716 SilcCommandStatus status;
718 SilcClientID *client_id = NULL;
719 SilcChannelEntry entry;
720 SilcHmac hmac = NULL;
721 uint32 id_len, len, list_count;
722 unsigned char *id_string;
723 char *channel_name, *tmp;
724 uint32 mode, created;
725 SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
727 COMMAND_CHECK_STATUS;
729 /* Get channel name */
730 channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
735 id_string = silc_argument_get_arg_type(cmd->args, 3, &id_len);
740 tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
743 client_id = silc_id_payload_parse_id(tmp, len);
748 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
751 SILC_GET32_MSB(mode, tmp);
753 /* Get created boolean value */
754 tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
757 SILC_GET32_MSB(created, tmp);
758 if (created != 0 && created != 1)
761 /* Get channel key */
762 tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
764 keyp = silc_buffer_alloc(len);
765 silc_buffer_pull_tail(keyp, SILC_BUFFER_END(keyp));
766 silc_buffer_put(keyp, tmp, len);
769 id = silc_id_payload_parse_id(id_string, id_len);
774 tmp = silc_argument_get_arg_type(cmd->args, 11, NULL);
776 if (!silc_hmac_alloc(tmp, NULL, &hmac))
780 /* Get the list count */
781 tmp = silc_argument_get_arg_type(cmd->args, 12, &len);
784 SILC_GET32_MSB(list_count, tmp);
786 /* Get Client ID list */
787 tmp = silc_argument_get_arg_type(cmd->args, 13, &len);
791 client_id_list = silc_buffer_alloc(len);
792 silc_buffer_pull_tail(client_id_list, len);
793 silc_buffer_put(client_id_list, tmp, len);
795 /* Get client mode list */
796 tmp = silc_argument_get_arg_type(cmd->args, 14, &len);
800 client_mode_list = silc_buffer_alloc(len);
801 silc_buffer_pull_tail(client_mode_list, len);
802 silc_buffer_put(client_mode_list, tmp, len);
804 /* See whether we already have the channel. */
805 entry = silc_idlist_find_channel_by_name(server->local_list,
806 channel_name, &cache);
808 /* Add new channel */
810 SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
811 (created == 0 ? "existing" : "created"), channel_name,
812 silc_id_render(id, SILC_ID_CHANNEL)));
814 /* If the channel is found from global list we must move it to the
816 entry = silc_idlist_find_channel_by_name(server->global_list,
817 channel_name, &cache);
819 silc_idlist_del_channel(server->global_list, entry);
821 /* Add the channel to our local list. */
822 entry = silc_idlist_add_channel(server->local_list, strdup(channel_name),
823 SILC_CHANNEL_MODE_NONE, id,
824 server->router, NULL, hmac);
829 server->stat.my_channels++;
831 /* The entry exists. */
832 silc_free(cache->id);
834 cache->id = entry->id;
835 entry->disabled = FALSE;
837 /* Remove the founder auth data if the mode is not set but we have
839 if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
840 silc_pkcs_public_key_free(entry->founder_key);
841 if (entry->founder_passwd) {
842 silc_free(entry->founder_passwd);
843 entry->founder_passwd = NULL;
848 if (entry->hmac_name && hmac) {
849 silc_free(entry->hmac_name);
850 entry->hmac_name = strdup(silc_hmac_get_name(hmac));
853 /* Get the ban list */
854 tmp = silc_argument_get_arg_type(cmd->args, 8, &len);
857 silc_free(entry->ban_list);
858 entry->ban_list = silc_calloc(len, sizeof(*entry->ban_list));
859 memcpy(entry->ban_list, tmp, len);
862 /* Get the invite list */
863 tmp = silc_argument_get_arg_type(cmd->args, 9, &len);
865 if (entry->invite_list)
866 silc_free(entry->invite_list);
867 entry->invite_list = silc_calloc(len, sizeof(*entry->invite_list));
868 memcpy(entry->invite_list, tmp, len);
872 tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
875 silc_free(entry->topic);
876 entry->topic = strdup(tmp);
879 /* If channel was not created we know there is global users on the
881 entry->global_users = (created == 0 ? TRUE : FALSE);
883 /* If channel was just created the mask must be zero */
884 if (!entry->global_users && mode) {
885 SILC_LOG_DEBUG(("Buggy router `%s' sent non-zero mode mask for "
886 "new channel, forcing it to zero", cmd->sock->hostname));
890 /* Save channel mode */
893 /* Save channel key */
894 if (!(entry->mode & SILC_CHANNEL_MODE_PRIVKEY))
895 silc_server_save_channel_key(server, keyp, entry);
897 silc_buffer_free(keyp);
899 /* Save the users to the channel */
900 silc_server_save_users_on_channel(server, cmd->sock, entry,
901 client_id, client_id_list,
902 client_mode_list, list_count);
905 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
906 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_JOIN);
907 silc_free(client_id);
908 silc_server_command_reply_free(cmd);
911 silc_buffer_free(client_id_list);
912 if (client_mode_list)
913 silc_buffer_free(client_mode_list);
916 SILC_SERVER_CMD_REPLY_FUNC(users)
918 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
919 SilcServer server = cmd->server;
920 SilcCommandStatus status;
921 SilcChannelEntry channel;
922 SilcChannelID *channel_id = NULL;
923 SilcBuffer client_id_list;
924 SilcBuffer client_mode_list;
929 COMMAND_CHECK_STATUS;
932 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
935 channel_id = silc_id_payload_parse_id(tmp, tmp_len);
939 /* Get channel entry */
940 channel = silc_idlist_find_channel_by_id(server->local_list,
943 channel = silc_idlist_find_channel_by_id(server->global_list,
948 if (server->server_type != SILC_SERVER)
951 idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
952 silc_server_send_command(server, server->router->connection,
953 SILC_COMMAND_IDENTIFY, ++server->cmd_ident,
954 1, 5, idp->data, idp->len);
955 silc_buffer_free(idp);
957 /* Register pending command callback. After we've received the channel
958 information we will reprocess this command reply by re-calling this
959 USERS command reply callback. */
960 silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
962 NULL, silc_server_command_reply_users, cmd);
967 /* Get the list count */
968 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
971 SILC_GET32_MSB(list_count, tmp);
973 /* Get Client ID list */
974 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
978 client_id_list = silc_buffer_alloc(tmp_len);
979 silc_buffer_pull_tail(client_id_list, tmp_len);
980 silc_buffer_put(client_id_list, tmp, tmp_len);
982 /* Get client mode list */
983 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
987 client_mode_list = silc_buffer_alloc(tmp_len);
988 silc_buffer_pull_tail(client_mode_list, tmp_len);
989 silc_buffer_put(client_mode_list, tmp, tmp_len);
991 /* Save the users to the channel */
992 silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
993 client_id_list, client_mode_list,
996 silc_buffer_free(client_id_list);
997 silc_buffer_free(client_mode_list);
1000 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
1001 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_USERS);
1002 silc_free(channel_id);
1003 silc_server_command_reply_free(cmd);
1006 SILC_SERVER_CMD_REPLY_FUNC(getkey)
1008 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1009 SilcServer server = cmd->server;
1010 SilcCommandStatus status;
1011 SilcClientEntry client = NULL;
1012 SilcServerEntry server_entry = NULL;
1013 SilcClientID *client_id = NULL;
1014 SilcServerID *server_id = NULL;
1016 unsigned char *tmp, *pk;
1019 SilcIDPayload idp = NULL;
1021 SilcPublicKey public_key = NULL;
1023 COMMAND_CHECK_STATUS;
1025 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1028 idp = silc_id_payload_parse(tmp, len);
1032 /* Get the public key payload */
1033 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1037 /* Decode the public key */
1039 SILC_GET16_MSB(pk_len, tmp);
1040 SILC_GET16_MSB(type, tmp + 2);
1043 if (type != SILC_SKE_PK_TYPE_SILC)
1046 if (!silc_pkcs_public_key_decode(pk, pk_len, &public_key))
1049 id_type = silc_id_payload_get_type(idp);
1050 if (id_type == SILC_ID_CLIENT) {
1051 client_id = silc_id_payload_get_id(idp);
1053 client = silc_idlist_find_client_by_id(server->local_list, client_id,
1056 client = silc_idlist_find_client_by_id(server->global_list,
1057 client_id, TRUE, NULL);
1062 client->data.public_key = public_key;
1063 } else if (id_type == SILC_ID_SERVER) {
1064 server_id = silc_id_payload_get_id(idp);
1066 server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
1068 if (!server_entry) {
1069 server_entry = silc_idlist_find_server_by_id(server->global_list,
1070 server_id, TRUE, NULL);
1075 server_entry->data.public_key = public_key;
1081 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_GETKEY);
1082 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_GETKEY);
1084 silc_id_payload_free(idp);
1085 silc_free(client_id);
1086 silc_free(server_id);
1088 silc_pkcs_public_key_free(public_key);
1089 silc_server_command_reply_free(cmd);
1092 SILC_SERVER_CMD_REPLY_FUNC(list)
1094 SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1095 SilcServer server = cmd->server;
1096 SilcCommandStatus status;
1097 SilcChannelID *channel_id = NULL;
1098 SilcChannelEntry channel;
1099 SilcIDCacheEntry cache;
1101 unsigned char *tmp, *name, *topic;
1102 uint32 usercount = 0;
1104 COMMAND_CHECK_STATUS_LIST;
1106 tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
1107 channel_id = silc_id_payload_parse_id(tmp, len);
1111 name = silc_argument_get_arg_type(cmd->args, 3, NULL);
1112 topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
1113 tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
1115 SILC_GET32_MSB(usercount, tmp);
1117 /* Add the channel entry if we do not have it already */
1118 channel = silc_idlist_find_channel_by_name(server->local_list,
1121 channel = silc_idlist_find_channel_by_name(server->global_list,
1124 /* If router did not find such channel in its lists then this must
1125 be bogus channel or some router in the net is buggy. */
1126 if (server->server_type != SILC_SERVER)
1129 channel = silc_idlist_add_channel(server->global_list, strdup(name),
1130 SILC_CHANNEL_MODE_NONE, channel_id,
1131 server->router, NULL, NULL);
1135 /* Update cache entry expiry */
1136 if (silc_idlist_find_channel_by_id(server->global_list, channel_id,
1138 cache->expire = time(NULL) + 60;
1142 /* Found, update expiry */
1143 cache->expire = time(NULL) + 60;
1147 silc_free(channel->topic);
1148 channel->topic = strdup(topic);
1151 /* Pending callbacks are not executed if this was an list entry */
1152 if (status != SILC_STATUS_OK &&
1153 status != SILC_STATUS_LIST_END) {
1154 silc_server_command_reply_free(cmd);
1158 /* Now purge all old entries from the global list, otherwise we'll might
1159 have non-existent entries for long periods of time in the cache. */
1160 silc_idcache_purge(server->global_list->channels);
1163 SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
1164 SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
1165 silc_free(channel_id);
1166 silc_server_command_reply_free(cmd);