1 // Main source module for the Citadel server
3 // Copyright (c) 1987-2024 by the citadel.org team
5 // This program is open source software. Use, duplication, or disclosure
6 // is subject to the terms of the GNU General Public License, version 3.
15 #include <libcitadel.h>
16 #include "ctdl_module.h"
17 #include "housekeeping.h"
18 #include "locate_host.h"
19 #include "citserver.h"
24 char *unique_session_numbers;
25 int ScheduledShutdown = 0;
26 time_t server_startup_time;
30 // We need pseudo-random numbers for a few things. Seed generously.
31 void seed_random_number_generator(void) {
32 syslog(LOG_INFO, "citserver: seeding the pseudo-random number generator");
33 srand(time(NULL) + getpid() + clock());
37 // Various things that need to be initialized at startup
38 void master_startup(void) {
39 struct ctdlroom qrbuf;
43 syslog(LOG_DEBUG, "citserver: master_startup() started");
44 time(&server_startup_time);
46 syslog(LOG_INFO, "citserver: checking directory access");
47 if ((pw = getpwuid(ctdluid)) == NULL) {
54 if (create_run_directories(ctdluid, gid) != 0) {
55 syslog(LOG_ERR, "citserver: failed to access and create directories");
59 syslog(LOG_DEBUG, "citserver: ctdl_message_dir is %s", ctdl_message_dir);
60 syslog(LOG_DEBUG, "citserver: ctdl_file_dir is %s", ctdl_file_dir);
61 syslog(LOG_DEBUG, "citserver: ctdl_key_dir is %s", ctdl_key_dir);
62 syslog(LOG_DEBUG, "citserver: ctdl_run_dir is %s", ctdl_run_dir);
64 syslog(LOG_INFO, "citserver: opening databases");
68 // Load site-specific configuration
69 seed_random_number_generator(); // must be done before config system
70 syslog(LOG_INFO, "citserver: initializing configuration system");
71 initialize_config_system();
73 migrate_legacy_control_record();
75 // If we have an existing database that is older than version 928, reindex the user records.
76 // Unfortunately we cannot do this in serv_upgrade.c because it needs to happen VERY early during startup.
77 int existing_db = CtdlGetConfigInt("MM_hosted_upgrade_level");
78 if ( (existing_db > 0) && (existing_db < 928) ) {
79 ForEachUser(reindex_user_928, NULL);
82 // Check floor reference counts
85 syslog(LOG_INFO, "citserver: creating base rooms (if necessary)");
86 CtdlCreateRoom(CtdlGetConfigStr("c_baseroom"), 0, "", 0, 1, 0, VIEW_BBS);
87 CtdlCreateRoom(AIDEROOM, 3, "", 0, 1, 0, VIEW_BBS);
88 CtdlCreateRoom(SYSCONFIGROOM, 3, "", 0, 1, 0, VIEW_BBS);
89 CtdlCreateRoom(CtdlGetConfigStr("c_twitroom"), 0, "", 0, 1, 0, VIEW_BBS);
91 // The "Local System Configuration" room doesn't need to be visible
92 if (CtdlGetRoomLock(&qrbuf, SYSCONFIGROOM) == 0) {
93 qrbuf.QRflags2 |= QR2_SYSTEM;
94 CtdlPutRoomLock(&qrbuf);
97 // Aide needs to be public postable, else we're not RFC conformant.
98 if (CtdlGetRoomLock(&qrbuf, AIDEROOM) == 0) {
99 qrbuf.QRflags2 |= QR2_SMTP_PUBLIC;
100 CtdlPutRoomLock(&qrbuf);
103 syslog(LOG_DEBUG, "citserver: master_startup() finished");
107 // Cleanup routine to be called when the server is shutting down. Returns the needed exit code.
108 void master_cleanup(int exitcode) {
109 static int already_cleaning_up = 0;
111 if (already_cleaning_up) {
116 already_cleaning_up = 1;
121 // Close the configuration system
122 shutdown_config_system();
125 syslog(LOG_INFO, "citserver: closing databases");
126 cdb_close_databases();
128 // If the operator requested a halt but not an exit, halt here.
129 if (shutdown_and_halt) {
130 syslog(LOG_ERR, "citserver: Halting server without exiting.");
139 syslog(LOG_ERR, "citserver: Exiting with status %d", exitcode);
143 if ((running_as_daemon != 0) && ((exitcode == 0))) {
144 exitcode = CTDLEXIT_SHUTDOWN;
152 // returns an asterisk if there are any instant messages waiting, space otherwise.
153 char CtdlCheckExpress(struct CitContext *con) {
154 if (con->FirstExpressMessage == NULL) {
163 void citproto_begin_session() {
164 if (CC->nologin == 1) {
165 cprintf("%d Too many users are already online (maximum is %d)\n",
166 ERROR + MAX_SESSIONS_EXCEEDED, CtdlGetConfigInt("c_maxsessions")
168 CC->kill_me = KILLME_MAX_SESSIONS_EXCEEDED;
171 cprintf("%d %s Citadel server ready.\n", CIT_OK, CtdlGetConfigStr("c_fqdn"));
172 strcpy(CC->cs_clientname, "Citadel client protocol");
173 CC->can_receive_im = 1;
178 void citproto_begin_admin_session() {
179 CC->internal_pgm = 1;
180 cprintf("%d %s Citadel server ADMIN CONNECTION ready.\n", CIT_OK, CtdlGetConfigStr("c_fqdn"));
184 // This loop performs all asynchronous functions.
185 void do_async_loop(void) {
186 PerformSessionHooks(EVT_ASYNC);