/*
- * control.c
- *
* This module handles states which are global to the entire server.
*
- * $Id$
+ * Copyright (c) 1987-2019 by the citadel.org team
+ *
+ * This program is open source software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3.
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
-#include "sysdep.h"
-#include <stdlib.h>
-#include <unistd.h>
#include <stdio.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <time.h>
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <syslog.h>
-#include "citadel.h"
-#include "server.h"
-#include "control.h"
-#include "sysdep_decls.h"
-#include "support.h"
+#include <sys/file.h>
+#include <libcitadel.h>
+
+#include "ctdl_module.h"
#include "config.h"
-#include "msgbase.h"
-#include "tools.h"
-#include "room_ops.h"
+#include "citserver.h"
+#include "user_ops.h"
-struct CitControl CitControl;
-struct config config;
-FILE *control_fp = NULL;
+long control_highest_user = 0;
/*
- * get_control - read the control record into memory.
+ * This is the legacy "control record" format for the message base. If found
+ * on disk, its contents will be migrated into the system configuration. Never
+ * change this.
*/
-void get_control(void) {
-
- /* Zero it out. If the control record on disk is missing or short,
- * the system functions with all control record fields initialized
- * to zero.
- */
- memset(&CitControl, 0, sizeof(struct CitControl));
- if (control_fp == NULL)
- control_fp = fopen("citadel.control", "rb+");
- if (control_fp == NULL) {
- control_fp = fopen("citadel.control", "wb+");
- if (control_fp != NULL) {
- memset(&CitControl, 0, sizeof(struct CitControl));
- fwrite(&CitControl, sizeof(struct CitControl),
- 1, control_fp);
- rewind(control_fp);
+struct legacy_ctrl_format {
+ long MMhighest; /* highest message number in file */
+ unsigned MMflags; /* Global system flags */
+ long MMnextuser; /* highest user number on system */
+ long MMnextroom; /* highest room number on system */
+ int MM_hosted_upgrade_level; /* Server-hosted upgrade level */
+ int MM_fulltext_wordbreaker; /* ID of wordbreaker in use */
+ long MMfulltext; /* highest message number indexed */
+ int MMdbversion; /* Version of Berkeley DB used on previous server run */
+};
+
+
+/*
+ * Callback to get highest room number when rebuilding message base metadata
+ *
+ * sanity_diag_mode (can be set by -s flag at startup) may be:
+ * 0 = attempt to fix inconsistencies
+ * 1 = show inconsistencies but don't repair them, exit after complete
+ * 2 = show inconsistencies but don't repair them, continue execution
+ */
+void control_find_highest(struct ctdlroom *qrbuf, void *data)
+{
+ struct ctdlroom room;
+ struct cdbdata *cdbfr;
+ long *msglist;
+ int num_msgs=0;
+ int c;
+
+ if (qrbuf->QRnumber > CtdlGetConfigLong("MMnextroom")) {
+ syslog(LOG_DEBUG, "control: fixing MMnextroom %ld > %ld , found in %s",
+ qrbuf->QRnumber, CtdlGetConfigLong("MMnextroom"), qrbuf->QRname
+ );
+ if (!sanity_diag_mode) {
+ CtdlSetConfigLong("MMnextroom", qrbuf->QRnumber);
+ }
+ }
+
+ CtdlGetRoom(&room, qrbuf->QRname);
+
+ /* Load the message list */
+ cdbfr = cdb_fetch(CDB_MSGLISTS, &room.QRnumber, sizeof(long));
+ if (cdbfr != NULL) {
+ msglist = (long *) cdbfr->ptr;
+ num_msgs = cdbfr->len / sizeof(long);
+ } else {
+ return; /* No messages at all? No further action. */
+ }
+
+ if (num_msgs > 0) {
+ for (c=0; c<num_msgs; c++) {
+ if (msglist[c] > CtdlGetConfigLong("MMhighest")) {
+ syslog(LOG_DEBUG, "control: fixing MMhighest %ld > %ld , found in %s",
+ msglist[c], CtdlGetConfigLong("MMhighest"), qrbuf->QRname
+ );
+ if (!sanity_diag_mode) {
+ CtdlSetConfigLong("MMhighest", msglist[c]);
+ }
+ }
}
}
- if (control_fp == NULL) {
- lprintf(1, "ERROR opening citadel.control: %s\n",
- strerror(errno));
+ cdb_free(cdbfr);
+ return;
+}
+
+
+/*
+ * Callback to get highest user number.
+ */
+void control_find_user(char *username, void *out_data) {
+ struct ctdluser EachUser;
+
+ if (CtdlGetUser(&EachUser, username) != 0) {
return;
}
- rewind(control_fp);
- fread(&CitControl, sizeof(struct CitControl), 1, control_fp);
+ if (EachUser.usernum > CtdlGetConfigLong("MMnextuser")) {
+ syslog(LOG_DEBUG, "control: fixing MMnextuser %ld > %ld , found in %s",
+ EachUser.usernum, CtdlGetConfigLong("MMnextuser"), EachUser.fullname
+ );
+ if (!sanity_diag_mode) {
+ CtdlSetConfigLong("MMnextuser", EachUser.usernum);
+ }
}
+}
+
/*
- * put_control - write the control record to disk.
+ * If we have a legacy format control record on disk, import it.
*/
-void put_control(void) {
+void migrate_legacy_control_record(void)
+{
+ FILE *fp = NULL;
+ struct legacy_ctrl_format c;
+ memset(&c, 0, sizeof(c));
+
+ fp = fopen(file_citadel_control, "rb+");
+ if (fp != NULL) {
+ syslog(LOG_INFO, "control: legacy format record found -- importing to db");
+ fread(&c, sizeof(struct legacy_ctrl_format), 1, fp);
+
+ CtdlSetConfigLong( "MMhighest", c.MMhighest);
+ CtdlSetConfigInt( "MMflags", c.MMflags);
+ CtdlSetConfigLong( "MMnextuser", c.MMnextuser);
+ CtdlSetConfigLong( "MMnextroom", c.MMnextroom);
+ CtdlSetConfigInt( "MM_hosted_upgrade_level", c.MM_hosted_upgrade_level);
+ CtdlSetConfigInt( "MM_fulltext_wordbreaker", c.MM_fulltext_wordbreaker);
+ CtdlSetConfigLong( "MMfulltext", c.MMfulltext);
- if (control_fp != NULL) {
- rewind(control_fp);
- fwrite(&CitControl, sizeof(struct CitControl), 1, control_fp);
- fflush(control_fp);
+ fclose(fp);
+ if (unlink(file_citadel_control) != 0) {
+ fprintf(stderr, "Unable to remove legacy control record %s after migrating it.\n", file_citadel_control);
+ fprintf(stderr, "Exiting to prevent data corruption.\n");
+ exit(CTDLEXIT_CONFIG);
}
}
+}
+
+
+/*
+ * check_control - check the control record has sensible values for message, user and room numbers
+ */
+void check_control(void)
+{
+ syslog(LOG_INFO, "control: sanity checking the recorded highest message and room numbers");
+ CtdlForEachRoom(control_find_highest, NULL);
+ syslog(LOG_INFO, "control: sanity checking the recorded highest user number");
+ ForEachUser(control_find_user, NULL);
+ syslog(LOG_INFO, "control: sanity checks complete");
+ if (sanity_diag_mode == 1) {
+ syslog(LOG_INFO, "control: sanity check diagnostic mode is active - exiting now");
+ abort();
+ }
+}
/*
* get_new_message_number() - Obtain a new, unique ID to be used for a message.
*/
-long get_new_message_number(void) {
+long get_new_message_number(void)
+{
+ long retval = 0L;
begin_critical_section(S_CONTROL);
- get_control();
- ++CitControl.MMhighest;
- put_control();
+ retval = CtdlGetConfigLong("MMhighest");
+ ++retval;
+ CtdlSetConfigLong("MMhighest", retval);
end_critical_section(S_CONTROL);
- return(CitControl.MMhighest);
- }
+ return(retval);
+}
+
+
+/*
+ * CtdlGetCurrentMessageNumber() - Obtain the current highest message number in the system
+ * This provides a quick way to initialise a variable that might be used to indicate
+ * messages that should not be processed. EG. a new Sieve script will use this
+ * to record determine that messages older than this should not be processed.
+ *
+ * (Why is this function here? Can't we just go straight to the config variable it fetches?)
+ */
+long CtdlGetCurrentMessageNumber(void)
+{
+ return CtdlGetConfigLong("MMhighest");
+}
/*
* get_new_user_number() - Obtain a new, unique ID to be used for a user.
*/
-long get_new_user_number(void) {
+long get_new_user_number(void)
+{
+ long retval = 0L;
begin_critical_section(S_CONTROL);
- get_control();
- ++CitControl.MMnextuser;
- put_control();
+ retval = CtdlGetConfigLong("MMnextuser");
+ ++retval;
+ CtdlSetConfigLong("MMnextuser", retval);
end_critical_section(S_CONTROL);
- return(CitControl.MMnextuser);
- }
-
+ return(retval);
+}
/*
* get_new_room_number() - Obtain a new, unique ID to be used for a room.
*/
-long get_new_room_number(void) {
+long get_new_room_number(void)
+{
+ long retval = 0L;
begin_critical_section(S_CONTROL);
- get_control();
- ++CitControl.MMnextroom;
- put_control();
+ retval = CtdlGetConfigLong("MMnextroom");
+ ++retval;
+ CtdlSetConfigLong("MMnextroom", retval);
end_critical_section(S_CONTROL);
- return(CitControl.MMnextroom);
- }
+ return(retval);
+}
+/*
+ * Helper function for cmd_conf() to handle boolean values
+ */
+int confbool(char *v)
+{
+ if (IsEmptyStr(v)) return(0);
+ if (atoi(v) != 0) return(1);
+ return(0);
+}
+
/*
* Get or set global configuration options
*/
-void cmd_conf(char *argbuf) {
- char cmd[256];
- char buf[256];
- int a;
+void cmd_conf(char *argbuf)
+{
+ char cmd[16];
+ char buf[1024];
+ int a, i;
+ long ii;
char *confptr;
- char confname[256];
+ char confname[128];
- if (!(CC->logged_in)) {
- cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
- return;
- }
+ if (CtdlAccessCheck(ac_aide)) return;
- if (CC->usersupp.axlevel < 6) {
- cprintf("%d Higher access required.\n",
- ERROR+HIGHER_ACCESS_REQUIRED);
- return;
- }
+ extract_token(cmd, argbuf, 0, '|', sizeof cmd);
- extract(cmd, argbuf, 0);
+ // CONF GET - retrieve system configuration in legacy format
+ // This is deprecated; please do not add fields or change their order.
if (!strcasecmp(cmd, "GET")) {
cprintf("%d Configuration...\n", LISTING_FOLLOWS);
- cprintf("%s\n", config.c_nodename);
- cprintf("%s\n", config.c_fqdn);
- cprintf("%s\n", config.c_humannode);
- cprintf("%s\n", config.c_phonenum);
- cprintf("%d\n", config.c_creataide);
- cprintf("%d\n", config.c_sleeping);
- cprintf("%d\n", config.c_initax);
- cprintf("%d\n", config.c_regiscall);
- cprintf("%d\n", config.c_twitdetect);
- cprintf("%s\n", config.c_twitroom);
- cprintf("%s\n", config.c_moreprompt);
- cprintf("%d\n", config.c_restrict);
- cprintf("%s\n", config.c_bbs_city);
- cprintf("%s\n", config.c_sysadm);
- cprintf("%d\n", config.c_maxsessions);
- cprintf("%s\n", config.c_net_password);
- cprintf("%d\n", config.c_userpurge);
- cprintf("%d\n", config.c_roompurge);
- cprintf("%s\n", config.c_logpages);
- cprintf("%d\n", config.c_createax);
- cprintf("%d\n", config.c_maxmsglen);
- cprintf("%d\n", config.c_min_workers);
- cprintf("%d\n", config.c_max_workers);
- cprintf("%d\n", config.c_pop3_port);
- cprintf("%d\n", config.c_smtp_port);
+ cprintf("%s\n", CtdlGetConfigStr("c_nodename"));
+ cprintf("%s\n", CtdlGetConfigStr("c_fqdn"));
+ cprintf("%s\n", CtdlGetConfigStr("c_humannode"));
+ cprintf("xxx\n"); /* placeholder -- field no longer in use */
+ cprintf("%d\n", CtdlGetConfigInt("c_creataide"));
+ cprintf("%d\n", CtdlGetConfigInt("c_sleeping"));
+ cprintf("%d\n", CtdlGetConfigInt("c_initax"));
+ cprintf("%d\n", CtdlGetConfigInt("c_regiscall"));
+ cprintf("%d\n", CtdlGetConfigInt("c_twitdetect"));
+ cprintf("%s\n", CtdlGetConfigStr("c_twitroom"));
+ cprintf("%s\n", CtdlGetConfigStr("c_moreprompt"));
+ cprintf("%d\n", CtdlGetConfigInt("c_restrict"));
+ cprintf("%s\n", CtdlGetConfigStr("c_site_location"));
+ cprintf("%s\n", CtdlGetConfigStr("c_sysadm"));
+ cprintf("%d\n", CtdlGetConfigInt("c_maxsessions"));
+ cprintf("xxx\n"); /* placeholder -- field no longer in use */
+ cprintf("%d\n", CtdlGetConfigInt("c_userpurge"));
+ cprintf("%d\n", CtdlGetConfigInt("c_roompurge"));
+ cprintf("%s\n", CtdlGetConfigStr("c_logpages"));
+ cprintf("%d\n", CtdlGetConfigInt("c_createax"));
+ cprintf("%ld\n", CtdlGetConfigLong("c_maxmsglen"));
+ cprintf("%d\n", CtdlGetConfigInt("c_min_workers"));
+ cprintf("%d\n", CtdlGetConfigInt("c_max_workers"));
+ cprintf("%d\n", CtdlGetConfigInt("c_pop3_port"));
+ cprintf("%d\n", CtdlGetConfigInt("c_smtp_port"));
+ cprintf("%d\n", CtdlGetConfigInt("c_rfc822_strict_from"));
+ cprintf("%d\n", CtdlGetConfigInt("c_aide_zap"));
+ cprintf("%d\n", CtdlGetConfigInt("c_imap_port"));
+ cprintf("%ld\n", CtdlGetConfigLong("c_net_freq"));
+ cprintf("%d\n", CtdlGetConfigInt("c_disable_newu"));
+ cprintf("1\n"); /* niu */
+ cprintf("%d\n", CtdlGetConfigInt("c_purge_hour"));
+#ifdef HAVE_LDAP
+ cprintf("%s\n", CtdlGetConfigStr("c_ldap_host"));
+ cprintf("%d\n", CtdlGetConfigInt("c_ldap_port"));
+ cprintf("%s\n", CtdlGetConfigStr("c_ldap_base_dn"));
+ cprintf("%s\n", CtdlGetConfigStr("c_ldap_bind_dn"));
+ cprintf("%s\n", CtdlGetConfigStr("c_ldap_bind_pw"));
+#else
+ cprintf("\n");
+ cprintf("0\n");
+ cprintf("\n");
+ cprintf("\n");
+ cprintf("\n");
+#endif
+ cprintf("%s\n", CtdlGetConfigStr("c_ip_addr"));
+ cprintf("%d\n", CtdlGetConfigInt("c_msa_port"));
+ cprintf("%d\n", CtdlGetConfigInt("c_imaps_port"));
+ cprintf("%d\n", CtdlGetConfigInt("c_pop3s_port"));
+ cprintf("%d\n", CtdlGetConfigInt("c_smtps_port"));
+ cprintf("%d\n", CtdlGetConfigInt("c_enable_fulltext"));
+ cprintf("%d\n", CtdlGetConfigInt("c_auto_cull"));
+ cprintf("1\n");
+ cprintf("%d\n", CtdlGetConfigInt("c_allow_spoofing"));
+ cprintf("%d\n", CtdlGetConfigInt("c_journal_email"));
+ cprintf("%d\n", CtdlGetConfigInt("c_journal_pubmsgs"));
+ cprintf("%s\n", CtdlGetConfigStr("c_journal_dest"));
+ cprintf("%s\n", CtdlGetConfigStr("c_default_cal_zone"));
+ cprintf("%d\n", CtdlGetConfigInt("c_pftcpdict_port"));
+ cprintf("0\n");
+ cprintf("%d\n", CtdlGetConfigInt("c_auth_mode"));
+ cprintf("\n");
+ cprintf("\n");
+ cprintf("\n");
+ cprintf("\n");
+ cprintf("%d\n", CtdlGetConfigInt("c_rbl_at_greeting"));
+ cprintf("\n");
+ cprintf("\n");
+ cprintf("%s\n", CtdlGetConfigStr("c_pager_program"));
+ cprintf("%d\n", CtdlGetConfigInt("c_imap_keep_from"));
+ cprintf("%d\n", CtdlGetConfigInt("c_xmpp_c2s_port"));
+ cprintf("%d\n", CtdlGetConfigInt("c_xmpp_s2s_port"));
+ cprintf("%ld\n", CtdlGetConfigLong("c_pop3_fetch"));
+ cprintf("%ld\n", CtdlGetConfigLong("c_pop3_fastest"));
+ cprintf("%d\n", CtdlGetConfigInt("c_spam_flag_only"));
+ cprintf("%d\n", CtdlGetConfigInt("c_guest_logins"));
+ cprintf("%d\n", CtdlGetConfigInt("c_port_number"));
+ cprintf("%d\n", ctdluid);
+ cprintf("%d\n", CtdlGetConfigInt("c_nntp_port"));
+ cprintf("%d\n", CtdlGetConfigInt("c_nntps_port"));
cprintf("000\n");
- }
+ }
+ // CONF SET - set system configuration in legacy format
+ // This is deprecated; please do not add fields or change their order.
else if (!strcasecmp(cmd, "SET")) {
+ unbuffer_output();
cprintf("%d Send configuration...\n", SEND_LISTING);
a = 0;
- while (client_gets(buf), strcmp(buf, "000")) {
- switch(a) {
- case 0: safestrncpy(config.c_nodename, buf,
- sizeof config.c_nodename);
+ while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
+ switch (a) {
+ case 0:
+ CtdlSetConfigStr("c_nodename", buf);
+ break;
+ case 1:
+ CtdlSetConfigStr("c_fqdn", buf);
+ break;
+ case 2:
+ CtdlSetConfigStr("c_humannode", buf);
+ break;
+ case 3:
+ /* placeholder -- field no longer in use */
+ break;
+ case 4:
+ CtdlSetConfigInt("c_creataide", confbool(buf));
+ break;
+ case 5:
+ CtdlSetConfigInt("c_sleeping", atoi(buf));
+ break;
+ case 6:
+ i = atoi(buf);
+ if (i < 1) i = 1;
+ if (i > 6) i = 6;
+ CtdlSetConfigInt("c_initax", i);
+ break;
+ case 7:
+ CtdlSetConfigInt("c_regiscall", confbool(buf));
+ break;
+ case 8:
+ CtdlSetConfigInt("c_twitdetect", confbool(buf));
+ break;
+ case 9:
+ CtdlSetConfigStr("c_twitroom", buf);
+ break;
+ case 10:
+ CtdlSetConfigStr("c_moreprompt", buf);
+ break;
+ case 11:
+ CtdlSetConfigInt("c_restrict", confbool(buf));
+ break;
+ case 12:
+ CtdlSetConfigStr("c_site_location", buf);
+ break;
+ case 13:
+ CtdlSetConfigStr("c_sysadm", buf);
+ break;
+ case 14:
+ i = atoi(buf);
+ if (i < 0) i = 0;
+ CtdlSetConfigInt("c_maxsessions", i);
+ break;
+ case 15:
+ /* placeholder -- field no longer in use */
+ break;
+ case 16:
+ CtdlSetConfigInt("c_userpurge", atoi(buf));
+ break;
+ case 17:
+ CtdlSetConfigInt("c_roompurge", atoi(buf));
+ break;
+ case 18:
+ CtdlSetConfigStr("c_logpages", buf);
+ break;
+ case 19:
+ i = atoi(buf);
+ if (i < 1) i = 1;
+ if (i > 6) i = 6;
+ CtdlSetConfigInt("c_createax", i);
+ break;
+ case 20:
+ ii = atol(buf);
+ if (ii >= 8192) {
+ CtdlSetConfigLong("c_maxmsglen", ii);
+ }
+ break;
+ case 21:
+ i = atoi(buf);
+ if (i >= 3) { // minimum value
+ CtdlSetConfigInt("c_min_workers", i);
+ }
+ break;
+ case 22:
+ i = atoi(buf);
+ if (i >= CtdlGetConfigInt("c_min_workers")) { // max must be >= min
+ CtdlSetConfigInt("c_max_workers", i);
+ }
+ break;
+ case 23:
+ CtdlSetConfigInt("c_pop3_port", atoi(buf));
+ break;
+ case 24:
+ CtdlSetConfigInt("c_smtp_port", atoi(buf));
+ break;
+ case 25:
+ CtdlSetConfigInt("c_rfc822_strict_from", atoi(buf));
+ break;
+ case 26:
+ CtdlSetConfigInt("c_aide_zap", confbool(buf));
break;
- case 1: safestrncpy(config.c_fqdn, buf,
- sizeof config.c_fqdn);
+ case 27:
+ CtdlSetConfigInt("c_imap_port", atoi(buf));
break;
- case 2: safestrncpy(config.c_humannode, buf,
- sizeof config.c_humannode);
+ case 28:
+ CtdlSetConfigLong("c_net_freq", atol(buf));
break;
- case 3: safestrncpy(config.c_phonenum, buf,
- sizeof config.c_phonenum);
+ case 29:
+ CtdlSetConfigInt("c_disable_newu", confbool(buf));
break;
- case 4: config.c_creataide = atoi(buf);
+ case 30:
+ /* niu */
break;
- case 5: config.c_sleeping = atoi(buf);
+ case 31:
+ i = atoi(buf);
+ if ((i >= 0) && (i <= 23)) {
+ CtdlSetConfigInt("c_purge_hour", i);
+ }
break;
- case 6: config.c_initax = atoi(buf);
- if (config.c_initax < 1) config.c_initax = 1;
- if (config.c_initax > 6) config.c_initax = 6;
+ case 32:
+ CtdlSetConfigStr("c_ldap_host", buf);
break;
- case 7: config.c_regiscall = atoi(buf);
- if (config.c_regiscall != 0)
- config.c_regiscall = 1;
+ case 33:
+ CtdlSetConfigInt("c_ldap_port", atoi(buf));
break;
- case 8: config.c_twitdetect = atoi(buf);
- if (config.c_twitdetect != 0)
- config.c_twitdetect = 1;
+ case 34:
+ CtdlSetConfigStr("c_ldap_base_dn", buf);
break;
- case 9: safestrncpy(config.c_twitroom, buf,
- sizeof config.c_twitroom);
+ case 35:
+ CtdlSetConfigStr("c_ldap_bind_dn", buf);
break;
- case 10: safestrncpy(config.c_moreprompt, buf,
- sizeof config.c_moreprompt);
+ case 36:
+ CtdlSetConfigStr("c_ldap_bind_pw", buf);
break;
- case 11: config.c_restrict = atoi(buf);
- if (config.c_restrict != 0)
- config.c_restrict = 1;
+ case 37:
+ CtdlSetConfigStr("c_ip_addr", buf);
break;
- case 12: safestrncpy(config.c_bbs_city, buf,
- sizeof config.c_bbs_city);
+ case 38:
+ CtdlSetConfigInt("c_msa_port", atoi(buf));
break;
- case 13: safestrncpy(config.c_sysadm, buf,
- sizeof config.c_sysadm);
+ case 39:
+ CtdlSetConfigInt("c_imaps_port", atoi(buf));
break;
- case 14: config.c_maxsessions = atoi(buf);
- if (config.c_maxsessions < 1)
- config.c_maxsessions = 1;
+ case 40:
+ CtdlSetConfigInt("c_pop3s_port", atoi(buf));
break;
- case 15: safestrncpy(config.c_net_password, buf,
- sizeof config.c_net_password);
+ case 41:
+ CtdlSetConfigInt("c_smtps_port", atoi(buf));
break;
- case 16: config.c_userpurge = atoi(buf);
+ case 42:
+ CtdlSetConfigInt("c_enable_fulltext", confbool(buf));
break;
- case 17: config.c_roompurge = atoi(buf);
+ case 43:
+ CtdlSetConfigInt("c_auto_cull", confbool(buf));
break;
- case 18: safestrncpy(config.c_logpages, buf,
- sizeof config.c_logpages);
+ case 44:
+ /* niu */
break;
- case 19: config.c_createax = atoi(buf);
- if (config.c_createax < 1)
- config.c_createax = 1;
- if (config.c_createax > 6)
- config.c_createax = 6;
+ case 45:
+ CtdlSetConfigInt("c_allow_spoofing", confbool(buf));
break;
- case 20: if (atoi(buf) >= 8192)
- config.c_maxmsglen = atoi(buf);
+ case 46:
+ CtdlSetConfigInt("c_journal_email", confbool(buf));
break;
- case 21: if (atoi(buf) >= 2)
- config.c_min_workers = atoi(buf);
- case 22: if (atoi(buf) >= config.c_min_workers)
- config.c_max_workers = atoi(buf);
- case 23: config.c_pop3_port = atoi(buf);
+ case 47:
+ CtdlSetConfigInt("c_journal_pubmsgs", confbool(buf));
break;
- case 24: config.c_smtp_port = atoi(buf);
+ case 48:
+ CtdlSetConfigStr("c_journal_dest", buf);
+ break;
+ case 49:
+ CtdlSetConfigStr("c_default_cal_zone", buf);
+ break;
+ case 50:
+ CtdlSetConfigInt("c_pftcpdict_port", atoi(buf));
+ break;
+ case 51:
+ /* niu */
+ break;
+ case 52:
+ CtdlSetConfigInt("c_auth_mode", atoi(buf));
+ break;
+ case 53:
+ /* niu */
+ break;
+ case 54:
+ /* niu */
+ break;
+ case 55:
+ /* niu */
+ break;
+ case 56:
+ /* niu */
+ break;
+ case 57:
+ CtdlSetConfigInt("c_rbl_at_greeting", confbool(buf));
+ break;
+ case 58:
+ /* niu */
+ break;
+ case 59:
+ /* niu */
+ break;
+ case 60:
+ CtdlSetConfigStr("c_pager_program", buf);
+ break;
+ case 61:
+ CtdlSetConfigInt("c_imap_keep_from", confbool(buf));
+ break;
+ case 62:
+ CtdlSetConfigInt("c_xmpp_c2s_port", atoi(buf));
+ break;
+ case 63:
+ CtdlSetConfigInt("c_xmpp_s2s_port", atoi(buf));
+ break;
+ case 64:
+ CtdlSetConfigLong("c_pop3_fetch", atol(buf));
+ break;
+ case 65:
+ CtdlSetConfigLong("c_pop3_fastest", atol(buf));
+ break;
+ case 66:
+ CtdlSetConfigInt("c_spam_flag_only", confbool(buf));
+ break;
+ case 67:
+ CtdlSetConfigInt("c_guest_logins", confbool(buf));
+ break;
+ case 68:
+ CtdlSetConfigInt("c_port_number", atoi(buf));
+ break;
+ case 69:
+ /* niu */
+ break;
+ case 70:
+ CtdlSetConfigInt("c_nntp_port", atoi(buf));
+ break;
+ case 71:
+ CtdlSetConfigInt("c_nntps_port", atoi(buf));
break;
}
- ++a;
- }
- put_config();
- snprintf(buf,sizeof buf,
- "Global system configuration edited by %s\n",
- CC->curr_user);
- aide_message(buf);
-
- if (strlen(config.c_logpages) > 0)
- create_room(config.c_logpages, 3, "", 0);
+ ++a;
}
+ snprintf(buf, sizeof buf,
+ "The global system configuration has been edited by %s.\n",
+ (CC->logged_in ? CC->curr_user : "an administrator")
+ );
+ CtdlAideMessage(buf, "Citadel Configuration Manager Message");
+
+ if (!IsEmptyStr(CtdlGetConfigStr("c_logpages")))
+ CtdlCreateRoom(CtdlGetConfigStr("c_logpages"), 3, "", 0, 1, 1, VIEW_BBS);
+
+ /* If full text indexing has been disabled, invalidate the
+ * index so it doesn't try to use it later.
+ */
+ if (CtdlGetConfigInt("c_enable_fulltext") == 0) {
+ CtdlSetConfigInt("MM_fulltext_wordbreaker", 0);
+ }
+ }
+ // CONF GETSYS - retrieve arbitrary system configuration stanzas stored in the message base
else if (!strcasecmp(cmd, "GETSYS")) {
- extract(confname, argbuf, 1);
+ extract_token(confname, argbuf, 1, '|', sizeof confname);
confptr = CtdlGetSysConfig(confname);
if (confptr != NULL) {
+ long len;
+
+ len = strlen(confptr);
cprintf("%d %s\n", LISTING_FOLLOWS, confname);
- client_write(confptr, strlen(confptr));
- if (confptr[strlen(confptr)-1] != 10)
+ client_write(confptr, len);
+ if ((len > 0) && (confptr[len - 1] != 10))
client_write("\n", 1);
cprintf("000\n");
- phree(confptr);
- }
- else {
+ free(confptr);
+ } else {
cprintf("%d No such configuration.\n",
- ERROR+ILLEGAL_VALUE);
+ ERROR + ILLEGAL_VALUE);
}
}
+ // CONF PUTSYS - store arbitrary system configuration stanzas in the message base
else if (!strcasecmp(cmd, "PUTSYS")) {
- extract(confname, argbuf, 1);
+ extract_token(confname, argbuf, 1, '|', sizeof confname);
+ unbuffer_output();
cprintf("%d %s\n", SEND_LISTING, confname);
- confptr = CtdlReadMessageBody("000", config.c_maxmsglen, NULL);
+ confptr = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0);
CtdlPutSysConfig(confname, confptr);
- phree(confptr);
+ free(confptr);
+ }
+
+ // CONF GETVAL - retrieve configuration variables from the database
+ // CONF LOADVAL - same thing but can handle variables bigger than 1 KB
+ else if ( (!strcasecmp(cmd, "GETVAL")) || (!strcasecmp(cmd, "LOADVAL")) ) {
+ extract_token(confname, argbuf, 1, '|', sizeof confname);
+ char *v = CtdlGetConfigStr(confname);
+ if ( (v) && (!strcasecmp(cmd, "GETVAL")) ) {
+ cprintf("%d %s|\n", CIT_OK, v);
+ }
+ else if ( (v) && (!strcasecmp(cmd, "LOADVAL")) ) {
+ cprintf("%d %d\n", BINARY_FOLLOWS, (int)strlen(v));
+ client_write(v, strlen(v));
+ }
+ else {
+ cprintf("%d |\n", ERROR);
+ }
+ }
+
+ // CONF PUTVAL - store configuration variables in the database
+ else if (!strcasecmp(cmd, "PUTVAL")) {
+ if (num_tokens(argbuf, '|') < 3) {
+ cprintf("%d name and value required\n", ERROR);
+ }
+ else {
+ extract_token(confname, argbuf, 1, '|', sizeof confname);
+ extract_token(buf, argbuf, 2, '|', sizeof buf);
+ CtdlSetConfigStr(confname, buf);
+ cprintf("%d setting '%s' to '%s'\n", CIT_OK, confname, buf);
+ }
+ }
+
+ // CONF STOREVAL - store configuration variables in the database bigger than 1 KB
+ else if (!strcasecmp(cmd, "STOREVAL")) {
+ if (num_tokens(argbuf, '|') < 3) {
+ cprintf("%d name and length required\n", ERROR);
+ }
+ else {
+ extract_token(confname, argbuf, 1, '|', sizeof confname);
+ int bytes = extract_int(argbuf, 2);
+ char *valbuf = malloc(bytes + 1);
+ cprintf("%d %d\n", SEND_BINARY, bytes);
+ client_read(valbuf, bytes);
+ valbuf[bytes+1] = 0;
+ CtdlSetConfigStr(confname, valbuf);
+ free(valbuf);
+ }
+ }
+
+ // CONF LISTVAL - list configuration variables in the database and their values
+ else if (!strcasecmp(cmd, "LISTVAL")) {
+ struct cdbdata *cdbcfg;
+ int keylen = 0;
+ char *key = NULL;
+ char *value = NULL;
+
+ cprintf("%d all configuration variables\n", LISTING_FOLLOWS);
+ cdb_rewind(CDB_CONFIG);
+ while (cdbcfg = cdb_next_item(CDB_CONFIG), cdbcfg != NULL) {
+ if (cdbcfg->len < 1020) {
+ keylen = strlen(cdbcfg->ptr);
+ key = cdbcfg->ptr;
+ value = cdbcfg->ptr + keylen + 1;
+ cprintf("%s|%s\n", key, value);
+ }
+ cdb_free(cdbcfg);
+ }
+ cprintf("000\n");
}
else {
- cprintf("%d Illegal option(s) specified.\n",
- ERROR+ILLEGAL_VALUE);
+ cprintf("%d Illegal option(s) specified.\n", ERROR + ILLEGAL_VALUE);
+ }
+}
+
+
+typedef struct __ConfType {
+ ConstStr Name;
+ long Type;
+}ConfType;
+
+ConfType CfgNames[] = {
+ { {HKEY("localhost") }, 0},
+ { {HKEY("directory") }, 0},
+ { {HKEY("smarthost") }, 2},
+ { {HKEY("fallbackhost") }, 2},
+ { {HKEY("rbl") }, 3},
+ { {HKEY("spamassassin") }, 3},
+ { {HKEY("masqdomain") }, 1},
+ { {HKEY("clamav") }, 3},
+ { {HKEY("notify") }, 3},
+ { {NULL, 0}, 0}
+};
+
+HashList *CfgNameHash = NULL;
+void cmd_gvdn(char *argbuf)
+{
+ const ConfType *pCfg;
+ char *confptr;
+ long min = atol(argbuf);
+ const char *Pos = NULL;
+ const char *PPos = NULL;
+ const char *HKey;
+ long HKLen;
+ StrBuf *Line;
+ StrBuf *Config;
+ StrBuf *Cfg;
+ StrBuf *CfgToken;
+ HashList *List;
+ HashPos *It;
+ void *vptr;
+
+ List = NewHash(1, NULL);
+ Cfg = NewStrBufPlain(CtdlGetConfigStr("c_fqdn"), -1);
+ Put(List, SKEY(Cfg), Cfg, HFreeStrBuf);
+ Cfg = NULL;
+
+ confptr = CtdlGetSysConfig(INTERNETCFG);
+ Config = NewStrBufPlain(confptr, -1);
+ free(confptr);
+
+ Line = NewStrBufPlain(NULL, StrLength(Config));
+ CfgToken = NewStrBufPlain(NULL, StrLength(Config));
+ while (StrBufSipLine(Line, Config, &Pos))
+ {
+ if (Cfg == NULL)
+ Cfg = NewStrBufPlain(NULL, StrLength(Line));
+ PPos = NULL;
+ StrBufExtract_NextToken(Cfg, Line, &PPos, '|');
+ StrBufExtract_NextToken(CfgToken, Line, &PPos, '|');
+ if (GetHash(CfgNameHash, SKEY(CfgToken), &vptr) &&
+ (vptr != NULL))
+ {
+ pCfg = (ConfType *) vptr;
+ if (pCfg->Type <= min)
+ {
+ Put(List, SKEY(Cfg), Cfg, HFreeStrBuf);
+ Cfg = NULL;
+ }
}
}
+
+ cprintf("%d Valid Domains\n", LISTING_FOLLOWS);
+ It = GetNewHashPos(List, 1);
+ while (GetNextHashPos(List, It, &HKLen, &HKey, &vptr))
+ {
+ cputbuf(vptr);
+ cprintf("\n");
+ }
+ cprintf("000\n");
+
+ DeleteHashPos(&It);
+ DeleteHash(&List);
+ FreeStrBuf(&Cfg);
+ FreeStrBuf(&Line);
+ FreeStrBuf(&CfgToken);
+ FreeStrBuf(&Config);
+}
+
+/*****************************************************************************/
+/* MODULE INITIALIZATION STUFF */
+/*****************************************************************************/
+
+void control_cleanup(void)
+{
+ DeleteHash(&CfgNameHash);
+}
+CTDL_MODULE_INIT(control)
+{
+ if (!threading) {
+ int i;
+
+ CfgNameHash = NewHash(1, NULL);
+ for (i = 0; CfgNames[i].Name.Key != NULL; i++)
+ Put(CfgNameHash, CKEY(CfgNames[i].Name), &CfgNames[i], reference_free_handler);
+
+ CtdlRegisterProtoHook(cmd_gvdn, "GVDN", "get valid domain names");
+ CtdlRegisterProtoHook(cmd_conf, "CONF", "get/set system configuration");
+ CtdlRegisterCleanupHook(control_cleanup);
+
+ }
+ /* return our id for the Log */
+ return "control";
+}