X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fcontrol.c;h=da9603abaf4de41fec2c9e8a3bc00a8f8432d64f;hb=e21b689461215d6012ff62d76c2da73d4ffeb33a;hp=db5868d5e0a69fc5bccf01355f87526e22766090;hpb=4fedb8d5970b7c19fdefdce9d7768e4db97acde3;p=citadel.git diff --git a/citadel/control.c b/citadel/control.c index db5868d5e..b79689b08 100644 --- a/citadel/control.c +++ b/citadel/control.c @@ -1,325 +1,808 @@ /* - * $Id$ - * * This module handles states which are global to the entire server. * + * Copyright (c) 1987-2017 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. */ -#ifdef DLL_EXPORT -#define IN_LIBCIT -#endif - -#include "sysdep.h" -#include -#include #include -#include -#include +#include +#include -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#include -#include -#include -#include -#include -#include -#include "citadel.h" -#include "server.h" -#include "control.h" -#include "dynloader.h" -#include "sysdep_decls.h" -#include "support.h" +#include "ctdl_module.h" #include "config.h" -#include "msgbase.h" #include "citserver.h" -#include "tools.h" -#include "room_ops.h" +#include "user_ops.h" -#ifndef HAVE_SNPRINTF -#include "snprintf.h" -#endif +long control_highest_user = 0; + +/* + * 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. + */ +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 */ +}; -struct CitControl CitControl; -struct config config; -FILE *control_fp = NULL; /* - * get_control - read the control record into memory. + * Callback to get highest room number when rebuilding message base metadata */ -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) { - fchown(fileno(control_fp), config.c_bbsuid, -1); - } +void control_find_highest(struct ctdlroom *qrbuf, void *data) +{ + struct ctdlroom room; + struct cdbdata *cdbfr; + long *msglist; + int num_msgs=0; + int c; + int room_fixed = 0; + int message_fixed = 0; + + if (qrbuf->QRnumber > CtdlGetConfigLong("MMnextroom")) + { + CtdlSetConfigLong("MMnextroom", qrbuf->QRnumber); + room_fixed = 1; } - if (control_fp == NULL) { - control_fp = fopen("citadel.control", "wb+"); - if (control_fp != NULL) { - fchown(fileno(control_fp), config.c_bbsuid, -1); - memset(&CitControl, 0, sizeof(struct CitControl)); - fwrite(&CitControl, sizeof(struct CitControl), - 1, control_fp); - rewind(control_fp); + + 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 CtdlGetConfigLong("MMhighest")) + { + CtdlSetConfigLong("MMhighest", msglist[c]); + message_fixed = 1; + } } } - if (control_fp == NULL) { - lprintf(1, "ERROR opening citadel.control: %s\n", - strerror(errno)); - return; + cdb_free(cdbfr); + if (room_fixed) { + syslog(LOG_INFO, "control: fixed room counter"); + } + if (message_fixed) { + syslog(LOG_INFO, "control: fixed message count"); } + return; +} - rewind(control_fp); - fread(&CitControl, sizeof(struct CitControl), 1, control_fp); + +/* + * Callback to get highest user number. + */ + +void control_find_user (struct ctdluser *EachUser, void *out_data) +{ + int user_fixed = 0; + + if (EachUser->usernum > CtdlGetConfigLong("MMnextuser")) + { + CtdlSetConfigLong("MMnextuser", EachUser->usernum); + user_fixed = 1; } + if(user_fixed) + syslog(LOG_INFO, "control: fixed user count"); +} + /* - * 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, user, and room numbers"); + CtdlForEachRoom(control_find_highest, NULL); + ForEachUser(control_find_user, NULL); +} /* * 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 + * + * IF YOU ADD OR CHANGE FIELDS HERE, YOU *MUST* DOCUMENT YOUR CHANGES AT: + * http://www.citadel.org/doku.php/documentation:appproto:system_config + * */ -void cmd_conf(char *argbuf) { - char cmd[SIZ]; - char buf[SIZ]; - int a; +void cmd_conf(char *argbuf) +{ + char cmd[16]; + char buf[1024]; + int a, i; + long ii; char *confptr; - char confname[SIZ]; + char confname[128]; if (CtdlAccessCheck(ac_aide)) return; - extract(cmd, argbuf, 0); + extract_token(cmd, argbuf, 0, '|', sizeof cmd); + + // 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("%ld\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("%d\n", config.c_default_filter); - cprintf("%d\n", config.c_aide_zap); - cprintf("%d\n", config.c_imap_port); - cprintf("%ld\n", config.c_net_freq); + 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("%d\n", CtdlGetConfigInt("c_managesieve_port")); + cprintf("%d\n", CtdlGetConfigInt("c_auth_mode")); + cprintf("\n"); + cprintf("\n"); + cprintf("\n"); + cprintf("\n"); + cprintf("%d\n", CtdlGetConfigInt("c_rbl_at_greeting")); + cprintf("%s\n", CtdlGetConfigStr("c_master_user")); + cprintf("%s\n", CtdlGetConfigStr("c_master_pass")); + 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 1: safestrncpy(config.c_fqdn, buf, - sizeof config.c_fqdn); + case 24: + CtdlSetConfigInt("c_smtp_port", atoi(buf)); break; - case 2: safestrncpy(config.c_humannode, buf, - sizeof config.c_humannode); + case 25: + CtdlSetConfigInt("c_rfc822_strict_from", atoi(buf)); break; - case 3: safestrncpy(config.c_phonenum, buf, - sizeof config.c_phonenum); + case 26: + CtdlSetConfigInt("c_aide_zap", confbool(buf)); break; - case 4: config.c_creataide = atoi(buf); + case 27: + CtdlSetConfigInt("c_imap_port", atoi(buf)); break; - case 5: config.c_sleeping = atoi(buf); + case 28: + CtdlSetConfigLong("c_net_freq", atol(buf)); 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 29: + CtdlSetConfigInt("c_disable_newu", confbool(buf)); break; - case 7: config.c_regiscall = atoi(buf); - if (config.c_regiscall != 0) - config.c_regiscall = 1; + case 30: + /* niu */ break; - case 8: config.c_twitdetect = atoi(buf); - if (config.c_twitdetect != 0) - config.c_twitdetect = 1; + case 31: + i = atoi(buf); + if ((i >= 0) && (i <= 23)) { + CtdlSetConfigInt("c_purge_hour", i); + } break; - case 9: safestrncpy(config.c_twitroom, buf, - sizeof config.c_twitroom); + case 32: + CtdlSetConfigStr("c_ldap_host", buf); break; - case 10: safestrncpy(config.c_moreprompt, buf, - sizeof config.c_moreprompt); + case 33: + CtdlSetConfigInt("c_ldap_port", atoi(buf)); break; - case 11: config.c_restrict = atoi(buf); - if (config.c_restrict != 0) - config.c_restrict = 1; + case 34: + CtdlSetConfigStr("c_ldap_base_dn", buf); break; - case 12: safestrncpy(config.c_bbs_city, buf, - sizeof config.c_bbs_city); + case 35: + CtdlSetConfigStr("c_ldap_bind_dn", buf); break; - case 13: safestrncpy(config.c_sysadm, buf, - sizeof config.c_sysadm); + case 36: + CtdlSetConfigStr("c_ldap_bind_pw", buf); break; - case 14: config.c_maxsessions = atoi(buf); - if (config.c_maxsessions < 1) - config.c_maxsessions = 1; + case 37: + CtdlSetConfigStr("c_ip_addr", buf); break; - case 15: safestrncpy(config.c_net_password, buf, - sizeof config.c_net_password); + case 38: + CtdlSetConfigInt("c_msa_port", atoi(buf)); break; - case 16: config.c_userpurge = atoi(buf); + case 39: + CtdlSetConfigInt("c_imaps_port", atoi(buf)); break; - case 17: config.c_roompurge = atoi(buf); + case 40: + CtdlSetConfigInt("c_pop3s_port", atoi(buf)); break; - case 18: safestrncpy(config.c_logpages, buf, - sizeof config.c_logpages); + case 41: + CtdlSetConfigInt("c_smtps_port", atoi(buf)); 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 42: + CtdlSetConfigInt("c_enable_fulltext", confbool(buf)); break; - case 20: if (atoi(buf) >= 8192) - config.c_maxmsglen = atoi(buf); + case 43: + CtdlSetConfigInt("c_auto_cull", 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 44: + /* niu */ break; - case 24: config.c_smtp_port = atoi(buf); + case 45: + CtdlSetConfigInt("c_allow_spoofing", confbool(buf)); break; - case 25: config.c_default_filter = atoi(buf); + case 46: + CtdlSetConfigInt("c_journal_email", confbool(buf)); break; - case 26: config.c_aide_zap = atoi(buf); - if (config.c_aide_zap != 0) - config.c_aide_zap = 1; + case 47: + CtdlSetConfigInt("c_journal_pubmsgs", confbool(buf)); break; - case 27: config.c_imap_port = atoi(buf); + case 48: + CtdlSetConfigStr("c_journal_dest", buf); break; - case 28: config.c_net_freq = atol(buf); + case 49: + CtdlSetConfigStr("c_default_cal_zone", buf); + break; + case 50: + CtdlSetConfigInt("c_pftcpdict_port", atoi(buf)); + break; + case 51: + CtdlSetConfigInt("c_managesieve_port", atoi(buf)); + 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: + CtdlSetConfigStr("c_master_user", buf); + break; + case 59: + CtdlSetConfigStr("c_master_pass", buf); + 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, 1); + ++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"; +}