]> code.citadel.org Git - citadel.git/commitdiff
Merge branch 'configdb' of ssh://git.citadel.org/appl/gitroot/citadel
authorWilfried Goesgens <dothebart@citadel.org>
Sun, 16 Aug 2015 10:25:07 +0000 (12:25 +0200)
committerWilfried Goesgens <dothebart@citadel.org>
Sun, 16 Aug 2015 10:25:07 +0000 (12:25 +0200)
Conflicts:
citadel/citserver.c
citadel/config.c
citadel/control.c
citadel/modules/fulltext/serv_fulltext.c
citadel/modules/migrate/serv_migrate.c
citadel/modules/upgrade/serv_upgrade.c
citadel/server.h

29 files changed:
1  2 
citadel/config.c
citadel/control.c
citadel/database.c
citadel/ical_dezonify.c
citadel/include/ctdl_module.h
citadel/modules/autocompletion/serv_autocompletion.c
citadel/modules/calendar/serv_calendar.c
citadel/modules/ctdlproto/serv_messages.c
citadel/modules/expire/serv_expire.c
citadel/modules/extnotify/extnotify_main.c
citadel/modules/fulltext/serv_fulltext.c
citadel/modules/imap/imap_fetch.c
citadel/modules/imap/imap_search.c
citadel/modules/migrate/serv_migrate.c
citadel/modules/network/serv_netmail.c
citadel/modules/network/serv_netspool.c
citadel/modules/network/serv_network.c
citadel/modules/nntp/serv_nntp.c
citadel/modules/pop3client/serv_pop3client.c
citadel/modules/rssclient/serv_rssclient.c
citadel/modules/sieve/serv_sieve.c
citadel/modules/smtp/serv_smtp.c
citadel/modules/smtp/serv_smtpqueue.c
citadel/modules/vcard/serv_vcard.c
citadel/modules/wiki/serv_wiki.c
citadel/modules/xmpp/xmpp_presence.c
citadel/msgbase.c
citadel/room_ops.c
citadel/server_main.c

diff --combined citadel/config.c
index b2d27c8b63ca42d5276342a9f5982e80d71b519c,9b5b96d2607b987996bf89f9ed86af7e2582310b..b6c386b6e56dc7c0ee9d31ed8ea909860ca903c1
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * Read and write the citadel.config file
   *
-  * Copyright (c) 1987-2014 by the citadel.org team
+  * Copyright (c) 1987-2015 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.
  #include "config.h"
  #include "ctdl_module.h"
  
- struct config config;
- struct configlen configlen;
+ long config_msgnum = 0;
+ HashList *ctdlconfig = NULL;  // new configuration
+ void config_warn_if_port_unset(char *key, int default_port)                   \
+ {
+       int p = CtdlGetConfigInt(key);
+       if ((p < -1) || (p == 0) || (p > UINT16_MAX))
+       {
+               syslog(LOG_EMERG,
+                       "configuration setting %s is not -1 (disabled) or a valid TCP-Port - check your config! Default setting is: %d",
+                       key, default_port
+               );
+       }
+ }
+ void config_warn_if_empty(char *key)
+ {
+       if (IsEmptyStr(CtdlGetConfigStr(key)))
+       {
+               syslog(LOG_EMERG, "configuration setting %s is empty, but must not - check your config!", key);
+       }
+ }
  
- #define STR_NOT_EMPTY(CFG_FIELDNAME) if (IsEmptyStr(config.CFG_FIELDNAME)) \
-               syslog(LOG_EMERG, "configuration setting "#CFG_FIELDNAME" is empty, but must not - check your config!");
  
- #define TEST_PORT(CFG_PORT, DEFAULTPORT)                      \
-       if ((config.CFG_PORT < -1) ||           \
-           (config.CFG_PORT == 0) ||           \
-           (config.CFG_PORT > UINT16_MAX))     \
-               syslog(LOG_EMERG, "configuration setting "#CFG_PORT" is not -1 (disabled) or a valid TCP-Port - check your config! Default setting is: "#DEFAULTPORT);
-                       
  
  void validate_config(void) {
- /* these shouldn't be empty: */
-       STR_NOT_EMPTY(c_fqdn);
-       STR_NOT_EMPTY(c_baseroom);
-       STR_NOT_EMPTY(c_aideroom);
-       STR_NOT_EMPTY(c_twitroom);
-       STR_NOT_EMPTY(c_nodename);
-       STR_NOT_EMPTY(c_default_cal_zone);
- /* we bind a lot of ports: */
-       TEST_PORT(c_smtp_port, 25);
-       TEST_PORT(c_pop3_port, 110);
-       TEST_PORT(c_imap_port, 143);
-       TEST_PORT(c_msa_port, 587);
-       TEST_PORT(c_port_number, 504);
-       TEST_PORT(c_smtps_port, 465);
-       TEST_PORT(c_pop3s_port, 995);
-       TEST_PORT(c_imaps_port, 993);
-       TEST_PORT(c_pftcpdict_port, -1);
-       TEST_PORT(c_managesieve_port, 2020);
-       TEST_PORT(c_xmpp_c2s_port, 5222);
-       TEST_PORT(c_xmpp_s2s_port, 5269);
-       TEST_PORT(c_nntp_port, 119);
-       TEST_PORT(c_nntps_port, 563);
-       if (config.c_ctdluid == 0)
-               syslog(LOG_EMERG, "citadel should not be configured to run as root! Check the value of c_ctdluid");
-       else if (getpwuid(CTDLUID) == NULL)
-               syslog(LOG_EMERG, "The UID (%d) citadel is configured to use is not defined in your system (/etc/passwd?)! Check the value of c_ctdluid", CTDLUID);
+       /*
+        * these shouldn't be empty
+        */
+       config_warn_if_empty("c_fqdn");
+       config_warn_if_empty("c_baseroom");
+       config_warn_if_empty("c_aideroom");
+       config_warn_if_empty("c_twitroom");
+       config_warn_if_empty("c_nodename");
+       config_warn_if_empty("c_default_cal_zone");
+       /*
+        * Sanity check for port bindings
+        */
+       config_warn_if_port_unset("c_smtp_port", 25);
+       config_warn_if_port_unset("c_pop3_port", 110);
+       config_warn_if_port_unset("c_imap_port", 143);
+       config_warn_if_port_unset("c_msa_port", 587);
+       config_warn_if_port_unset("c_port_number", 504);
+       config_warn_if_port_unset("c_smtps_port", 465);
+       config_warn_if_port_unset("c_pop3s_port", 995);
+       config_warn_if_port_unset("c_imaps_port", 993);
+       config_warn_if_port_unset("c_pftcpdict_port", -1);
+       config_warn_if_port_unset("c_managesieve_port", 2020);
+       config_warn_if_port_unset("c_xmpp_c2s_port", 5222);
+       config_warn_if_port_unset("c_xmpp_s2s_port", 5269);
+       config_warn_if_port_unset("c_nntp_port", 119);
+       config_warn_if_port_unset("c_nntps_port", 563);
+       if (getpwuid(ctdluid) == NULL) {
+               syslog(LOG_EMERG, "The UID (%d) citadel is configured to use is not defined in your system (/etc/passwd?)!", ctdluid);
+       }
        
  }
  
   */
  void brand_new_installation_set_defaults(void) {
  
-       struct passwd *pw;
        struct utsname my_utsname;
        struct hostent *he;
+       char detected_hostname[256];
  
        /* Determine our host name, in case we need to use it as a default */
        uname(&my_utsname);
-       memset(&configlen, 0, sizeof(struct configlen));
        /* set some sample/default values in place of blanks... */
-       configlen.c_nodename = extract_token(config.c_nodename, my_utsname.nodename, 0, '.', sizeof config.c_nodename);
-       if (IsEmptyStr(config.c_fqdn) ) {
-               if ((he = gethostbyname(my_utsname.nodename)) != NULL) {
-                       configlen.c_fqdn = safestrncpy(config.c_fqdn, he->h_name, sizeof config.c_fqdn);
-               }
-               else {
-                       configlen.c_fqdn = safestrncpy(config.c_fqdn, my_utsname.nodename, sizeof config.c_fqdn);
-               }
-       }
+       extract_token(detected_hostname, my_utsname.nodename, 0, '.', sizeof detected_hostname);
+       CtdlSetConfigStr("c_nodename", detected_hostname);
  
-       configlen.c_humannode = safestrncpy(config.c_humannode, "Citadel Server", sizeof config.c_humannode);
-       configlen.c_phonenum = safestrncpy(config.c_phonenum, "US 800 555 1212", sizeof config.c_phonenum);
-       config.c_initax = 4;
-       configlen.c_moreprompt = safestrncpy(config.c_moreprompt, "<more>", sizeof config.c_moreprompt);
-       configlen.c_twitroom = safestrncpy(config.c_twitroom, "Trashcan", sizeof config.c_twitroom);
-       configlen.c_baseroom = safestrncpy(config.c_baseroom, BASEROOM, sizeof config.c_baseroom);
-       configlen.c_aideroom = safestrncpy(config.c_aideroom, "Aide", sizeof config.c_aideroom);
-       config.c_port_number = 504;
-       config.c_sleeping = 900;
-       if (config.c_ctdluid == 0) {
-               pw = getpwnam("citadel");
-               if (pw != NULL) {
-                       config.c_ctdluid = pw->pw_uid;
-               }
-       }
-       if (config.c_ctdluid == 0) {
-               pw = getpwnam("bbs");
-               if (pw != NULL) {
-                       config.c_ctdluid = pw->pw_uid;
-               }
+       if ((he = gethostbyname(my_utsname.nodename)) != NULL) {
+               CtdlSetConfigStr("c_fqdn", he->h_name);
        }
-       if (config.c_ctdluid == 0) {
-               pw = getpwnam("guest");
-               if (pw != NULL) {
-                       config.c_ctdluid = pw->pw_uid;
-               }
+       else {
+               CtdlSetConfigStr("c_fqdn", my_utsname.nodename);
        }
-       if (config.c_createax == 0) {
-               config.c_createax = 3;
+       CtdlSetConfigStr("c_humannode",         "Citadel Server");
+       CtdlSetConfigInt("c_initax",            4);
+       CtdlSetConfigStr("c_moreprompt",        "<more>");
+       CtdlSetConfigStr("c_twitroom",          "Trashcan");
+       CtdlSetConfigStr("c_baseroom",          BASEROOM);
+       CtdlSetConfigStr("c_aideroom",          "Aide");
+       CtdlSetConfigInt("c_sleeping",          900);
+       if (CtdlGetConfigInt("c_createax") == 0) {
+               CtdlSetConfigInt("c_createax", 3);
        }
  
        /*
         * Default port numbers for various services
         */
-       config.c_smtp_port = 25;
-       config.c_pop3_port = 110;
-       config.c_imap_port = 143;
-       config.c_msa_port = 587;
-       config.c_smtps_port = 465;
-       config.c_pop3s_port = 995;
-       config.c_imaps_port = 993;
-       config.c_pftcpdict_port = -1 ;
-       config.c_managesieve_port = 2020;
-       config.c_xmpp_c2s_port = 5222;
-       config.c_xmpp_s2s_port = 5269;
-       config.c_nntp_port = 119;
-       config.c_nntps_port = 563;
+       CtdlSetConfigInt("c_port_number",       504);
+       CtdlSetConfigInt("c_smtp_port",         25);
+       CtdlSetConfigInt("c_pop3_port",         110);
+       CtdlSetConfigInt("c_imap_port",         143);
+       CtdlSetConfigInt("c_msa_port",          587);
+       CtdlSetConfigInt("c_smtps_port",        465);
+       CtdlSetConfigInt("c_pop3s_port",        995);
+       CtdlSetConfigInt("c_imaps_port",        993);
+       CtdlSetConfigInt("c_pftcpdict_port",    -1);
+       CtdlSetConfigInt("c_managesieve_port",  2020);
+       CtdlSetConfigInt("c_xmpp_c2s_port",     5222);
+       CtdlSetConfigInt("c_xmpp_s2s_port",     5269);
+       CtdlSetConfigInt("c_nntp_port",         119);
+       CtdlSetConfigInt("c_nntps_port",        563);
+       /*
+        * Prevent the "new installation, set defaults" behavior from occurring again
+        */
+       CtdlSetConfigLong("c_config_created_or_migrated", (long)time(NULL));
  }
  
- void setcfglen(void)
+ /*
+  * Migrate a supplied legacy configuration to the new in-db format.
+  * No individual site should ever have to do this more than once.
+  */
+ void migrate_legacy_config(struct legacy_config *lconfig)
  {
-       configlen.c_nodename = strlen(config.c_nodename);
-       configlen.c_fqdn = strlen(config.c_fqdn);
-       configlen.c_humannode = strlen(config.c_humannode);
-       configlen.c_phonenum = strlen(config.c_phonenum);
-       configlen.c_twitroom = strlen(config.c_twitroom);
-       configlen.c_moreprompt = strlen(config.c_moreprompt);
-       configlen.c_site_location = strlen(config.c_site_location);
-       configlen.c_sysadm = strlen(config.c_sysadm);
-       configlen.c_niu_2 = strlen(config.c_niu_2);
-       configlen.c_ip_addr = strlen(config.c_ip_addr);
-       configlen.c_logpages = strlen(config.c_logpages);
-       configlen.c_baseroom = strlen(config.c_baseroom);
-       configlen.c_aideroom = strlen(config.c_aideroom);
-       configlen.c_ldap_host = strlen(config.c_ldap_host);
-       configlen.c_ldap_base_dn = strlen(config.c_ldap_base_dn);
-       configlen.c_ldap_bind_dn = strlen(config.c_ldap_bind_dn);
-       configlen.c_ldap_bind_pw = strlen(config.c_ldap_bind_pw);
-       configlen.c_journal_dest = strlen(config.c_journal_dest);
-       configlen.c_default_cal_zone = strlen(config.c_default_cal_zone);
-       configlen.c_funambol_host = strlen(config.c_funambol_host);
-       configlen.c_funambol_source = strlen(config.c_funambol_source);
-       configlen.c_funambol_auth = strlen(config.c_funambol_auth);
-       configlen.c_master_user = strlen(config.c_master_user);
-       configlen.c_master_pass = strlen(config.c_master_pass);
-       configlen.c_pager_program = strlen(config.c_pager_program);
+       CtdlSetConfigStr(       "c_nodename"            ,       lconfig->c_nodename             );
+       CtdlSetConfigStr(       "c_fqdn"                ,       lconfig->c_fqdn                 );
+       CtdlSetConfigStr(       "c_humannode"           ,       lconfig->c_humannode            );
+       CtdlSetConfigInt(       "c_creataide"           ,       lconfig->c_creataide            );
+       CtdlSetConfigInt(       "c_sleeping"            ,       lconfig->c_sleeping             );
+       CtdlSetConfigInt(       "c_initax"              ,       lconfig->c_initax               );
+       CtdlSetConfigInt(       "c_regiscall"           ,       lconfig->c_regiscall            );
+       CtdlSetConfigInt(       "c_twitdetect"          ,       lconfig->c_twitdetect           );
+       CtdlSetConfigStr(       "c_twitroom"            ,       lconfig->c_twitroom             );
+       CtdlSetConfigStr(       "c_moreprompt"          ,       lconfig->c_moreprompt           );
+       CtdlSetConfigInt(       "c_restrict"            ,       lconfig->c_restrict             );
+       CtdlSetConfigStr(       "c_site_location"       ,       lconfig->c_site_location        );
+       CtdlSetConfigStr(       "c_sysadm"              ,       lconfig->c_sysadm               );
+       CtdlSetConfigInt(       "c_maxsessions"         ,       lconfig->c_maxsessions          );
+       CtdlSetConfigStr(       "c_ip_addr"             ,       lconfig->c_ip_addr              );
+       CtdlSetConfigInt(       "c_port_number"         ,       lconfig->c_port_number          );
+       CtdlSetConfigInt(       "c_ep_mode"             ,       lconfig->c_ep.expire_mode       );
+       CtdlSetConfigInt(       "c_ep_value"            ,       lconfig->c_ep.expire_value      );
+       CtdlSetConfigInt(       "c_userpurge"           ,       lconfig->c_userpurge            );
+       CtdlSetConfigInt(       "c_roompurge"           ,       lconfig->c_roompurge            );
+       CtdlSetConfigStr(       "c_logpages"            ,       lconfig->c_logpages             );
+       CtdlSetConfigInt(       "c_createax"            ,       lconfig->c_createax             );
+       CtdlSetConfigLong(      "c_maxmsglen"           ,       lconfig->c_maxmsglen            );
+       CtdlSetConfigInt(       "c_min_workers"         ,       lconfig->c_min_workers          );
+       CtdlSetConfigInt(       "c_max_workers"         ,       lconfig->c_max_workers          );
+       CtdlSetConfigInt(       "c_pop3_port"           ,       lconfig->c_pop3_port            );
+       CtdlSetConfigInt(       "c_smtp_port"           ,       lconfig->c_smtp_port            );
+       CtdlSetConfigInt(       "c_rfc822_strict_from"  ,       lconfig->c_rfc822_strict_from   );
+       CtdlSetConfigInt(       "c_aide_zap"            ,       lconfig->c_aide_zap             );
+       CtdlSetConfigInt(       "c_imap_port"           ,       lconfig->c_imap_port            );
+       CtdlSetConfigLong(      "c_net_freq"            ,       lconfig->c_net_freq             );
+       CtdlSetConfigInt(       "c_disable_newu"        ,       lconfig->c_disable_newu         );
+       CtdlSetConfigInt(       "c_enable_fulltext"     ,       lconfig->c_enable_fulltext      );
+       CtdlSetConfigStr(       "c_baseroom"            ,       lconfig->c_baseroom             );
+       CtdlSetConfigStr(       "c_aideroom"            ,       lconfig->c_aideroom             );
+       CtdlSetConfigInt(       "c_purge_hour"          ,       lconfig->c_purge_hour           );
+       CtdlSetConfigInt(       "c_mbxep_mode"          ,       lconfig->c_mbxep.expire_mode    );
+       CtdlSetConfigInt(       "c_mbxep_value"         ,       lconfig->c_mbxep.expire_value   );
+       CtdlSetConfigStr(       "c_ldap_host"           ,       lconfig->c_ldap_host            );
+       CtdlSetConfigInt(       "c_ldap_port"           ,       lconfig->c_ldap_port            );
+       CtdlSetConfigStr(       "c_ldap_base_dn"        ,       lconfig->c_ldap_base_dn         );
+       CtdlSetConfigStr(       "c_ldap_bind_dn"        ,       lconfig->c_ldap_bind_dn         );
+       CtdlSetConfigStr(       "c_ldap_bind_pw"        ,       lconfig->c_ldap_bind_pw         );
+       CtdlSetConfigInt(       "c_msa_port"            ,       lconfig->c_msa_port             );
+       CtdlSetConfigInt(       "c_imaps_port"          ,       lconfig->c_imaps_port           );
+       CtdlSetConfigInt(       "c_pop3s_port"          ,       lconfig->c_pop3s_port           );
+       CtdlSetConfigInt(       "c_smtps_port"          ,       lconfig->c_smtps_port           );
+       CtdlSetConfigInt(       "c_auto_cull"           ,       lconfig->c_auto_cull            );
+       CtdlSetConfigInt(       "c_allow_spoofing"      ,       lconfig->c_allow_spoofing       );
+       CtdlSetConfigInt(       "c_journal_email"       ,       lconfig->c_journal_email        );
+       CtdlSetConfigInt(       "c_journal_pubmsgs"     ,       lconfig->c_journal_pubmsgs      );
+       CtdlSetConfigStr(       "c_journal_dest"        ,       lconfig->c_journal_dest         );
+       CtdlSetConfigStr(       "c_default_cal_zone"    ,       lconfig->c_default_cal_zone     );
+       CtdlSetConfigInt(       "c_pftcpdict_port"      ,       lconfig->c_pftcpdict_port       );
+       CtdlSetConfigInt(       "c_managesieve_port"    ,       lconfig->c_managesieve_port     );
+       CtdlSetConfigInt(       "c_auth_mode"           ,       lconfig->c_auth_mode            );
+       CtdlSetConfigStr(       "c_funambol_host"       ,       lconfig->c_funambol_host        );
+       CtdlSetConfigInt(       "c_funambol_port"       ,       lconfig->c_funambol_port        );
+       CtdlSetConfigStr(       "c_funambol_source"     ,       lconfig->c_funambol_source      );
+       CtdlSetConfigStr(       "c_funambol_auth"       ,       lconfig->c_funambol_auth        );
+       CtdlSetConfigInt(       "c_rbl_at_greeting"     ,       lconfig->c_rbl_at_greeting      );
+       CtdlSetConfigStr(       "c_master_user"         ,       lconfig->c_master_user          );
+       CtdlSetConfigStr(       "c_master_pass"         ,       lconfig->c_master_pass          );
+       CtdlSetConfigStr(       "c_pager_program"       ,       lconfig->c_pager_program        );
+       CtdlSetConfigInt(       "c_imap_keep_from"      ,       lconfig->c_imap_keep_from       );
+       CtdlSetConfigInt(       "c_xmpp_c2s_port"       ,       lconfig->c_xmpp_c2s_port        );
+       CtdlSetConfigInt(       "c_xmpp_s2s_port"       ,       lconfig->c_xmpp_s2s_port        );
+       CtdlSetConfigLong(      "c_pop3_fetch"          ,       lconfig->c_pop3_fetch           );
+       CtdlSetConfigLong(      "c_pop3_fastest"        ,       lconfig->c_pop3_fastest         );
+       CtdlSetConfigInt(       "c_spam_flag_only"      ,       lconfig->c_spam_flag_only       );
+       CtdlSetConfigInt(       "c_guest_logins"        ,       lconfig->c_guest_logins         );
+       CtdlSetConfigInt(       "c_nntp_port"           ,       lconfig->c_nntp_port            );
+       CtdlSetConfigInt(       "c_nntps_port"          ,       lconfig->c_nntps_port           );
  }
  
  /*
-  * get_config() is called during the initialization of Citadel server.
+  * Called during the initialization of Citadel server.
   * It verifies the system's integrity and reads citadel.config into memory.
   */
- void get_config(void) {
+ void initialize_config_system(void) {
        FILE *cfp;
        int rv;
+       struct legacy_config lconfig;   // legacy configuration
+       ctdlconfig = NewHash(1, NULL);  // set up the real config system
+       /* Ensure that we are linked to the correct version of libcitadel */
+       if (libcitadel_version_number() < LIBCITADEL_VERSION_NUMBER) {
+               fprintf(stderr, "You are running libcitadel version %d.%02d\n",
+                       (libcitadel_version_number() / 100), (libcitadel_version_number() % 100)
+               );
+               fprintf(stderr, "citserver was compiled against version %d.%02d\n",
+                       (LIBCITADEL_VERSION_NUMBER / 100), (LIBCITADEL_VERSION_NUMBER % 100)
+               );
+               exit(CTDLEXIT_LIBCITADEL);
+       }
  
        if (chdir(ctdl_bbsbase_dir) != 0) {
                fprintf(stderr,
                exit(CTDLEXIT_HOME);
        }
  
-       memset(&config, 0, sizeof(struct config));
+       memset(&lconfig, 0, sizeof(struct legacy_config));
        cfp = fopen(file_citadel_config, "rb");
        if (cfp != NULL) {
-               rv = fread((char *) &config, sizeof(struct config), 1, cfp);
+               if (CtdlGetConfigLong("c_config_created_or_migrated") > 0) {
+                       fprintf(stderr, "Citadel Server found BOTH legacy and new configurations present.\n");
+                       fprintf(stderr, "Exiting to prevent data corruption.\n");
+                       exit(CTDLEXIT_CONFIG);
+               }
+               rv = fread((char *) &lconfig, sizeof(struct legacy_config), 1, cfp);
                if (rv != 1)
                {
                        fprintf(stderr, 
-                               "Warning: The config file %s has unexpected size. \n",
+                               "Warning: Found a legacy config file %s has unexpected size. \n",
                                file_citadel_config
                        );
                }
+               migrate_legacy_config(&lconfig);
                fclose(cfp);
-               setcfglen();
-       }
-       else {
-               brand_new_installation_set_defaults();
+               if (unlink(file_citadel_config) != 0) {
+                       fprintf(stderr, "Unable to remove legacy config file %s after migrating it.\n", file_citadel_config);
+                       fprintf(stderr, "Exiting to prevent data corruption.\n");
+                       exit(CTDLEXIT_CONFIG);
+               }
+               /*
+                * Prevent migration/initialization from happening again.
+                */
+               CtdlSetConfigLong("c_config_created_or_migrated", (long)time(NULL));
        }
  
-       /* Ensure that we are linked to the correct version of libcitadel */
-       if (libcitadel_version_number() < LIBCITADEL_VERSION_NUMBER) {
-               fprintf(stderr, "    You are running libcitadel version %d.%02d\n",
-                       (libcitadel_version_number() / 100), (libcitadel_version_number() % 100));
-               fprintf(stderr, "citserver was compiled against version %d.%02d\n",
-                       (LIBCITADEL_VERSION_NUMBER / 100), (LIBCITADEL_VERSION_NUMBER % 100));
-               exit(CTDLEXIT_LIBCITADEL);
+       /* New installation?  Set up configuration */
+       if (CtdlGetConfigLong("c_config_created_or_migrated") <= 0) {
+               brand_new_installation_set_defaults();
        }
  
        /* Only allow LDAP auth mode if we actually have LDAP support */
  #ifndef HAVE_LDAP
-       if ((config.c_auth_mode == AUTHMODE_LDAP) || (config.c_auth_mode == AUTHMODE_LDAP_AD)) {
+       if ((CtdlGetConfigInt("c_auth_mode") == AUTHMODE_LDAP) || (CtdlGetConfigInt("c_auth_mode") == AUTHMODE_LDAP_AD)) {
                fprintf(stderr, "Your system is configured for LDAP authentication,\n"
                                "but you are running a server built without OpenLDAP support.\n");
                exit(CTDL_EXIT_UNSUP_AUTH);
         * configurable.  Also check to make sure the limit has not been
         * set below 8192 bytes.
           */
-         if (config.c_maxmsglen <= 0)
-                 config.c_maxmsglen = 10485760;
-         if (config.c_maxmsglen < 8192)
-                 config.c_maxmsglen = 8192;
-         /* Default lower and upper limits on number of worker threads */
+         if (CtdlGetConfigLong("c_maxmsglen") <= 0)    CtdlSetConfigLong("c_maxmsglen", 10485760);
+         if (CtdlGetConfigLong("c_maxmsglen") < 8192)  CtdlSetConfigLong("c_maxmsglen", 8192);
  
-       if (config.c_min_workers < 3)           /* no less than 3 */
-               config.c_min_workers = 5;
-       if (config.c_max_workers == 0)                  /* default maximum */
-               config.c_max_workers = 256;
-       if (config.c_max_workers < config.c_min_workers)   /* max >= min */
-               config.c_max_workers = config.c_min_workers;
+         /*
+        * Default lower and upper limits on number of worker threads
+        */
+       if (CtdlGetConfigInt("c_min_workers") < 5)      CtdlSetConfigInt("c_min_workers", 5);   // min
+       if (CtdlGetConfigInt("c_max_workers") == 0)     CtdlSetConfigInt("c_max_workers", 256); // default max
+       if (CtdlGetConfigInt("c_max_workers") < CtdlGetConfigInt("c_min_workers")) {
+               CtdlSetConfigInt("c_max_workers", CtdlGetConfigInt("c_min_workers"));           // max >= min
+       }
  
        /* Networking more than once every five minutes just isn't sane */
-       if (config.c_net_freq == 0L)
-               config.c_net_freq = 3600L;      /* once per hour default */
-       if (config.c_net_freq < 300L) 
-               config.c_net_freq = 300L;
+       if (CtdlGetConfigLong("c_net_freq") == 0)       CtdlSetConfigLong("c_net_freq", 3600);  // once per hour default
+       if (CtdlGetConfigLong("c_net_freq") < 300)      CtdlSetConfigLong("c_net_freq", 300);   // minimum 5 minutes
  
        /* Same goes for POP3 */
-       if (config.c_pop3_fetch == 0L)
-               config.c_pop3_fetch = 3600L;    /* once per hour default */
-       if (config.c_pop3_fetch < 300L) 
-               config.c_pop3_fetch = 300L;
-       if (config.c_pop3_fastest == 0L)
-               config.c_pop3_fastest = 3600L;  /* once per hour default */
-       if (config.c_pop3_fastest < 300L) 
-               config.c_pop3_fastest = 300L;
+       if (CtdlGetConfigLong("c_pop3_fetch") == 0)     CtdlSetConfigLong("c_pop3_fetch", 3600);        // once per hour default
+       if (CtdlGetConfigLong("c_pop3_fetch") < 300)    CtdlSetConfigLong("c_pop3_fetch", 300);         // 5 minutes min
+       if (CtdlGetConfigLong("c_pop3_fastest") == 0)   CtdlSetConfigLong("c_pop3_fastest", 3600);      // once per hour default
+       if (CtdlGetConfigLong("c_pop3_fastest") < 300)  CtdlSetConfigLong("c_pop3_fastest", 300);       // 5 minutes min
  
        /* "create new user" only works with native authentication mode */
-       if (config.c_auth_mode != AUTHMODE_NATIVE) {
-               config.c_disable_newu = 1;
+       if (CtdlGetConfigInt("c_auth_mode") != AUTHMODE_NATIVE) {
+               CtdlSetConfigInt("c_disable_newu", 1);
        }
  }
  
- long config_msgnum = 0;
  
  /*
-  * Occasionally, we will need to write the config file, because some operations
-  * change site-wide parameters.
+  * Called when Citadel server is shutting down.
+  * Clears out the config hash table.
   */
- void put_config(void)
+ void shutdown_config_system(void) 
  {
-       FILE *cfp;
-       int blocks_written = 0;
+       DeleteHash(&ctdlconfig);
+ }
  
-       cfp = fopen(file_citadel_config, "w");
-       if (cfp != NULL) {
-               blocks_written = fwrite((char *) &config, sizeof(struct config), 1, cfp);
-               if (blocks_written == 1) {
-                       chown(file_citadel_config, CTDLUID, (-1));
-                       chmod(file_citadel_config, 0600);
-                       fclose(cfp);
-                       return;
-               }
-               fclose(cfp);
+ /*
+  * Set a system config value.  Simple key/value here.
+  */
+ void CtdlSetConfigStr(char *key, char *value)
+ {
+       int key_len = strlen(key);
+       int value_len = strlen(value);
+       /* FIXME we are noisy logging for now */
+       syslog(LOG_DEBUG, "\033[31mSET CONFIG: '%s' = '%s'\033[0m", key, value);
+       /* Save it in memory */
+       Put(ctdlconfig, key, key_len, strdup(value), NULL);
+       /* Also write it to the config database */
+       int dbv_size = key_len + value_len + 2;
+       char *dbv = malloc(dbv_size);
+       strcpy(dbv, key);
+       strcpy(&dbv[key_len + 1], value);
+       cdb_store(CDB_CONFIG, key, key_len, dbv, dbv_size);
+       free(dbv);
+ }
+ /*
+  * Set a numeric system config value (long integer)
+  */
+ void CtdlSetConfigLong(char *key, long value)
+ {
+       char longstr[256];
+       sprintf(longstr, "%ld", value);
+       CtdlSetConfigStr(key, longstr);
+ }
+ /*
+  * Set a numeric system config value (integer)
+  */
+ void CtdlSetConfigInt(char *key, int value)
+ {
+       char intstr[256];
+       sprintf(intstr, "%d", value);
+       CtdlSetConfigStr(key, intstr);
+ }
+ /*
+  * Fetch a system config value.  Caller does *not* own the returned value and may not alter it.
+  */
+ char *CtdlGetConfigStr(char *key)
+ {
+       char *value = NULL;
+       struct cdbdata *cdb;
+       int key_len = strlen(key);
+       if (IsEmptyStr(key)) return(NULL);
+       /* Temporary hack to make sure we didn't mess up any porting - FIXME remove this after testing thoroughly */
+       if (!strncmp(key, "config", 6)) {
+               syslog(LOG_EMERG, "You requested a key starting with 'config' which probably means a porting error: %s", key);
+               abort();
+       }
+       /* First look in memory */
+       if (GetHash(ctdlconfig, key, key_len, (void *)&value))
+       {
+               if (strcmp(key, "c_min_workers")) syslog(LOG_DEBUG, "\033[32mGET CONFIG: '%s' = '%s'\033[0m", key, value);
+               return value;
+       }
+       /* Then look in the database. */
+       cdb = cdb_fetch(CDB_CONFIG, key, key_len);
+       if (cdb == NULL) {      /* nope, not there either. */
+               syslog(LOG_DEBUG, "\033[32mGET CONFIG: '%s' = NULL\033[0m", key);
+               return(NULL);
        }
-       syslog(LOG_EMERG, "%s: %s", file_citadel_config, strerror(errno));
+       /* Got it.  Save it in memory for the next fetch. */
+       value = strdup(cdb->ptr + key_len + 1);         /* The key was stored there too; skip past it */
+       cdb_free(cdb);
+       Put(ctdlconfig, key, key_len, value, NULL);
+       syslog(LOG_DEBUG, "\033[32mGET CONFIG: '%s' = '%s'\033[0m", key, value);
+       return value;
+ }
+ /*
+  * Fetch a system config value - integer
+  */
+ int CtdlGetConfigInt(char *key)
+ {
+       char *s = CtdlGetConfigStr(key);
+       if (s) return atoi(s);
+       return 0;
  }
  
  
+ /*
+  * Fetch a system config value - long integer
+  */
+ long CtdlGetConfigLong(char *key)
+ {
+       char *s = CtdlGetConfigStr(key);
+       if (s) return atol(s);
+       return 0;
+ }
+ /**********************************************************************/
  
  void CtdlGetSysConfigBackend(long msgnum, void *userdata) {
        config_msgnum = msgnum;
@@@ -320,7 -502,7 +502,7 @@@ char *CtdlGetSysConfig(char *sysconfnam
                conf = NULL;
        }
        else {
 -              msg = CtdlFetchMessage(msgnum, 1);
 +              msg = CtdlFetchMessage(msgnum, 1, 1);
                if (msg != NULL) {
                        conf = strdup(msg->cm_fields[eMesageText]);
                        CM_Free(msg);
diff --combined citadel/control.c
index 2a608eee014a24a78887f6a0c9e62c593dc57208,681381f25a9a4d0c0271d38ecd9629723e89a053..2339f07f4b180aa1dcabd6a61c35f2d878f593df
@@@ -1,15 -1,15 +1,15 @@@
  /*
   * This module handles states which are global to the entire server.
   *
-  * Copyright (c) 1987-2014 by the citadel.org team
+  * Copyright (c) 1987-2015 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 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.
+  * 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 <stdio.h>
  #include "citserver.h"
  #include "user_ops.h"
  
- struct CitControl CitControl;
- extern struct config config;
- FILE *control_fp = NULL;
  long control_highest_user = 0;
  
  /*
-  * lock_control  -  acquire a lock on the control record file.
-  *                  This keeps multiple citservers from running concurrently.
+  * This is the control record for the message base... 
   */
- void lock_control(void)
- {
- #if defined(LOCK_EX) && defined(LOCK_NB)
-       if (flock(fileno(control_fp), (LOCK_EX | LOCK_NB))) {
-               syslog(LOG_EMERG, "citserver: unable to lock %s.\n", file_citadel_control);
-               syslog(LOG_EMERG, "Is another citserver already running?\n");
-               exit(CTDLEXIT_CONTROL);
-       }
- #endif
- }
+ 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 control file
@@@ -55,9 -52,9 +52,9 @@@ void control_find_highest(struct ctdlro
        int room_fixed = 0;
        int message_fixed = 0;
        
-       if (qrbuf->QRnumber > CitControl.MMnextroom)
+       if (qrbuf->QRnumber > CtdlGetConfigLong("MMnextroom"))
        {
-               CitControl.MMnextroom = qrbuf->QRnumber;
+               CtdlSetConfigLong("MMnextroom", qrbuf->QRnumber);
                room_fixed = 1;
        }
                
        {
                for (c=0; c<num_msgs; c++)
                {
-                       if (msglist[c] > CitControl.MMhighest)
+                       if (msglist[c] > CtdlGetConfigLong("MMhighest"))
                        {
-                               CitControl.MMhighest = msglist[c];
+                               CtdlSetConfigLong("MMhighest", msglist[c]);
                                message_fixed = 1;
                        }
                }
        }
        cdb_free(cdbfr);
-       if (room_fixed)
+       if (room_fixed) {
                syslog(LOG_INFO, "Control record checking....Fixed room counter\n");
-       if (message_fixed)
+       }
+       if (message_fixed) {
                syslog(LOG_INFO, "Control record checking....Fixed message count\n");
+       }
        return;
  }
  
@@@ -100,9 -99,9 +99,9 @@@ void control_find_user (struct ctdluse
  {
        int user_fixed = 0;
        
-       if (EachUser->usernum > CitControl.MMnextuser)
+       if (EachUser->usernum > CtdlGetConfigLong("MMnextuser"))
        {
-               CitControl.MMnextuser = EachUser->usernum;
+               CtdlSetConfigLong("MMnextuser", EachUser->usernum);
                user_fixed = 1;
        }
        if(user_fixed)
  
  
  /*
-  * get_control  -  read the control record into memory.
+  * If we have a legacy format control record on disk, import it.
   */
- void get_control(void)
+ void migrate_legacy_control_record(void)
  {
-       static int already_have_control = 0;
-       int rv = 0;
-       /*
-        * If we already have the control record in memory, there's no point
-        * in reading it from disk again.
-        */
-       if (already_have_control) return;
-       /* 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(file_citadel_control, "rb+");
-               if (control_fp != NULL) {
-                       lock_control();
-                       rv = fchown(fileno(control_fp), config.c_ctdluid, -1);
-                       if (rv == -1)
-                               syslog(LOG_EMERG, "Failed to adjust ownership of: %s [%s]\n", 
-                                      file_citadel_control, strerror(errno));
-                       rv = fchmod(fileno(control_fp), S_IRUSR|S_IWUSR);
-                       if (rv == -1)
-                               syslog(LOG_EMERG, "Failed to adjust accessrights of: %s [%s]\n", 
-                                      file_citadel_control, strerror(errno));
-               }
-       }
-       if (control_fp == NULL) {
-               control_fp = fopen(file_citadel_control, "wb+");
-               if (control_fp != NULL) {
-                       lock_control();
-                       memset(&CitControl, 0, sizeof(struct CitControl));
-                       rv = fchown(fileno(control_fp), config.c_ctdluid, -1);
-                       if (rv == -1)
-                               syslog(LOG_EMERG, "Failed to adjust ownership of: %s [%s]\n", 
-                                      file_citadel_control, strerror(errno));
-                       rv = fchmod(fileno(control_fp), S_IRUSR|S_IWUSR);
-                       if (rv == -1)
-                               syslog(LOG_EMERG, "Failed to adjust accessrights of: %s [%s]\n", 
-                                      file_citadel_control, strerror(errno));
-                       rv = fwrite(&CitControl, sizeof(struct CitControl), 1, control_fp);
-                       if (rv == -1)
-                               syslog(LOG_EMERG, "Failed to write: %s [%s]\n", 
-                                      file_citadel_control, strerror(errno));
-                       rewind(control_fp);
+       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, "Legacy format control 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);
+               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);
                }
        }
-       if (control_fp == NULL) {
-               syslog(LOG_ALERT, "ERROR opening %s: %s\n", file_citadel_control, strerror(errno));
-               return;
-       }
-       rewind(control_fp);
-       rv = fread(&CitControl, sizeof(struct CitControl), 1, control_fp);
-       if (rv == -1)
-               syslog(LOG_EMERG, "Failed to read Controlfile: %s [%s]\n", 
-                      file_citadel_control, strerror(errno));
-       already_have_control = 1;
-       rv = chown(file_citadel_control, config.c_ctdluid, (-1));
-       if (rv == -1)
-               syslog(LOG_EMERG, "Failed to adjust ownership of: %s [%s]\n", 
-                      file_citadel_control, strerror(errno));  
- }
- /*
-  * put_control  -  write the control record to disk.
-  */
- void put_control(void)
- {
-       int rv = 0;
-       if (control_fp != NULL) {
-               rewind(control_fp);
-               rv = fwrite(&CitControl, sizeof(struct CitControl), 1, control_fp);
-               if (rv == -1)
-                       syslog(LOG_EMERG, "Failed to write: %s [%s]\n", 
-                              file_citadel_control, strerror(errno));
-               fflush(control_fp);
-       }
  }
  
  
 -
 -
 -
  /*
   * check_control   -  check the control record has sensible values for message, user and room numbers
   */
  void check_control(void)
  {
-       syslog(LOG_INFO, "Checking/re-building control record\n");
-       get_control();
-       // Find highest room number and message number.
+       syslog(LOG_INFO, "Sanity checking the recorded highest message, user, and room numbers\n");
        CtdlForEachRoom(control_find_highest, NULL);
        ForEachUser(control_find_user, NULL);
-       put_control();
  }
  
  
- /*
-  * release_control - close our fd on exit
-  */
- void release_control(void)
- {
-       if (control_fp != NULL) {
-               fclose(control_fp);
-       }
-       control_fp = NULL;
- }
  
  /*
   * get_new_message_number()  -  Obtain a new, unique ID to be used for a message.
@@@ -232,9 -163,9 +160,9 @@@ long get_new_message_number(void
  {
        long retval = 0L;
        begin_critical_section(S_CONTROL);
-       get_control();
-       retval = ++CitControl.MMhighest;
-       put_control();
+       retval = CtdlGetConfigLong("MMhighest");
+       ++retval;
+       CtdlSetConfigLong("MMhighest", retval);
        end_critical_section(S_CONTROL);
        return(retval);
  }
   * 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)
  {
-       long retval = 0L;
-       begin_critical_section(S_CONTROL);
-       get_control();
-       retval = CitControl.MMhighest;
-       end_critical_section(S_CONTROL);
-       return(retval);
+       return CtdlGetConfigLong("MMhighest");
  }
  
  
@@@ -264,9 -192,9 +189,9 @@@ long get_new_user_number(void
  {
        long retval = 0L;
        begin_critical_section(S_CONTROL);
-       get_control();
-       retval = ++CitControl.MMnextuser;
-       put_control();
+       retval = CtdlGetConfigLong("MMnextuser");
+       ++retval;
+       CtdlSetConfigLong("MMnextuser", retval);
        end_critical_section(S_CONTROL);
        return(retval);
  }
@@@ -280,15 -208,26 +205,26 @@@ long get_new_room_number(void
  {
        long retval = 0L;
        begin_critical_section(S_CONTROL);
-       get_control();
-       retval = ++CitControl.MMnextroom;
-       put_control();
+       retval = CtdlGetConfigLong("MMnextroom");
+       ++retval;
+       CtdlSetConfigLong("MMnextroom", retval);
        end_critical_section(S_CONTROL);
        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
   *
@@@ -300,7 -239,8 +236,8 @@@ void cmd_conf(char *argbuf
  {
        char cmd[16];
        char buf[256];
-       int a;
+       int a, i;
+       long ii;
        char *confptr;
        char confname[128];
  
        extract_token(cmd, argbuf, 0, '|', sizeof cmd);
        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_site_location);
-               cprintf("%s\n", config.c_sysadm);
-               cprintf("%d\n", config.c_maxsessions);
+               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", 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_rfc822_strict_from);
-               cprintf("%d\n", config.c_aide_zap);
-               cprintf("%d\n", config.c_imap_port);
-               cprintf("%ld\n", config.c_net_freq);
-               cprintf("%d\n", config.c_disable_newu);
+               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", config.c_purge_hour);
+               cprintf("%d\n",         CtdlGetConfigInt("c_purge_hour"));
  #ifdef HAVE_LDAP
-               cprintf("%s\n", config.c_ldap_host);
-               cprintf("%d\n", config.c_ldap_port);
-               cprintf("%s\n", config.c_ldap_base_dn);
-               cprintf("%s\n", config.c_ldap_bind_dn);
-               cprintf("%s\n", config.c_ldap_bind_pw);
+               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");
  #endif
-               cprintf("%s\n", config.c_ip_addr);
-               cprintf("%d\n", config.c_msa_port);
-               cprintf("%d\n", config.c_imaps_port);
-               cprintf("%d\n", config.c_pop3s_port);
-               cprintf("%d\n", config.c_smtps_port);
-               cprintf("%d\n", config.c_enable_fulltext);
-               cprintf("%d\n", config.c_auto_cull);
+               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", config.c_allow_spoofing);
-               cprintf("%d\n", config.c_journal_email);
-               cprintf("%d\n", config.c_journal_pubmsgs);
-               cprintf("%s\n", config.c_journal_dest);
-               cprintf("%s\n", config.c_default_cal_zone);
-               cprintf("%d\n", config.c_pftcpdict_port);
-               cprintf("%d\n", config.c_managesieve_port);
-               cprintf("%d\n", config.c_auth_mode);
-               cprintf("%s\n", config.c_funambol_host);
-               cprintf("%d\n", config.c_funambol_port);
-               cprintf("%s\n", config.c_funambol_source);
-               cprintf("%s\n", config.c_funambol_auth);
-               cprintf("%d\n", config.c_rbl_at_greeting);
-               cprintf("%s\n", config.c_master_user);
-               cprintf("%s\n", config.c_master_pass);
-               cprintf("%s\n", config.c_pager_program);
-               cprintf("%d\n", config.c_imap_keep_from);
-               cprintf("%d\n", config.c_xmpp_c2s_port);
-               cprintf("%d\n", config.c_xmpp_s2s_port);
-               cprintf("%ld\n", config.c_pop3_fetch);
-               cprintf("%ld\n", config.c_pop3_fastest);
-               cprintf("%d\n", config.c_spam_flag_only);
-               cprintf("%d\n", config.c_guest_logins);
-               cprintf("%d\n", config.c_port_number);
-               cprintf("%d\n", config.c_ctdluid);
-               cprintf("%d\n", config.c_nntp_port);
-               cprintf("%d\n", config.c_nntps_port);
+               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("%s\n",         CtdlGetConfigStr("c_funambol_host"));
+               cprintf("%d\n",         CtdlGetConfigInt("c_funambol_port"));
+               cprintf("%s\n",         CtdlGetConfigStr("c_funambol_source"));
+               cprintf("%s\n",         CtdlGetConfigStr("c_funambol_auth"));
+               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");
        }
  
                while (client_getln(buf, sizeof buf) >= 0 && strcmp(buf, "000")) {
                        switch (a) {
                        case 0:
-                               configlen.c_nodename = safestrncpy(config.c_nodename, buf,
-                                                                  sizeof config.c_nodename);
+                               CtdlSetConfigStr("c_nodename", buf);
                                break;
                        case 1:
-                               configlen.c_fqdn = safestrncpy(config.c_fqdn, buf,
-                                                              sizeof config.c_fqdn);
+                               CtdlSetConfigStr("c_fqdn", buf);
                                break;
                        case 2:
-                               configlen.c_humannode = safestrncpy(config.c_humannode, buf,
-                                                                   sizeof config.c_humannode);
+                               CtdlSetConfigStr("c_humannode", buf);
                                break;
                        case 3:
-                               configlen.c_phonenum = safestrncpy(config.c_phonenum, buf,
-                                                                  sizeof config.c_phonenum);
+                               /* placeholder -- field no longer in use */
                                break;
                        case 4:
-                               config.c_creataide = atoi(buf);
+                               CtdlSetConfigInt("c_creataide", atoi(buf));
                                break;
                        case 5:
-                               config.c_sleeping = atoi(buf);
+                               CtdlSetConfigInt("c_sleeping", atoi(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;
+                               i = atoi(buf);
+                               if (i < 1) i = 1;
+                               if (i > 6) i = 6;
+                               CtdlSetConfigInt("c_initax", i);
                                break;
                        case 7:
-                               config.c_regiscall = atoi(buf);
-                               if (config.c_regiscall != 0)
-                                       config.c_regiscall = 1;
+                               CtdlSetConfigInt("c_regiscall", confbool(buf));
                                break;
                        case 8:
-                               config.c_twitdetect = atoi(buf);
-                               if (config.c_twitdetect != 0)
-                                       config.c_twitdetect = 1;
+                               CtdlSetConfigInt("c_twitdetect", confbool(buf));
                                break;
                        case 9:
-                               configlen.c_twitroom = safestrncpy(config.c_twitroom, buf,
-                                                                  sizeof config.c_twitroom);
+                               CtdlSetConfigStr("c_twitroom", buf);
                                break;
                        case 10:
-                               configlen.c_moreprompt = safestrncpy(config.c_moreprompt, buf,
-                                                                    sizeof config.c_moreprompt);
+                               CtdlSetConfigStr("c_moreprompt", buf);
                                break;
                        case 11:
-                               config.c_restrict = atoi(buf);
-                               if (config.c_restrict != 0)
-                                       config.c_restrict = 1;
+                               CtdlSetConfigInt("c_restrict", confbool(buf));
                                break;
                        case 12:
-                               configlen.c_site_location = safestrncpy(
-                                       config.c_site_location, buf,
-                                       sizeof config.c_site_location);
+                               CtdlSetConfigInt("c_site_location", confbool(buf));
                                break;
                        case 13:
-                               configlen.c_sysadm = safestrncpy(config.c_sysadm, buf,
-                                                                sizeof config.c_sysadm);
+                               CtdlSetConfigInt("c_sysadm", confbool(buf));
                                break;
                        case 14:
-                               config.c_maxsessions = atoi(buf);
-                               if (config.c_maxsessions < 0)
-                                       config.c_maxsessions = 0;
+                               i = atoi(buf);
+                               if (i < 0) i = 0;
+                               CtdlSetConfigInt("c_maxsessions", i);
                                break;
                        case 15:
                                /* placeholder -- field no longer in use */
                                break;
                        case 16:
-                               config.c_userpurge = atoi(buf);
+                               CtdlSetConfigInt("c_userpurge", atoi(buf));
                                break;
                        case 17:
-                               config.c_roompurge = atoi(buf);
+                               CtdlSetConfigInt("c_roompurge", atoi(buf));
                                break;
                        case 18:
-                               configlen.c_logpages = safestrncpy(config.c_logpages, buf,
-                                                                  sizeof config.c_logpages);
+                               CtdlSetConfigStr("c_logpages", 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;
+                               i = atoi(buf);
+                               if (i < 1) i = 1;
+                               if (i > 6) i = 6;
+                               CtdlSetConfigInt("c_createax", i);
                                break;
                        case 20:
-                               if (atoi(buf) >= 8192)
-                                       config.c_maxmsglen = atoi(buf);
+                               ii = atol(buf);
+                               if (ii >= 8192) {
+                                       CtdlSetConfigLong("c_maxmsglen", ii);
+                               }
                                break;
                        case 21:
-                               if (atoi(buf) >= 2)
-                                       config.c_min_workers = atoi(buf);
+                               i = atoi(buf);
+                               if (i >= 3) {                                   // minimum value
+                                       CtdlSetConfigInt("c_min_workers", i);
+                               }
+                               break;
                        case 22:
-                               if (atoi(buf) >= config.c_min_workers)
-                                       config.c_max_workers = atoi(buf);
+                               i = atoi(buf);
+                               if (i >= CtdlGetConfigInt("c_min_workers")) {   // max must be >= min
+                                       CtdlSetConfigInt("c_max_workers", i);
+                               }
+                               break;
                        case 23:
-                               config.c_pop3_port = atoi(buf);
+                               CtdlSetConfigInt("c_pop3_port", atoi(buf));
                                break;
                        case 24:
-                               config.c_smtp_port = atoi(buf);
+                               CtdlSetConfigInt("c_smtp_port", atoi(buf));
                                break;
                        case 25:
-                               config.c_rfc822_strict_from = atoi(buf);
+                               CtdlSetConfigInt("c_rfc822_strict_from", atoi(buf));
                                break;
                        case 26:
-                               config.c_aide_zap = atoi(buf);
-                               if (config.c_aide_zap != 0)
-                                       config.c_aide_zap = 1;
+                               CtdlSetConfigInt("c_aide_zap", confbool(buf));
                                break;
                        case 27:
-                               config.c_imap_port = atoi(buf);
+                               CtdlSetConfigInt("c_imap_port", atoi(buf));
                                break;
                        case 28:
-                               config.c_net_freq = atol(buf);
+                               CtdlSetConfigLong("c_net_freq", atol(buf));
                                break;
                        case 29:
-                               config.c_disable_newu = atoi(buf);
-                               if (config.c_disable_newu != 0)
-                                       config.c_disable_newu = 1;
+                               CtdlSetConfigInt("c_disable_newu", confbool(buf));
                                break;
                        case 30:
                                /* niu */
                                break;
                        case 31:
-                               if ((config.c_purge_hour >= 0)
-                                   && (config.c_purge_hour <= 23)) {
-                                       config.c_purge_hour = atoi(buf);
+                               i = atoi(buf);
+                               if ((i >= 0) && (i <= 23)) {
+                                       CtdlSetConfigInt("c_purge_hour", i);
                                }
                                break;
- #ifdef HAVE_LDAP
                        case 32:
-                               configlen.c_ldap_host = safestrncpy(config.c_ldap_host, buf,
-                                                                   sizeof config.c_ldap_host);
+                               CtdlSetConfigStr("c_ldap_host", buf);
                                break;
                        case 33:
-                               config.c_ldap_port = atoi(buf);
+                               CtdlSetConfigInt("c_ldap_port", atoi(buf));
                                break;
                        case 34:
-                               configlen.c_ldap_base_dn = safestrncpy(config.c_ldap_base_dn, buf,
-                                                                      sizeof config.c_ldap_base_dn);
+                               CtdlSetConfigStr("c_ldap_base_dn", buf);
                                break;
                        case 35:
-                               configlen.c_ldap_bind_dn = safestrncpy(config.c_ldap_bind_dn, buf,
-                                                                      sizeof config.c_ldap_bind_dn);
+                               CtdlSetConfigStr("c_ldap_bind_dn", buf);
                                break;
                        case 36:
-                               configlen.c_ldap_bind_pw = safestrncpy(config.c_ldap_bind_pw, buf,
-                                                                      sizeof config.c_ldap_bind_pw);
+                               CtdlSetConfigStr("c_ldap_bind_pw", buf);
                                break;
- #endif
                        case 37:
-                               configlen.c_ip_addr = safestrncpy(config.c_ip_addr, buf,
-                                                                 sizeof config.c_ip_addr);
+                               CtdlSetConfigStr("c_ip_addr", buf);
+                               break;
                        case 38:
-                               config.c_msa_port = atoi(buf);
+                               CtdlSetConfigInt("c_msa_port", atoi(buf));
                                break;
                        case 39:
-                               config.c_imaps_port = atoi(buf);
+                               CtdlSetConfigInt("c_imaps_port", atoi(buf));
                                break;
                        case 40:
-                               config.c_pop3s_port = atoi(buf);
+                               CtdlSetConfigInt("c_pop3s_port", atoi(buf));
                                break;
                        case 41:
-                               config.c_smtps_port = atoi(buf);
+                               CtdlSetConfigInt("c_smtps_port", atoi(buf));
                                break;
                        case 42:
-                               config.c_enable_fulltext = atoi(buf);
+                               CtdlSetConfigInt("c_enable_fulltext", confbool(buf));
                                break;
                        case 43:
-                               config.c_auto_cull = atoi(buf);
+                               CtdlSetConfigInt("c_auto_cull", confbool(buf));
                                break;
                        case 44:
                                /* niu */
                                break;
                        case 45:
-                               config.c_allow_spoofing = atoi(buf);
+                               CtdlSetConfigInt("c_allow_spoofing", confbool(buf));
                                break;
                        case 46:
-                               config.c_journal_email = atoi(buf);
+                               CtdlSetConfigInt("c_journal_email", confbool(buf));
                                break;
                        case 47:
-                               config.c_journal_pubmsgs = atoi(buf);
+                               CtdlSetConfigInt("c_journal_pubmsgs", confbool(buf));
                                break;
                        case 48:
-                               configlen.c_journal_dest = safestrncpy(config.c_journal_dest, buf,
-                                                                      sizeof config.c_journal_dest);
+                               CtdlSetConfigStr("c_journal_dest", buf);
+                               break;
                        case 49:
-                               configlen.c_default_cal_zone = safestrncpy(
-                                       config.c_default_cal_zone, buf,
-                                       sizeof config.c_default_cal_zone);
+                               CtdlSetConfigStr("c_default_cal_zone", buf);
                                break;
                        case 50:
-                               config.c_pftcpdict_port = atoi(buf);
+                               CtdlSetConfigInt("c_pftcpdict_port", atoi(buf));
                                break;
                        case 51:
-                               config.c_managesieve_port = atoi(buf);
+                               CtdlSetConfigInt("c_managesieve_port", atoi(buf));
                                break;
                        case 52:
-                               config.c_auth_mode = atoi(buf);
+                               CtdlSetConfigInt("c_auth_mode", atoi(buf));
+                               break;
                        case 53:
-                               configlen.c_funambol_host = safestrncpy(
-                                       config.c_funambol_host, buf,
-                                       sizeof config.c_funambol_host);
+                               CtdlSetConfigStr("c_funambol_host", buf);
                                break;
                        case 54:
-                               config.c_funambol_port = atoi(buf);
+                               CtdlSetConfigInt("c_funambol_port", atoi(buf));
                                break;
                        case 55:
-                               configlen.c_funambol_source = safestrncpy(
-                                       config.c_funambol_source, buf, 
-                                       sizeof config.c_funambol_source);
+                               CtdlSetConfigStr("c_funambol_source", buf);
                                break;
                        case 56:
-                               configlen.c_funambol_auth = safestrncpy(
-                                       config.c_funambol_auth, buf,
-                                       sizeof config.c_funambol_auth);
+                               CtdlSetConfigStr("c_funambol_auth", buf);
                                break;
                        case 57:
-                               config.c_rbl_at_greeting = atoi(buf);
+                               CtdlSetConfigInt("c_rbl_at_greeting", confbool(buf));
                                break;
                        case 58:
-                               configlen.c_master_user = safestrncpy(
-                                       config.c_master_user,
-                                       buf, sizeof config.c_master_user);
+                               CtdlSetConfigStr("c_master_user", buf);
                                break;
                        case 59:
-                               configlen.c_master_pass = safestrncpy(
-                                       config.c_master_pass, buf, sizeof config.c_master_pass);
+                               CtdlSetConfigStr("c_master_pass", buf);
                                break;
                        case 60:
-                               configlen.c_pager_program = safestrncpy(
-                                       config.c_pager_program, buf, sizeof config.c_pager_program);
+                               CtdlSetConfigStr("c_pager_program", buf);
                                break;
                        case 61:
-                               config.c_imap_keep_from = atoi(buf);
+                               CtdlSetConfigInt("c_imap_keep_from", confbool(buf));
                                break;
                        case 62:
-                               config.c_xmpp_c2s_port = atoi(buf);
+                               CtdlSetConfigInt("c_xmpp_c2s_port", atoi(buf));
                                break;
                        case 63:
-                               config.c_xmpp_s2s_port = atoi(buf);
+                               CtdlSetConfigInt("c_xmpp_s2s_port", atoi(buf));
                                break;
                        case 64:
-                               config.c_pop3_fetch = atol(buf);
+                               CtdlSetConfigLong("c_pop3_fetch", atol(buf));
                                break;
                        case 65:
-                               config.c_pop3_fastest = atol(buf);
+                               CtdlSetConfigLong("c_pop3_fastest", atol(buf));
                                break;
                        case 66:
-                               config.c_spam_flag_only = atoi(buf);
+                               CtdlSetConfigInt("c_spam_flag_only", confbool(buf));
                                break;
                        case 67:
-                               config.c_guest_logins = atoi(buf);
+                               CtdlSetConfigInt("c_guest_logins", confbool(buf));
                                break;
                        case 68:
-                               config.c_port_number = atoi(buf);
+                               CtdlSetConfigInt("c_port_number", atoi(buf));
                                break;
                        case 69:
-                               config.c_ctdluid = atoi(buf);
+                               /* niu */
                                break;
                        case 70:
-                               config.c_nntp_port = atoi(buf);
+                               CtdlSetConfigInt("c_nntp_port", atoi(buf));
                                break;
                        case 71:
-                               config.c_nntps_port = atoi(buf);
+                               CtdlSetConfigInt("c_nntps_port", atoi(buf));
                                break;
                        }
                        ++a;
                }
-               put_config();
                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(config.c_logpages))
-                       CtdlCreateRoom(config.c_logpages, 3, "", 0, 1, 1, VIEW_BBS);
+               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 (config.c_enable_fulltext == 0) {
-                       CitControl.fulltext_wordbreaker = 0;
-                       put_control();
+               if (CtdlGetConfigInt("c_enable_fulltext") == 0) {
+                       CtdlSetConfigInt("MM_fulltext_wordbreaker", 0);
                }
        }
  
                extract_token(confname, argbuf, 1, '|', sizeof confname);
                unbuffer_output();
                cprintf("%d %s\n", SEND_LISTING, confname);
-               confptr = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
+               confptr = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0, 0);
                CtdlPutSysConfig(confname, confptr);
                free(confptr);
        }
@@@ -758,7 -665,7 +662,7 @@@ void cmd_gvdn(char *argbuf
        void *vptr;
        
        List = NewHash(1, NULL);
-       Cfg = NewStrBufPlain(config.c_fqdn, -1);
+       Cfg = NewStrBufPlain(CtdlGetConfigStr("c_fqdn"), -1);
        Put(List, SKEY(Cfg), Cfg, HFreeStrBuf);
        Cfg = NULL;
  
diff --combined citadel/database.c
index dbcccf5b16b1a51ce3b7c17136d08f3f849022f7,fd7730d42aaee22cdc46922467a35e802c899bd6..de1be0d2ca34666e5e9a53c308262353eafb3e56
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * This is a data store backend for the Citadel server which uses Berkeley DB.
   *
-  * Copyright (c) 1987-2012 by the citadel.org team
+  * Copyright (c) 1987-2015 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.
@@@ -50,6 -50,7 +50,7 @@@
  #include "ctdl_module.h"
  #include "control.h"
  #include "citserver.h"
+ #include "config.h"
  
  
  static DB *dbp[MAXCDB];               /* One DB handle for each Citadel database */
@@@ -223,7 -224,7 +224,7 @@@ void cdb_checkpoint(void
        }
  
        /* After a successful checkpoint, we can cull the unused logs */
-       if (config.c_auto_cull) {
+       if (CtdlGetConfigInt("c_auto_cull")) {
                cdb_cull_logs();
        }
  }
@@@ -243,30 -244,10 +244,10 @@@ void open_databases(void
        char dbfilename[32];
        u_int32_t flags = 0;
        int dbversion_major, dbversion_minor, dbversion_patch;
-       int current_dbversion = 0;
  
        syslog(LOG_DEBUG, "bdb(): open_databases() starting");
        syslog(LOG_DEBUG, "Compiled db: %s", DB_VERSION_STRING);
-       syslog(LOG_INFO, "  Linked db: %s",
-               db_version(&dbversion_major, &dbversion_minor, &dbversion_patch));
-       current_dbversion = (dbversion_major * 1000000) + (dbversion_minor * 1000) + dbversion_patch;
-       syslog(LOG_DEBUG, "Calculated dbversion: %d", current_dbversion);
-       syslog(LOG_DEBUG, "  Previous dbversion: %d", CitControl.MMdbversion);
-       if ( (getenv("SUPPRESS_DBVERSION_CHECK") == NULL)
-          && (CitControl.MMdbversion > current_dbversion) ) {
-               syslog(LOG_EMERG, "You are attempting to run the Citadel server using a version");
-               syslog(LOG_EMERG, "of Berkeley DB that is older than that which last created or");
-               syslog(LOG_EMERG, "updated the database.  Because this would probably cause data");
-               syslog(LOG_EMERG, "corruption or loss, the server is aborting execution now.");
-               exit(CTDLEXIT_DB);
-       }
-       CitControl.MMdbversion = current_dbversion;
-       put_control();
+       syslog(LOG_INFO, "  Linked db: %s", db_version(&dbversion_major, &dbversion_minor, &dbversion_patch));
        syslog(LOG_INFO, "Linked zlib: %s\n", zlibVersion());
  
        /*
@@@ -935,10 -916,8 +916,10 @@@ time_t CheckIfAlreadySeen(const char *F
                else
                {
                        if (cdbut) cdb_free(cdbut);
 -
 +                      
                        SEENM_syslog(LOG_DEBUG, "not Found");
 +                      if (cType == eCheckUpdate)
 +                              return 0;
                }
  
                if (cType == eCheckExist)
diff --combined citadel/ical_dezonify.c
index 41c67a7e7556261649db1aac46e37e2b7f7e6d6e,34c0e4bff64e77c381d6a9f3e44c300af1fb3cab..cc3c60efc1b5d9ce3f1aae23ab5d4d7114425b30
@@@ -2,6 -2,16 +2,6 @@@
   * Function to go through an ical component set and convert all non-UTC
   * date/time properties to UTC.  It also strips out any VTIMEZONE
   * subcomponents afterwards, because they're irrelevant.
 - *
 - * Copyright (c) 1987-2015 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.
   */
  
  
@@@ -34,8 -44,7 +34,7 @@@
  icaltimezone *get_default_icaltimezone(void) {
  
          icaltimezone *zone = NULL;
-       char *default_zone_name = config.c_default_cal_zone;
-       //char *default_zone_name = "America/New_York";
+       char *default_zone_name = CtdlGetConfigStr("c_default_cal_zone");
  
          if (!zone) {
                  zone = icaltimezone_get_builtin_timezone(default_zone_name);
index a91308639cbfb4737662a3456d80e26e6cf13c8f,ba6a881c88a14a5743f922e277540752663f2128..17f88fc654177a9e0a12c72f7e7525439f7dc7fa
@@@ -240,7 -240,7 +240,7 @@@ unsigned CtdlCreateRoom(char *new_room_
                        int avoid_access,
                        int new_room_view);
  int CtdlGetRoom(struct ctdlroom *qrbuf, const char *room_name);
 -int CtdlGetRoomLock(struct ctdlroom *qrbuf, char *room_name);
 +int CtdlGetRoomLock(struct ctdlroom *qrbuf, const char *room_name);
  int CtdlDoIHavePermissionToDeleteThisRoom(struct ctdlroom *qr);
  void CtdlRoomAccess(struct ctdlroom *roombuf, struct ctdluser *userbuf, int *result, int *view);
  void CtdlPutRoomLock(struct ctdlroom *qrbuf);
@@@ -299,134 -299,14 +299,14 @@@ enum 
   */
  void CtdlModuleDoSearch(int *num_msgs, long **search_msgs, const char *search_string, const char *func_name);
  
- /* 
-  * Global system configuration
-  */
- struct config {
-       char c_nodename[16];            /* short name of this node on a Citadel network */
-       char c_fqdn[64];                /* this site's fully qualified domain name */
-       char c_humannode[21];           /* human-readable site name */
-       char c_phonenum[16];            /* telephone number */
-       uid_t c_ctdluid;                /* uid of posix account under which Citadel will run */
-       char c_creataide;               /* 1 = creating a room auto-grants room aide privileges */
-       int c_sleeping;                 /* watchdog timer (seconds) */
-       char c_initax;                  /* initial access level for new users */
-       char c_regiscall;               /* after c_regiscall logins user will be asked to register */
-       char c_twitdetect;              /* automatically move messages from problem users to trashcan */
-       char c_twitroom[ROOMNAMELEN];   /* name of trashcan */
-       char c_moreprompt[80];          /* paginator prompt */
-       char c_restrict;                /* require per-user permission to send Internet mail */
-       long c_niu_1;
-       char c_site_location[32];       /* geographic location of this Citadel site */
-       char c_sysadm[26];              /* name of system administrator */
-       char c_niu_2[15];
-       int c_niu_3;
-       int c_maxsessions;              /* maximum number of concurrent sessions allowed */
-       char c_ip_addr[20];             /* bind address for listening sockets */
-       int c_port_number;              /* port number for Citadel protocol (usually 504) */
-       int c_niu_4;
-       struct ExpirePolicy c_ep;       /* default expire policy for the entire site */
-       int c_userpurge;                /* user purge time (in days) */
-       int c_roompurge;                /* room purge time (in days) */
-       char c_logpages[ROOMNAMELEN];
-       char c_createax;
-       long c_maxmsglen;
-       int c_min_workers;
-       int c_max_workers;
-       int c_pop3_port;
-       int c_smtp_port;
-       int c_rfc822_strict_from;
-       int c_aide_zap;
-       int c_imap_port;
-       time_t c_net_freq;
-       char c_disable_newu;
-       char c_enable_fulltext;
-       char c_baseroom[ROOMNAMELEN];
-       char c_aideroom[ROOMNAMELEN];
-       int c_purge_hour;
-       struct ExpirePolicy c_mbxep;
-       char c_ldap_host[128];
-       int c_ldap_port;
-       char c_ldap_base_dn[256];
-       char c_ldap_bind_dn[256];
-       char c_ldap_bind_pw[256];
-       int c_msa_port;
-       int c_imaps_port;
-       int c_pop3s_port;
-       int c_smtps_port;
-       char c_auto_cull;
-       char c_niu_5;
-       char c_allow_spoofing;
-       char c_journal_email;
-       char c_journal_pubmsgs;
-       char c_journal_dest[128];
-       char c_default_cal_zone[128];
-       int c_pftcpdict_port;
-       int c_managesieve_port;
-       int c_auth_mode;
-       char c_funambol_host[256];
-       int c_funambol_port;
-       char c_funambol_source[256];
-       char c_funambol_auth[256];
-       char c_rbl_at_greeting;
-       char c_master_user[32];
-       char c_master_pass[32];
-       char c_pager_program[256];
-       char c_imap_keep_from;
-       int c_xmpp_c2s_port;
-       int c_xmpp_s2s_port;
-       time_t c_pop3_fetch;
-       time_t c_pop3_fastest;
-       int c_spam_flag_only;
-       int c_guest_logins;
-       int c_nntp_port;
-       int c_nntps_port;
- };
- struct configlen {
-       long c_nodename;
-       long c_fqdn;
-       long c_humannode;
-       long c_phonenum;
-       long c_twitroom;
-       long c_moreprompt;
-       long c_site_location;
-       long c_sysadm;
-       long c_niu_2;
-       long c_ip_addr;
-       long c_logpages;
-       long c_baseroom;
-       long c_aideroom;
-       long c_ldap_host;
-       long c_ldap_base_dn;
-       long c_ldap_bind_dn;
-       long c_ldap_bind_pw;
-       long c_journal_dest;
-       long c_default_cal_zone;
-       long c_funambol_host;
-       long c_funambol_source;
-       long c_funambol_auth;
-       long c_master_user;
-       long c_master_pass;
-       long c_pager_program;
- };
- #define SET_CFGSTRBUF(which, buffer) configlen.which = safestrncpy(config.which, ChrPtr(buffer), sizeof(config.which))
- #define SET_CFGSTR(which, buffer) configlen.which = safestrncpy(config.which, buffer, sizeof(config.which))
- extern struct config config;
- extern struct configlen configlen;
- #define NODENAME              config.c_nodename
- #define FQDN                  config.c_fqdn
- #define CTDLUID                       config.c_ctdluid
- #define CREATAIDE             config.c_creataide
- #define REGISCALL             config.c_regiscall
- #define TWITDETECT            config.c_twitdetect
- #define TWITROOM              config.c_twitroom
- #define RESTRICT_INTERNET     config.c_restrict
- #define CFG_KEY(which) config.which, configlen.which
+ #define NODENAME              CtdlGetConfigStr("c_nodename")
+ #define FQDN                  CtdlGetConfigStr("c_fqdn")
+ #define CTDLUID                       ctdluid
+ #define CREATAIDE             CtdlGetConfigInt("c_creataide")
+ #define REGISCALL             CtdlGetConfigInt("c_regiscall")
+ #define TWITDETECT            CtdlGetConfigInt("c_twitdetect")
+ #define TWITROOM              CtdlGetConfigStr("c_twitroom")
+ #define RESTRICT_INTERNET     CtdlGetConfigInt("c_restrict")
  
  typedef void (*CfgLineParser)(const CfgLineType *ThisOne, StrBuf *Line, const char *LinePos, OneRoomNetCfg *rncfg);
  typedef void (*CfgLineSerializer)(const CfgLineType *ThisOne, StrBuf *OuptputBuffer, OneRoomNetCfg *rncfg, RoomNetCfgLine *data);
index 146cc292d6e613b185fb7ffe23c39c7935132479,952b313db61cfede8220ec0256c0822e39ff97d0..ca7c0ae426f61c32f7a971e0c481718d575532cd
@@@ -1,21 -1,21 +1,21 @@@
  /*
   * Autocompletion of email recipients, etc.
   *
-  * Copyright (c) 1987-2012 by the citadel.org team
+  * Copyright (c) 1987-2015 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 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.
+  * 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 "ctdl_module.h"
  
  
+ #include "ctdl_module.h"
  #include "serv_autocompletion.h"
+ #include "config.h"
  
  
  /*
@@@ -59,7 -59,7 +59,7 @@@ void hunt_for_autocomplete(long msgnum
        int i = 0;
        char *nnn = NULL;
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) return;
  
        v = vcard_load(msg->cm_fields[eMesageText]);
@@@ -170,7 -170,7 +170,7 @@@ void cmd_auto(char *argbuf) 
        /*
         * Search-reduce the results if we have the full text index available
         */
-       if (config.c_enable_fulltext) {
+       if (CtdlGetConfigInt("c_enable_fulltext")) {
                CtdlModuleDoSearch(&fts_num_msgs, &fts_msgs, search_string, "fulltext");
                if (fts_msgs) {
                        for (i=0; i<num_msgs; ++i) {
index 2fa2b6dd6ff3adae09a230910fab6ec3076a9a12,df3a13d4f7109b708c9b346aff92cba9a976f51c..5fb86a2287fb12512fce7ecc532ce3fe34458358
@@@ -3,22 -3,15 +3,15 @@@
   * room on a Citadel server.  It handles iCalendar objects using the
   * iTIP protocol.  See RFCs 2445 and 2446.
   *
+  * Copyright (c) 1987-2015 by the citadel.org team
   *
-  * Copyright (c) 1987-2011 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 open source software; you can redistribute it and/or modify
-  *  it under the terms of the GNU General Public License as published by
-  *  the Free Software Foundation; either version 3 of the License, or
-  *  (at your option) any later version.
-  *
-  *  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.
-  *
-  *  You should have received a copy of the GNU General Public License
-  *  along with this program; if not, write to the Free Software
-  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  * 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.
   */
  
  #define PRODID "-//Citadel//NONSGML Citadel Calendar//EN"
@@@ -33,6 -26,7 +26,7 @@@
  #include "room_ops.h"
  #include "euidindex.h"
  #include "ical_dezonify.h"
+ #include "config.h"
  
  
  
@@@ -149,8 -143,8 +143,8 @@@ void ical_write_to_cal(struct ctdluser 
                msg->cm_format_type = 4;
                CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname));
                CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname));
-               CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
-               CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode));
+               CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
+               CM_SetField(msg, eHumanNode, CtdlGetConfigStr("c_humannode"), strlen(CtdlGetConfigStr("c_humannode")));
  
                MsgBody = NewStrBufPlain(NULL, serlen + 100);
                StrBufAppendBufPlain(MsgBody, HKEY("Content-type: text/calendar\r\n\r\n"), 0);
@@@ -375,7 -369,7 +369,7 @@@ void ical_respond(long msgnum, char *pa
                return;
        }
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) {
                cprintf("%d Message %ld not found.\n",
                        ERROR + ILLEGAL_VALUE,
@@@ -636,7 -630,7 +630,7 @@@ int ical_update_my_calendar_with_reply(
         * us the ability to load the event into memory so we can diddle the
         * attendees.
         */
 -      msg = CtdlFetchMessage(msgnum_being_replaced, 1);
 +      msg = CtdlFetchMessage(msgnum_being_replaced, 1, 1);
        if (msg == NULL) {
                return(2);                      /* internal error */
        }
@@@ -716,7 -710,7 +710,7 @@@ void ical_handle_rsvp(long msgnum, cha
                return;
        }
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) {
                cprintf("%d Message %ld not found.\n",
                        ERROR + ILLEGAL_VALUE,
@@@ -1154,7 -1148,7 +1148,7 @@@ void ical_hunt_for_conflicts_backend(lo
  
        proposed_event = (icalcomponent *)data;
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) return;
        memset(&ird, 0, sizeof ird);
        strcpy(ird.desired_partnum, "_HUNT_");
@@@ -1215,7 -1209,7 +1209,7 @@@ void ical_conflicts(long msgnum, char *
        struct CtdlMessage *msg = NULL;
        struct ical_respond_data ird;
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) {
                cprintf("%d Message %ld not found\n",
                        ERROR + ILLEGAL_VALUE,
@@@ -1402,7 -1396,7 +1396,7 @@@ void ical_freebusy_backend(long msgnum
  
        fb = (icalcomponent *)data;             /* User-supplied data will be the VFREEBUSY component */
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) return;
        memset(&ird, 0, sizeof ird);
        strcpy(ird.desired_partnum, "_HUNT_");
@@@ -1460,7 -1454,7 +1454,7 @@@ void ical_freebusy(char *who) 
         * primary FQDN of this Citadel node.
         */
        if (found_user != 0) {
-               snprintf(buf, sizeof buf, "%s@%s", who, config.c_fqdn);
+               snprintf(buf, sizeof buf, "%s@%s", who, CtdlGetConfigStr("c_fqdn"));
                syslog(LOG_DEBUG, "Trying <%s>\n", buf);
                recp = validate_recipients(buf, NULL, 0);
                if (recp != NULL) {
        sprintf(buf, "MAILTO:%s", who);
        if (strchr(buf, '@') == NULL) {
                strcat(buf, "@");
-               strcat(buf, config.c_fqdn);
+               strcat(buf, CtdlGetConfigStr("c_fqdn"));
        }
        for (i=0; buf[i]; ++i) {
                if (buf[i]==' ') buf[i] = '_';
@@@ -1602,7 -1596,7 +1596,7 @@@ void ical_getics_backend(long msgnum, v
  
        /* Look for the calendar event... */
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) return;
        memset(&ird, 0, sizeof ird);
        strcpy(ird.desired_partnum, "_HUNT_");
@@@ -1755,7 -1749,7 +1749,7 @@@ void ical_putics(void
        }
  
        cprintf("%d Transmit data now\n", SEND_LISTING);
-       calstream = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
+       calstream = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0, 0);
        if (calstream == NULL) {
                return;
        }
index 2bb50633fd2e2dfb6f66eba69b3715377f4498a2,3a51e16b6b46ea86319f6b841b05a61ef1a7e698..31e48cb8c3077409ae9827f84b303e51208dd267
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * represent messages to the citadel clients
   *
-  * Copyright (c) 1987-2012 by the citadel.org team
+  * Copyright (c) 1987-2015 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.
  #include "internet_addressing.h"
  #include "user_ops.h"
  #include "room_ops.h"
+ #include "config.h"
  
  extern char *msgkeys[];
  
  
  /*
   * Back end for the MSGS command: output message number only.
   */
@@@ -34,7 -34,6 +34,6 @@@ void simple_listing(long msgnum, void *
  }
  
  
  /*
   * Back end for the MSGS command: output header summary.
   */
@@@ -42,7 -41,7 +41,7 @@@ void headers_listing(long msgnum, void 
  {
        struct CtdlMessage *msg;
  
 -      msg = CtdlFetchMessage(msgnum, 0);
 +      msg = CtdlFetchMessage(msgnum, 0, 1);
        if (msg == NULL) {
                cprintf("%ld|0|||||\n", msgnum);
                return;
@@@ -66,7 -65,7 +65,7 @@@ void headers_euid(long msgnum, void *us
  {
        struct CtdlMessage *msg;
  
 -      msg = CtdlFetchMessage(msgnum, 0);
 +      msg = CtdlFetchMessage(msgnum, 0, 1);
        if (msg == NULL) {
                cprintf("%ld||\n", msgnum);
                return;
@@@ -137,7 -136,7 +136,7 @@@ void cmd_msgs(char *cmdbuf
        else
                mode = MSGS_ALL;
  
-       if ( (mode == MSGS_SEARCH) && (!config.c_enable_fulltext) ) {
+       if ( (mode == MSGS_SEARCH) && (!CtdlGetConfigInt("c_enable_fulltext")) ) {
                cprintf("%d Full text index is not enabled on this server.\n",
                        ERROR + CMD_NOT_SUPPORTED);
                return;
@@@ -228,7 -227,7 +227,7 @@@ void cmd_msg3(char *cmdbuf
        }
  
        msgnum = extract_long(cmdbuf, 0);
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) {
                cprintf("%d Message %ld not found.\n", 
                        ERROR + MESSAGE_NOT_FOUND, msgnum);
index 398b8f6806cb01959be5d3bc8d2eab20e1cb0fe7,cf501e081615b06a425e8ace4906dbfdc00a9298..76bd626fbada1a23cb473f0a03b799da95d2ff45
@@@ -3,7 -3,7 +3,7 @@@
   *
   * You might also see this module affectionately referred to as the DAP (the Dreaded Auto-Purger).
   *
-  * Copyright (c) 1988-2011 by citadel.org (Art Cancro, Wilifried Goesgens, and others)
+  * Copyright (c) 1988-2015 by citadel.org (Art Cancro, Wilifried Goesgens, and others)
   *
   * This program is open source software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as published
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
-  * You should have received a copy of the GNU General Public License
-  * along with this program; if not, write to the Free Software
-  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-  *
-  *
   * A brief technical discussion:
   *
   * Several of the purge operations found in this module operate in two
@@@ -197,7 -192,7 +192,7 @@@ void GatherPurgeMessages(struct ctdlroo
                for (a=0; a<num_msgs; ++a) {
                        delnum = msglist[a];
  
 -                      msg = CtdlFetchMessage(delnum, 0); /* dont need body */
 +                      msg = CtdlFetchMessage(delnum, 0, 1); /* dont need body */
                        if (msg != NULL) {
                                xtime = atol(msg->cm_fields[eTimestamp]);
                                CM_Free(msg);
@@@ -312,11 -307,11 +307,11 @@@ void DoPurgeRooms(struct ctdlroom *qrbu
                if (qrbuf->QRmtime <= (time_t)0) return;
  
                /* If no room purge time is set, be safe and don't purge */
-               if (config.c_roompurge < 0) return;
+               if (CtdlGetConfigLong("c_roompurge") < 0) return;
  
                /* Otherwise, check the date of last modification */
                age = time(NULL) - (qrbuf->QRmtime);
-               purge_secs = (time_t)config.c_roompurge * (time_t)86400;
+               purge_secs = CtdlGetConfigLong("c_roompurge") * 86400;
                if (purge_secs <= (time_t)0) return;
                syslog(LOG_DEBUG, "<%s> is <%ld> seconds old", qrbuf->QRname, (long)age);
                if (age > purge_secs) do_purge = 1;
@@@ -417,10 -412,10 +412,10 @@@ void do_user_purge(struct ctdluser *us
  
        /* Set purge time; if the user overrides the system default, use it */
        if (us->USuserpurge > 0) {
-               purge_time = ((time_t)us->USuserpurge) * 86400L;
+               purge_time = ((time_t)us->USuserpurge) * 86400;
        }
        else {
-               purge_time = ((time_t)config.c_userpurge) * 86400L;
+               purge_time = CtdlGetConfigLong("c_userpurge") * 86400;
        }
  
        /* The default rule is to not purge. */
        /* If the user hasn't called in two months and expiring of accounts is turned on, his/her account
         * has expired, so purge the record.
         */
-       if (config.c_userpurge > 0)
+       if (CtdlGetConfigLong("c_userpurge") > 0)
        {
                now = time(NULL);
                if ((now - us->lastcall) > purge_time) purge = 1;
@@@ -528,7 -523,7 +523,7 @@@ int PurgeUsers(void) 
        syslog(LOG_DEBUG, "PurgeUsers() called");
        users_not_purged = 0;
  
-       switch(config.c_auth_mode) {
+       switch(CtdlGetConfigInt("c_auth_mode")) {
                case AUTHMODE_NATIVE:
                        ForEachUser(do_user_purge, NULL);
                        break;
                        ForEachUser(do_uid_user_purge, NULL);
                        break;
                default:
-                       syslog(LOG_DEBUG, "User purge for auth mode %d is not implemented.",
-                               config.c_auth_mode);
+                       syslog(LOG_DEBUG, "User purge for auth mode %d is not implemented.", CtdlGetConfigInt("c_auth_mode"));
                        break;
        }
  
@@@ -771,7 -765,7 +765,7 @@@ int PurgeEuidIndexTable(void) 
  
                memcpy(&msgnum, cdbei->ptr, sizeof(long));
  
 -              msg = CtdlFetchMessage(msgnum, 0);
 +              msg = CtdlFetchMessage(msgnum, 0, 1);
                if (msg != NULL) {
                        CM_Free(msg);   /* it still exists, so do nothing */
                }
@@@ -870,10 -864,8 +864,8 @@@ void purge_databases(void
         */
        now = time(NULL);
        localtime_r(&now, &tm);
-       if (
-               ((tm.tm_hour != config.c_purge_hour) || ((now - last_purge) < 43200))
-               && (force_purge_now == 0)
-       ) {
+       if (((tm.tm_hour != CtdlGetConfigInt("c_purge_hour")) || ((now - last_purge) < 43200)) && (force_purge_now == 0))
+       {
                        return;
        }
  
index 9244a26fa0600b548b3b003a9f1abf49a98ec41e,219a03fa122cf4409c21266a4722568f6d69e93c..38b6ef1fa19cd1e65ac25dc16f9be541255d5aff
@@@ -8,7 -8,7 +8,7 @@@
   * Based on bits of serv_funambol
   * Contact: <matt@mcbridematt.dhs.org> / <matt@comalies>
   *
-  * Copyright (c) 2008-2011
+  * Copyright (c) 2008-2015
   *
   * This program is open source software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * 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.
-  *
-  * You should have received a copy of the GNU General Public License
-  * along with this program; if not, write to the Free Software
-  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
  
  
@@@ -184,7 -180,7 +180,7 @@@ eNotifyType extNotify_getConfigMessage(
                return eNone;   /* No messages at all?  No further action. */
        }
        for (a = 0; a < num_msgs; ++a) {
 -              msg = CtdlFetchMessage(msglist[a], 1);
 +              msg = CtdlFetchMessage(msglist[a], 1, 1);
                if (msg != NULL) {
                        if (!CM_IsEmpty(msg, eMsgSubject) &&
                            (strncasecmp(msg->cm_fields[eMsgSubject],
@@@ -279,7 -275,7 +275,7 @@@ void process_notify(long NotifyMsgnum, 
  
        Ctx = (NotifyContext*) usrdata;
  
 -      msg = CtdlFetchMessage(NotifyMsgnum, 1);
 +      msg = CtdlFetchMessage(NotifyMsgnum, 1, 1);
        if (!CM_IsEmpty(msg, eExtnotify))
        {
                Type = extNotify_getConfigMessage(
                {
                case eFunambol:
                        snprintf(remoteurl, SIZ, "http://%s@%s:%d/%s",
-                                config.c_funambol_auth,
-                                config.c_funambol_host,
-                                config.c_funambol_port,
+                                CtdlGetConfigStr("c_funambol_auth"),
+                                CtdlGetConfigStr("c_funambol_host"),
+                                CtdlGetConfigInt("c_funambol_port"),
                                 FUNAMBOL_WS);
  
                        notify_http_server(remoteurl,
                        int commandSiz;
                        char *command;
  
-                       commandSiz = sizeof(config.c_pager_program) +
+                       commandSiz = sizeof(CtdlGetConfigStr("c_pager_program")) +
                                strlen(PagerNo) +
                                msg->cm_lengths[eExtnotify] + 5;
  
                        snprintf(command,
                                 commandSiz,
                                 "%s %s -u %s",
-                                config.c_pager_program,
+                                CtdlGetConfigStr("c_pager_program"),
                                 PagerNo,
                                 msg->cm_fields[eExtnotify]);
  
@@@ -393,8 -389,8 +389,8 @@@ void do_extnotify_queue(void
         * don't really require extremely fine granularity here, we'll do it
         * with a static variable instead.
         */
-       if (IsEmptyStr(config.c_pager_program) &&
-           IsEmptyStr(config.c_funambol_host))
+       if (IsEmptyStr(CtdlGetConfigStr("c_pager_program")) &&
+           IsEmptyStr(CtdlGetConfigStr("c_funambol_host")))
        {
                syslog(LOG_ERR,
                       "No external notifiers configured on system/user\n");
@@@ -472,7 -468,7 +468,7 @@@ int extnotify_after_mbox_save(struct Ct
        /* If this is private, local mail, make a copy in the
         * recipient's mailbox and bump the reference count.
         */
-       if (!IsEmptyStr(config.c_funambol_host) || !IsEmptyStr(config.c_pager_program))
+       if (!IsEmptyStr(CtdlGetConfigStr("c_funambol_host")) || !IsEmptyStr(CtdlGetConfigStr("c_pager_program")))
        {
                /* Generate a instruction message for the Funambol notification
                 * server, in the same style as the SMTP queue
index 4589859d4fd9ca20eb740028bb044e3364427369,05ab77906e3004e374616d5e22c4b74940417c13..3709ef6319398c3515143af9871a7e473e9fcdfc
@@@ -1,6 -1,6 +1,6 @@@
  /*
   * This module handles fulltext indexing of the message base.
-  * Copyright (c) 2005-2011 by the citadel.org team
+  * Copyright (c) 2005-2015 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 as published
@@@ -120,7 -120,7 +120,7 @@@ void ft_index_message(long msgnum, int 
        int tok;
        struct CtdlMessage *msg = NULL;
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) {
                syslog(LOG_ERR, "ft_index_message() could not load msg %ld", msgnum);
                return;
   */
  void ft_index_msg(long msgnum, void *userdata) {
  
-       if ((msgnum > CitControl.MMfulltext) && (msgnum <= ft_newhighest)) {
+       if ((msgnum > CtdlGetConfigLong("MMfulltext")) && (msgnum <= ft_newhighest)) {
                ++ft_num_msgs;
                if (ft_num_msgs > ft_num_alloc) {
                        ft_num_alloc += 1024;
@@@ -251,7 -251,7 +251,7 @@@ void do_fulltext_indexing(void) 
        /*
         * Don't do this if the site doesn't have it enabled.
         */
-       if (!config.c_enable_fulltext) {
+       if (!CtdlGetConfigInt("c_enable_fulltext")) {
                return;
        }
  
         * Check to see whether the fulltext index is up to date; if there
         * are no messages to index, don't waste any more time trying.
         */
-       if ((CitControl.MMfulltext >= CitControl.MMhighest) && (CitControl.fulltext_wordbreaker == FT_WORDBREAKER_ID)) {
+       if (
+               (CtdlGetConfigLong("MMfulltext") >= CtdlGetConfigLong("MMhighest"))
+               && (CtdlGetConfigInt("MM_fulltext_wordbreaker") == FT_WORDBREAKER_ID)
+       ) {
                return;         /* nothing to do! */
        }
        
         * over.
         */
        begin_critical_section(S_CONTROL);
-       if (CitControl.fulltext_wordbreaker != FT_WORDBREAKER_ID) {
+       if (CtdlGetConfigInt("MM_fulltext_wordbreaker") != FT_WORDBREAKER_ID) {
                syslog(LOG_DEBUG, "wb ver on disk = %d, code ver = %d",
-                       CitControl.fulltext_wordbreaker, FT_WORDBREAKER_ID
+                       CtdlGetConfigInt("MM_fulltext_wordbreaker"), FT_WORDBREAKER_ID
                );
                syslog(LOG_INFO, "(re)initializing full text index");
                cdb_trunc(CDB_FULLTEXT);
-               CitControl.MMfulltext = 0L;
-               put_control();
+               CtdlSetConfigLong("MMfulltext", 0);
        }
        end_critical_section(S_CONTROL);
  
        /*
         * Now go through each room and find messages to index.
         */
-       ft_newhighest = CitControl.MMhighest;
+       ft_newhighest = CtdlGetConfigLong("MMhighest");
        CtdlForEachRoom(ft_index_room, NULL);   /* load all msg pointers */
  
        if (ft_num_msgs > 0) {
        /* Save our place so we don't have to do this again */
        ft_flush_cache();
        begin_critical_section(S_CONTROL);
-       CitControl.MMfulltext = ft_newhighest;
-       CitControl.fulltext_wordbreaker = FT_WORDBREAKER_ID;
-       put_control();
+       CtdlSetConfigLong("MMfulltext", ft_newhighest);
+       CtdlSetConfigInt("MM_fulltext_wordbreaker", FT_WORDBREAKER_ID);
        end_critical_section(S_CONTROL);
        last_index = time(NULL);
  
@@@ -455,7 -456,7 +456,7 @@@ void cmd_srch(char *argbuf) 
  
        if (CtdlAccessCheck(ac_logged_in)) return;
  
-       if (!config.c_enable_fulltext) {
+       if (!CtdlGetConfigInt("c_enable_fulltext")) {
                cprintf("%d Full text index is not enabled on this server.\n",
                        ERROR + CMD_NOT_SUPPORTED);
                return;
@@@ -489,7 -490,7 +490,7 @@@ void ft_delete_remove(char *room, long 
        if (room) return;
        
        /* Remove from fulltext index */
-       if (config.c_enable_fulltext) {
+       if (CtdlGetConfigInt("c_enable_fulltext")) {
                ft_index_message(msgnum, 0);
        }
  }
index 7e47106074bb869fab4125b785246b72323352be,6708fbc4ea4a63f2b9d7cec5de10e1017ee1e46b..8fcd6bd813ab6c2bc3055f65cde7dbb176e4d288
@@@ -2,21 -2,17 +2,17 @@@
   * Implements the FETCH command in IMAP.
   * This is a good example of the protocol's gratuitous complexity.
   *
-  * Copyright (c) 2001-2011 by the citadel.org team
+  * Copyright (c) 2001-2015 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 as published by
-  *  the Free Software Foundation; either version 3 of the License, or
-  *  (at your option) any later version.
+  * This program is open source software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+  * the Free Software Foundation; either version 3 of the License, or
+  * (at your option) any later version.
   *
-  *  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.
-  *
-  *  You should have received a copy of the GNU General Public License
-  *  along with this program; if not, write to the Free Software
-  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  * 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.
   */
  
  
@@@ -363,8 -359,8 +359,8 @@@ void imap_output_envelope_from(struct C
                process_rfc822_addr(msg->cm_fields[erFc822Addr], user, node, name);
                IPutStr(user, strlen(user));            /* mailbox name (user id) */
                IAPuts(" ");
-               if (!strcasecmp(node, config.c_nodename)) {
-                       IPutStr(CFG_KEY(c_fqdn));
+               if (!strcasecmp(node, CtdlGetConfigStr("c_nodename"))) {
+                       IPutStr(CtdlGetConfigStr("c_fqdn"), strlen(CtdlGetConfigStr("c_fqdn")));
                }
                else {
                        IPutStr(node, strlen(node));            /* host name */
@@@ -710,7 -706,7 +706,7 @@@ void imap_fetch_body(long msgnum, Const
        if (Imap->cached_body == NULL) {
                CCC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
                loading_body_now = 1;
 -              msg = CtdlFetchMessage(msgnum, (need_body ? 1 : 0));
 +              msg = CtdlFetchMessage(msgnum, (need_body ? 1 : 0), 1);
        }
  
        /* Now figure out what the client wants, and get it */
@@@ -1085,7 -1081,7 +1081,7 @@@ void imap_do_fetch_msg(int seq, citimap
                                msg = NULL;
                        }
                        if (msg == NULL) {
 -                              msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                              msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                                body_loaded = 1;
                        }
                        imap_fetch_bodystructure(Imap->msgids[seq-1],
                }
                else if (!strcasecmp(Cmd->Params[i].Key, "ENVELOPE")) {
                        if (msg == NULL) {
 -                              msg = CtdlFetchMessage(Imap->msgids[seq-1], 0);
 +                              msg = CtdlFetchMessage(Imap->msgids[seq-1], 0, 1);
                                body_loaded = 0;
                        }
                        imap_fetch_envelope(msg);
                }
                else if (!strcasecmp(Cmd->Params[i].Key, "INTERNALDATE")) {
                        if (msg == NULL) {
 -                              msg = CtdlFetchMessage(Imap->msgids[seq-1], 0);
 +                              msg = CtdlFetchMessage(Imap->msgids[seq-1], 0, 1);
                                body_loaded = 0;
                        }
                        imap_fetch_internaldate(msg);
index d5c5bfc355e39c94c796cf3dc8ff25a72461512e,02240b1e8c887a6704f010e3a731a0eeed2995c4..f1b7f73e993ce26cc246a3f3effcd7c8070c48aa
@@@ -1,21 -1,15 +1,15 @@@
  /*
   * Implements IMAP's gratuitously complex SEARCH command.
   *
-  * Copyright (c) 2001-2012 by the citadel.org team
+  * Copyright (c) 2001-2015 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 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.
-  *
-  *  
-  *  
-  *  
+  * 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 "ctdl_module.h"
@@@ -121,7 -115,7 +115,7 @@@ int imap_do_search_msg(int seq, struct 
  
        else if (!strcasecmp(itemlist[pos].Key, "BCC")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "BEFORE")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
                /* If fulltext indexing is active, on this server,
                 *  all messages have already been qualified.
                 */
-               if (config.c_enable_fulltext) {
+               if (CtdlGetConfigInt("c_enable_fulltext")) {
                        match = 1;
                }
  
                /* Otherwise, we have to do a slow search. */
                else {
                        if (msg == NULL) {
 -                              msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                              msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                                need_to_free_msg = 1;
                        }
                        if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "CC")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "FROM")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
                 * examining the message body.
                 */
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
  
  
        else if (!strcasecmp(itemlist[pos].Key, "LARGER")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "ON")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "SENTBEFORE")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "SENTON")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "SENTSINCE")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "SINCE")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "SMALLER")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "SUBJECT")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "TEXT")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
  
        else if (!strcasecmp(itemlist[pos].Key, "TO")) {
                if (msg == NULL) {
 -                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
 +                      msg = CtdlFetchMessage(Imap->msgids[seq-1], 1, 1);
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
@@@ -571,7 -565,7 +565,7 @@@ void imap_do_search(int num_items, Cons
         * text index to disqualify messages that don't have any chance of
         * matching.  (Only do this if the index is enabled!!)
         */
-       if (config.c_enable_fulltext) for (i=0; i<(num_items-1); ++i) {
+       if (CtdlGetConfigInt("c_enable_fulltext")) for (i=0; i<(num_items-1); ++i) {
                if (!strcasecmp(itemlist[i].Key, "BODY")) {
                        CtdlModuleDoSearch(&fts_num_msgs, &fts_msgs, itemlist[i+1].Key, "fulltext");
                        if (fts_num_msgs > 0) {
index 6dc342ff77f04f9b7c7f8e3afb064c334047381b,3f9ee3a495848d50afb128c51eac1f7b8be7fe12..83173268239cbc2f69074ee6e24d7ce8f5c2f2f6
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * This module dumps and/or loads the Citadel database in XML format.
   *
-  * Copyright (c) 1987-2014 by the citadel.org team
+  * Copyright (c) 1987-2015 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.
@@@ -16,8 -16,7 +16,7 @@@
   * Explanation of <progress> tags:
   *
   * 0%              nothing
-  * 1%              finished exporting config
-  * 2%              finished exporting control
+  * 2%              finished exporting configuration
   * 7%              finished exporting users
   * 12%             finished exporting openids
   * 17%             finished exporting rooms
@@@ -61,7 -60,6 +60,6 @@@
  #include "database.h"
  #include "msgbase.h"
  #include "user_ops.h"
- #include "control.h"
  #include "euidindex.h"
  #include "ctdl_module.h"
  
@@@ -72,10 -70,9 +70,10 @@@ char migr_tempfilename2[PATH_MAX]
  FILE *migr_global_message_list;
  int total_msgs = 0;
  
 -/*
 - * Code which implements the export appears in this section
 - */
 +
 +/******************************************************************************
 + *        Code which implements the export appears in this section            *
 + ******************************************************************************/
  
  /*
   * Output a string to the client with these characters escaped:  & < >
@@@ -90,19 -87,19 +88,19 @@@ void xml_strout(char *str) 
  
        while (*c != 0) {
                if (*c == '\"') {
 -                      client_write("&quot;", 6);
 +                      client_write(HKEY("&quot;"));
                }
                else if (*c == '\'') {
 -                      client_write("&apos;", 6);
 +                      client_write(HKEY("&apos;"));
                }
                else if (*c == '<') {
 -                      client_write("&lt;", 4);
 +                      client_write(HKEY("&lt;"));
                }
                else if (*c == '>') {
 -                      client_write("&gt;", 4);
 +                      client_write(HKEY("&gt;"));
                }
                else if (*c == '&') {
 -                      client_write("&amp;", 5);
 +                      client_write(HKEY("&amp;"));
                }
                else {
                        client_write(c, 1);
   * Export a user record as XML
   */
  void migr_export_users_backend(struct ctdluser *buf, void *data) {
 -      client_write("<user>\n", 7);
 +      client_write(HKEY("<user>\n"));
        cprintf("<u_version>%d</u_version>\n", buf->version);
        cprintf("<u_uid>%ld</u_uid>\n", (long)buf->uid);
 -      client_write("<u_password>", 12);       xml_strout(buf->password);              client_write("</u_password>\n", 14);
 +      client_write(HKEY("<u_password>"));     xml_strout(buf->password);              client_write(HKEY("</u_password>\n"));
        cprintf("<u_flags>%u</u_flags>\n", buf->flags);
        cprintf("<u_timescalled>%ld</u_timescalled>\n", buf->timescalled);
        cprintf("<u_posted>%ld</u_posted>\n", buf->posted);
        cprintf("<u_usernum>%ld</u_usernum>\n", buf->usernum);
        cprintf("<u_lastcall>%ld</u_lastcall>\n", (long)buf->lastcall);
        cprintf("<u_USuserpurge>%d</u_USuserpurge>\n", buf->USuserpurge);
 -      client_write("<u_fullname>", 12);       xml_strout(buf->fullname);              client_write("</u_fullname>\n", 14);
 -      client_write("</user>\n", 8);
 +      client_write(HKEY("<u_fullname>"));     xml_strout(buf->fullname);              client_write(HKEY("</u_fullname>\n"));
 +      client_write(HKEY("</user>\n"));
  }
  
  
@@@ -144,17 -141,17 +142,17 @@@ void migr_export_room_msg(long msgnum, 
  
  
  void migr_export_rooms_backend(struct ctdlroom *buf, void *data) {
 -      client_write("<room>\n", 7);
 -      client_write("<QRname>", 8);    xml_strout(buf->QRname);        client_write("</QRname>\n", 10);
 -      client_write("<QRpasswd>", 10); xml_strout(buf->QRpasswd);      client_write("</QRpasswd>\n", 12);
 +      client_write(HKEY("<room>\n"));
 +      client_write(HKEY("<QRname>")); xml_strout(buf->QRname);        client_write(HKEY("</QRname>\n"));
 +      client_write(HKEY("<QRpasswd>"));       xml_strout(buf->QRpasswd);      client_write(HKEY("</QRpasswd>\n"));
        cprintf("<QRroomaide>%ld</QRroomaide>\n", buf->QRroomaide);
        cprintf("<QRhighest>%ld</QRhighest>\n", buf->QRhighest);
        cprintf("<QRgen>%ld</QRgen>\n", (long)buf->QRgen);
        cprintf("<QRflags>%u</QRflags>\n", buf->QRflags);
        if (buf->QRflags & QR_DIRECTORY) {
 -              client_write("<QRdirname>", 11);
 +              client_write(HKEY("<QRdirname>"));
                xml_strout(buf->QRdirname);
 -              client_write("</QRdirname>\n", 13);
 +              client_write(HKEY("</QRdirname>\n"));
        }
        cprintf("<QRinfo>%ld</QRinfo>\n", buf->QRinfo);
        cprintf("<QRfloor>%d</QRfloor>\n", buf->QRfloor);
        cprintf("<QRorder>%d</QRorder>\n", buf->QRorder);
        cprintf("<QRflags2>%u</QRflags2>\n", buf->QRflags2);
        cprintf("<QRdefaultview>%d</QRdefaultview>\n", buf->QRdefaultview);
 -      client_write("</room>\n", 8);
 +      client_write(HKEY("</room>\n"));
  
        /* message list goes inside this tag */
  
        CtdlGetRoom(&CC->room, buf->QRname);
 -      client_write("<room_messages>", 15);
 -      client_write("<FRname>", 8);    xml_strout(CC->room.QRname);    client_write("</FRname>\n", 10);
 -      client_write("<FRmsglist>", 11);
 +      client_write(HKEY("<room_messages>"));
 +      client_write(HKEY("<FRname>")); xml_strout(CC->room.QRname);    client_write(HKEY("</FRname>\n"));
 +      client_write(HKEY("<FRmsglist>"));
        CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, migr_export_room_msg, NULL);
 -      client_write("</FRmsglist>\n", 13);
 -      client_write("</room_messages>\n", 17);
 +      client_write(HKEY("</FRmsglist>\n"));
 +      client_write(HKEY("</room_messages>\n"));
  
  
  }
@@@ -220,16 -217,16 +218,16 @@@ void migr_export_floors(void) 
          int i;
  
          for (i=0; i < MAXFLOORS; ++i) {
 -              client_write("<floor>\n", 8);
 +              client_write(HKEY("<floor>\n"));
                cprintf("<f_num>%d</f_num>\n", i);
                  CtdlGetFloor(&qfbuf, i);
                buf = &qfbuf;
                cprintf("<f_flags>%u</f_flags>\n", buf->f_flags);
 -              client_write("<f_name>", 8); xml_strout(buf->f_name); client_write("</f_name>\n", 10);
 +              client_write(HKEY("<f_name>")); xml_strout(buf->f_name); client_write(HKEY("</f_name>\n"));
                cprintf("<f_ref_count>%d</f_ref_count>\n", buf->f_ref_count);
                cprintf("<f_ep_expire_mode>%d</f_ep_expire_mode>\n", buf->f_ep.expire_mode);
                cprintf("<f_ep_expire_value>%d</f_ep_expire_value>\n", buf->f_ep.expire_value);
 -              client_write("</floor>\n", 9);
 +              client_write(HKEY("</floor>\n"));
        }
  }
  
@@@ -268,29 -265,29 +266,29 @@@ void migr_export_visits(void) 
                        sizeof(visit) : cdbv->len));
                cdb_free(cdbv);
  
 -              client_write("<visit>\n", 8);
 +              client_write(HKEY("<visit>\n"));
                cprintf("<v_roomnum>%ld</v_roomnum>\n", vbuf.v_roomnum);
                cprintf("<v_roomgen>%ld</v_roomgen>\n", vbuf.v_roomgen);
                cprintf("<v_usernum>%ld</v_usernum>\n", vbuf.v_usernum);
  
 -              client_write("<v_seen>", 8);
 +              client_write(HKEY("<v_seen>"));
                if ( (!IsEmptyStr(vbuf.v_seen)) && (is_sequence_set(vbuf.v_seen)) ) {
                        xml_strout(vbuf.v_seen);
                }
                else {
                        cprintf("%ld", vbuf.v_lastseen);
                }
 -              client_write("</v_seen>", 9);
 +              client_write(HKEY("</v_seen>"));
  
                if ( (!IsEmptyStr(vbuf.v_answered)) && (is_sequence_set(vbuf.v_answered)) ) {
 -                      client_write("<v_answered>", 12);
 +                      client_write(HKEY("<v_answered>"));
                        xml_strout(vbuf.v_answered);
 -                      client_write("</v_answered>\n", 14);
 +                      client_write(HKEY("</v_answered>\n"));
                }
  
                cprintf("<v_flags>%u</v_flags>\n", vbuf.v_flags);
                cprintf("<v_view>%d</v_view>\n", vbuf.v_view);
 -              client_write("</visit>\n", 9);
 +              client_write(HKEY("</visit>\n"));
        }
  }
  
@@@ -319,18 -316,16 +317,18 @@@ void migr_export_message(long msgnum) 
  
        /* Ok, here we go ... */
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 0);
        if (msg == NULL) return;        /* fail silently */
  
 -      client_write("<message>\n", 10);
 +      client_write(HKEY("<message>\n"));
        GetMetaData(&smi, msgnum);
        cprintf("<msg_msgnum>%ld</msg_msgnum>\n", msgnum);
        cprintf("<msg_meta_refcount>%d</msg_meta_refcount>\n", smi.meta_refcount);
 -      client_write("<msg_meta_content_type>", 23); xml_strout(smi.meta_content_type); client_write("</msg_meta_content_type>\n", 25);
 +      cprintf("<msg_meta_rfc822_length>%ld</msg_meta_rfc822_length>\n", smi.meta_rfc822_length);
 +      client_write(HKEY("<msg_meta_content_type>")); xml_strout(smi.meta_content_type); client_write(HKEY("</msg_meta_content_type>\n"));
 +      client_write(HKEY("<msg_mimetype>")); xml_strout(smi.mimetype); client_write(HKEY("</msg_mimetype>\n"));
  
 -      client_write("<msg_text>", 10);
 +      client_write(HKEY("<msg_text>"));
        CtdlSerializeMessage(&smr, msg);
        CM_Free(msg);
  
  
        free(smr.ser);
  
 -      client_write("</msg_text>\n", 12);
 -      client_write("</message>\n", 11);
 +      client_write(HKEY("</msg_text>\n"));
 +      client_write(HKEY("</message>\n"));
  }
  
  
@@@ -367,20 -362,43 +365,43 @@@ void migr_export_openids(void) 
        cdb_rewind(CDB_OPENID);
        while (cdboi = cdb_next_item(CDB_OPENID), cdboi != NULL) {
                if (cdboi->len > sizeof(long)) {
 -                      client_write("<openid>\n", 9);
 +                      client_write(HKEY("<openid>\n"));
                        memcpy(&usernum, cdboi->ptr, sizeof(long));
                        snprintf(url, sizeof url, "%s", (cdboi->ptr)+sizeof(long) );
 -                      client_write("<oid_url>", 9);
 +                      client_write(HKEY("<oid_url>"));
                        xml_strout(url);
 -                      client_write("</oid_url>\n", 11);
 +                      client_write(HKEY("</oid_url>\n"));
                        cprintf("<oid_usernum>%ld</oid_usernum>\n", usernum);
 -                      client_write("</openid>\n", 10);
 +                      client_write(HKEY("</openid>\n"));
                }
                cdb_free(cdboi);
        }
  }
  
  
+ void migr_export_configs(void) {
+       struct cdbdata *cdbcfg;
+       int keylen = 0;
+       char *key = NULL;
+       char *value = NULL;
+       cdb_rewind(CDB_CONFIG);
+       while (cdbcfg = cdb_next_item(CDB_CONFIG), cdbcfg != NULL) {
+               keylen = strlen(cdbcfg->ptr);
+               key = cdbcfg->ptr;
+               value = cdbcfg->ptr + keylen + 1;
+               client_write("<config key=\"", 13);
+               xml_strout(key);
+               client_write("\">", 2);
+               xml_strout(value);
+               client_write("</config>\n", 10);
+               cdb_free(cdbcfg);
+       }
+ }
  
  
  void migr_export_messages(void) {
@@@ -427,101 -445,15 +448,15 @@@ void migr_do_export(void) 
        cprintf("%d Exporting all Citadel databases.\n", LISTING_FOLLOWS);
        Ctx->dont_term = 1;
  
 -      client_write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n", 40);
 -      client_write("<citadel_migrate_data>\n", 23);
 +      client_write(HKEY("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"));
 +      client_write(HKEY("<citadel_migrate_data>\n"));
        cprintf("<version>%d</version>\n", REV_LEVEL);
        cprintf("<progress>%d</progress>\n", 0);
  
-       /* export the config file (this is done using x-macros) */
-       client_write(HKEY("<config>\n"));
-       client_write(HKEY("<c_nodename>"));     xml_strout(config.c_nodename);          client_write(HKEY("</c_nodename>\n"));
-       client_write(HKEY("<c_fqdn>"));         xml_strout(config.c_fqdn);              client_write(HKEY("</c_fqdn>\n"));
-       client_write(HKEY("<c_humannode>"));    xml_strout(config.c_humannode);         client_write(HKEY("</c_humannode>\n"));
-       client_write(HKEY("<c_phonenum>"));     xml_strout(config.c_phonenum);          client_write(HKEY("</c_phonenum>\n"));
-       cprintf("<c_ctdluid>%d</c_ctdluid>\n", config.c_ctdluid);
-       cprintf("<c_creataide>%d</c_creataide>\n", config.c_creataide);
-       cprintf("<c_sleeping>%d</c_sleeping>\n", config.c_sleeping);
-       cprintf("<c_initax>%d</c_initax>\n", config.c_initax);
-       cprintf("<c_regiscall>%d</c_regiscall>\n", config.c_regiscall);
-       cprintf("<c_twitdetect>%d</c_twitdetect>\n", config.c_twitdetect);
-       client_write(HKEY("<c_twitroom>"));     xml_strout(config.c_twitroom);          client_write(HKEY("</c_twitroom>\n"));
-       client_write(HKEY("<c_moreprompt>"));   xml_strout(config.c_moreprompt);        client_write(HKEY("</c_moreprompt>\n"));
-       cprintf("<c_restrict>%d</c_restrict>\n", config.c_restrict);
-       client_write(HKEY("<c_site_location>"));        xml_strout(config.c_site_location);     client_write(HKEY("</c_site_location>\n"));
-       client_write(HKEY("<c_sysadm>"));               xml_strout(config.c_sysadm);            client_write(HKEY("</c_sysadm>\n"));
-       cprintf("<c_maxsessions>%d</c_maxsessions>\n", config.c_maxsessions);
-       client_write(HKEY("<c_ip_addr>"));      xml_strout(config.c_ip_addr);           client_write(HKEY("</c_ip_addr>\n"));
-       cprintf("<c_port_number>%d</c_port_number>\n", config.c_port_number);
-       cprintf("<c_ep_expire_mode>%d</c_ep_expire_mode>\n", config.c_ep.expire_mode);
-       cprintf("<c_ep_expire_value>%d</c_ep_expire_value>\n", config.c_ep.expire_value);
-       cprintf("<c_userpurge>%d</c_userpurge>\n", config.c_userpurge);
-       cprintf("<c_roompurge>%d</c_roompurge>\n", config.c_roompurge);
-       client_write(HKEY("<c_logpages>"));     xml_strout(config.c_logpages);          client_write(HKEY("</c_logpages>\n"));
-       cprintf("<c_createax>%d</c_createax>\n", config.c_createax);
-       cprintf("<c_maxmsglen>%ld</c_maxmsglen>\n", config.c_maxmsglen);
-       cprintf("<c_min_workers>%d</c_min_workers>\n", config.c_min_workers);
-       cprintf("<c_max_workers>%d</c_max_workers>\n", config.c_max_workers);
-       cprintf("<c_pop3_port>%d</c_pop3_port>\n", config.c_pop3_port);
-       cprintf("<c_smtp_port>%d</c_smtp_port>\n", config.c_smtp_port);
-       cprintf("<c_rfc822_strict_from>%d</c_rfc822_strict_from>\n", config.c_rfc822_strict_from);
-       cprintf("<c_aide_zap>%d</c_aide_zap>\n", config.c_aide_zap);
-       cprintf("<c_imap_port>%d</c_imap_port>\n", config.c_imap_port);
-       cprintf("<c_net_freq>%ld</c_net_freq>\n", config.c_net_freq);
-       cprintf("<c_disable_newu>%d</c_disable_newu>\n", config.c_disable_newu);
-       cprintf("<c_enable_fulltext>%d</c_enable_fulltext>\n", config.c_enable_fulltext);
-       client_write(HKEY("<c_baseroom>"));     xml_strout(config.c_baseroom);          client_write(HKEY("</c_baseroom>\n"));
-       client_write(HKEY("<c_aideroom>"));     xml_strout(config.c_aideroom);          client_write(HKEY("</c_aideroom>\n"));
-       cprintf("<c_purge_hour>%d</c_purge_hour>\n", config.c_purge_hour);
-       cprintf("<c_mbxep_expire_mode>%d</c_mbxep_expire_mode>\n", config.c_mbxep.expire_mode);
-       cprintf("<c_mbxep_expire_value>%d</c_mbxep_expire_value>\n", config.c_mbxep.expire_value);
-       client_write(HKEY("<c_ldap_host>"));    xml_strout(config.c_ldap_host);         client_write(HKEY("</c_ldap_host>\n"));
-       cprintf("<c_ldap_port>%d</c_ldap_port>\n", config.c_ldap_port);
-       client_write(HKEY("<c_ldap_base_dn>")); xml_strout(config.c_ldap_base_dn);      client_write(HKEY("</c_ldap_base_dn>\n"));
-       client_write(HKEY("<c_ldap_bind_dn>")); xml_strout(config.c_ldap_bind_dn);      client_write(HKEY("</c_ldap_bind_dn>\n"));
-       client_write(HKEY("<c_ldap_bind_pw>")); xml_strout(config.c_ldap_bind_pw);      client_write(HKEY("</c_ldap_bind_pw>\n"));
-       cprintf("<c_msa_port>%d</c_msa_port>\n", config.c_msa_port);
-       cprintf("<c_imaps_port>%d</c_imaps_port>\n", config.c_imaps_port);
-       cprintf("<c_pop3s_port>%d</c_pop3s_port>\n", config.c_pop3s_port);
-       cprintf("<c_smtps_port>%d</c_smtps_port>\n", config.c_smtps_port);
-       cprintf("<c_auto_cull>%d</c_auto_cull>\n", config.c_auto_cull);
-       cprintf("<c_allow_spoofing>%d</c_allow_spoofing>\n", config.c_allow_spoofing);
-       cprintf("<c_journal_email>%d</c_journal_email>\n", config.c_journal_email);
-       cprintf("<c_journal_pubmsgs>%d</c_journal_pubmsgs>\n", config.c_journal_pubmsgs);
-       client_write(HKEY("<c_journal_dest>")); xml_strout(config.c_journal_dest);      client_write(HKEY("</c_journal_dest>\n"));
-       client_write(HKEY("<c_default_cal_zone>"));     xml_strout(config.c_default_cal_zone);  client_write(HKEY("</c_default_cal_zone>\n"));
-       cprintf("<c_pftcpdict_port>%d</c_pftcpdict_port>\n", config.c_pftcpdict_port);
-       cprintf("<c_managesieve_port>%d</c_managesieve_port>\n", config.c_managesieve_port);
-       cprintf("<c_auth_mode>%d</c_auth_mode>\n", config.c_auth_mode);
-       client_write(HKEY("<c_funambol_host>"));        xml_strout(config.c_funambol_host);     client_write(HKEY("</c_funambol_host>\n"));
-       cprintf("<c_funambol_port>%d</c_funambol_port>\n", config.c_funambol_port);
-       client_write(HKEY("<c_funambol_source>"));      xml_strout(config.c_funambol_source);   client_write(HKEY("</c_funambol_source>\n"));
-       client_write(HKEY("<c_funambol_auth>"));        xml_strout(config.c_funambol_auth);     client_write(HKEY("</c_funambol_auth>\n"));
-       cprintf("<c_rbl_at_greeting>%d</c_rbl_at_greeting>\n", config.c_rbl_at_greeting);
-       client_write(HKEY("<c_master_user>"));   xml_strout(config.c_master_user);              client_write(HKEY("</c_master_user>\n"));
-       client_write(HKEY("<c_master_pass>"));   xml_strout(config.c_master_pass);              client_write(HKEY("</c_master_pass>\n"));
-       client_write(HKEY("<c_pager_program>")); xml_strout(config.c_pager_program);            client_write(HKEY("</c_pager_program>\n"));
-       cprintf("<c_imap_keep_from>%d</c_imap_keep_from>\n", config.c_imap_keep_from);
-       cprintf("<c_xmpp_c2s_port>%d</c_xmpp_c2s_port>\n", config.c_xmpp_c2s_port);
-       cprintf("<c_xmpp_s2s_port>%d</c_xmpp_s2s_port>\n", config.c_xmpp_s2s_port);
-       cprintf("<c_pop3_fetch>%ld</c_pop3_fetch>\n", config.c_pop3_fetch);
-       cprintf("<c_pop3_fastest>%ld</c_pop3_fastest>\n", config.c_pop3_fastest);
-       cprintf("<c_spam_flag_only>%d</c_spam_flag_only>\n", config.c_spam_flag_only);
-       cprintf("<c_nntp_port>%d</c_nntp_port>\n", config.c_nntp_port);
-       cprintf("<c_nntps_port>%d</c_nntps_port>\n", config.c_nntps_port);
-       client_write(HKEY("</config>\n"));
-       cprintf("<progress>%d</progress>\n", 1);
-       
-       /* Export the control file */
-       get_control();
-       client_write(HKEY("<control>\n"));
-       cprintf("<control_highest>%ld</control_highest>\n", CitControl.MMhighest);
-       cprintf("<control_flags>%u</control_flags>\n", CitControl.MMflags);
-       cprintf("<control_nextuser>%ld</control_nextuser>\n", CitControl.MMnextuser);
-       cprintf("<control_nextroom>%ld</control_nextroom>\n", CitControl.MMnextroom);
-       cprintf("<control_version>%d</control_version>\n", CitControl.version);
-       client_write(HKEY("</control>\n"));
+       /* export the configuration database */
+       migr_export_configs();
        cprintf("<progress>%d</progress>\n", 2);
+       
        if (Ctx->kill_me == 0)  migr_export_users();
        cprintf("<progress>%d</progress>\n", 7);
        if (Ctx->kill_me == 0)  migr_export_openids();
        if (Ctx->kill_me == 0)  migr_export_visits();
        cprintf("<progress>%d</progress>\n", 25);
        if (Ctx->kill_me == 0)  migr_export_messages();
 -      client_write("</citadel_migrate_data>\n", 24);
 +      client_write(HKEY("</citadel_migrate_data>\n"));
        cprintf("<progress>%d</progress>\n", 100);
 -      client_write("000\n", 4);
 +      client_write(HKEY("000\n"));
        Ctx->dont_term = 0;
  }
  
  
  
  
 -      
 -/*
 - * Here's the code that implements the import side.  It's going to end up being
 - * one big loop with lots of global variables.  I don't care.  You wouldn't run
 - * multiple concurrent imports anyway.  If this offends your delicate sensibilities
 - * then go rewrite it in Ruby on Rails or something.
 - */
 +/******************************************************************************
 + *                              Import code                                   *
 + *    Here's the code that implements the import side.  It's going to end up  *
 + *        being one big loop with lots of global variables.  I don't care.    *
 + * You wouldn't run multiple concurrent imports anyway.  If this offends your *
 + * delicate sensibilities  then go rewrite it in Ruby on Rails or something.  *
 + ******************************************************************************/
  
  
  int citadel_migrate_data = 0;         /* Are we inside a <citadel_migrate_data> tag pair? */
@@@ -616,105 -548,9 +551,9 @@@ void migr_xml_start(void *data, const c
                memset(&smi, 0, sizeof (struct MetaData));
                import_msgnum = 0;
        }
- }
- int migr_config(void *data, const char *el)
- {
-       if (!strcasecmp(el, "c_nodename"))                      SET_CFGSTRBUF(c_nodename, migr_chardata);
-       else if (!strcasecmp(el, "c_fqdn"))                     SET_CFGSTRBUF(c_fqdn, migr_chardata);
-       else if (!strcasecmp(el, "c_humannode"))                SET_CFGSTRBUF(c_humannode, migr_chardata);
-       else if (!strcasecmp(el, "c_phonenum"))                 SET_CFGSTRBUF(c_phonenum, migr_chardata);
-       else if (!strcasecmp(el, "c_ctdluid"))                  config.c_ctdluid = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_creataide"))                config.c_creataide = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_sleeping"))                 config.c_sleeping = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_initax"))                   config.c_initax = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_regiscall"))                config.c_regiscall = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_twitdetect"))               config.c_twitdetect = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_twitroom"))                 SET_CFGSTRBUF(c_twitroom, migr_chardata);
-       else if (!strcasecmp(el, "c_moreprompt"))               SET_CFGSTRBUF(c_moreprompt, migr_chardata);
-       else if (!strcasecmp(el, "c_restrict"))                 config.c_restrict = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_site_location"))            SET_CFGSTRBUF(c_site_location, migr_chardata);
-       else if (!strcasecmp(el, "c_sysadm"))                   SET_CFGSTRBUF(c_sysadm, migr_chardata);
-       else if (!strcasecmp(el, "c_maxsessions"))              config.c_maxsessions = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_ip_addr"))                  SET_CFGSTRBUF(c_ip_addr, migr_chardata);
-       else if (!strcasecmp(el, "c_port_number"))              config.c_port_number = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_ep_expire_mode"))           config.c_ep.expire_mode = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_ep_expire_value"))          config.c_ep.expire_value = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_userpurge"))                config.c_userpurge = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_roompurge"))                config.c_roompurge = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_logpages"))                 SET_CFGSTRBUF(c_logpages, migr_chardata);
-       else if (!strcasecmp(el, "c_createax"))                 config.c_createax = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_maxmsglen"))                config.c_maxmsglen = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_min_workers"))              config.c_min_workers = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_max_workers"))              config.c_max_workers = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_pop3_port"))                config.c_pop3_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_smtp_port"))                config.c_smtp_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_rfc822_strict_from"))       config.c_rfc822_strict_from = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_aide_zap"))                 config.c_aide_zap = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_imap_port"))                config.c_imap_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_net_freq"))                 config.c_net_freq = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_disable_newu"))             config.c_disable_newu = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_enable_fulltext"))          config.c_enable_fulltext = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_baseroom"))                 SET_CFGSTRBUF(c_baseroom, migr_chardata);
-       else if (!strcasecmp(el, "c_aideroom"))                 SET_CFGSTRBUF(c_aideroom, migr_chardata);
-       else if (!strcasecmp(el, "c_purge_hour"))               config.c_purge_hour = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_mbxep_expire_mode"))        config.c_mbxep.expire_mode = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_mbxep_expire_value"))       config.c_mbxep.expire_value = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_ldap_host"))                SET_CFGSTRBUF(c_ldap_host, migr_chardata);
-       else if (!strcasecmp(el, "c_ldap_port"))                config.c_ldap_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_ldap_base_dn"))             SET_CFGSTRBUF(c_ldap_base_dn, migr_chardata);
-       else if (!strcasecmp(el, "c_ldap_bind_dn"))             SET_CFGSTRBUF(c_ldap_bind_dn, migr_chardata);
-       else if (!strcasecmp(el, "c_ldap_bind_pw"))             SET_CFGSTRBUF(c_ldap_bind_pw, migr_chardata);
-       else if (!strcasecmp(el, "c_msa_port"))                 config.c_msa_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_imaps_port"))               config.c_imaps_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_pop3s_port"))               config.c_pop3s_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_smtps_port"))               config.c_smtps_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_auto_cull"))                config.c_auto_cull = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_allow_spoofing"))           config.c_allow_spoofing = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_journal_email"))            config.c_journal_email = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_journal_pubmsgs"))          config.c_journal_pubmsgs = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_journal_dest"))             SET_CFGSTRBUF(c_journal_dest, migr_chardata);
-       else if (!strcasecmp(el, "c_default_cal_zone"))         SET_CFGSTRBUF(c_default_cal_zone, migr_chardata);
-       else if (!strcasecmp(el, "c_pftcpdict_port"))           config.c_pftcpdict_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_managesieve_port"))         config.c_managesieve_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_auth_mode"))                config.c_auth_mode = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_funambol_host"))            SET_CFGSTRBUF(c_funambol_host, migr_chardata);
-       else if (!strcasecmp(el, "c_funambol_port"))            config.c_funambol_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_funambol_source"))          SET_CFGSTRBUF(c_funambol_source, migr_chardata);
-       else if (!strcasecmp(el, "c_funambol_auth"))            SET_CFGSTRBUF(c_funambol_auth, migr_chardata);
-       else if (!strcasecmp(el, "c_rbl_at_greeting"))          config.c_rbl_at_greeting = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_master_user"))              SET_CFGSTRBUF(c_master_user, migr_chardata);
-       else if (!strcasecmp(el, "c_master_pass"))              SET_CFGSTRBUF(c_master_pass, migr_chardata);
-       else if (!strcasecmp(el, "c_pager_program"))            SET_CFGSTRBUF(c_pager_program, migr_chardata);
-       else if (!strcasecmp(el, "c_imap_keep_from"))           config.c_imap_keep_from = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_xmpp_c2s_port"))            config.c_xmpp_c2s_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_xmpp_s2s_port"))            config.c_xmpp_s2s_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_pop3_fetch"))               config.c_pop3_fetch = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_pop3_fastest"))             config.c_pop3_fastest = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_spam_flag_only"))           config.c_spam_flag_only = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_nntp_port"))                config.c_nntp_port = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "c_nntps_port"))               config.c_nntps_port = atoi(ChrPtr(migr_chardata));
-       else return 0;
-       return 1; /* Found above...*/
- }
- int migr_controlrecord(void *data, const char *el)
- {
-       if (!strcasecmp(el, "control_highest"))         CitControl.MMhighest = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "control_flags"))              CitControl.MMflags = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "control_nextuser"))           CitControl.MMnextuser = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "control_nextroom"))           CitControl.MMnextroom = atol(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "control_version"))            CitControl.version = atoi(ChrPtr(migr_chardata));
-       else if (!strcasecmp(el, "control")) {
-               CitControl.MMfulltext = (-1L);  /* always flush */
-               put_control();
-               syslog(LOG_INFO, "Completed import of control record\n");
+       else if (!strcasecmp(el, "config")) {
+               syslog(LOG_DEBUG, "\033[31m IMPORT OF CONFIG START ELEMENT FIXME\033\0m");
        }
-       else return 0;
-       return 1;
  
  }
  
@@@ -796,6 -632,8 +635,8 @@@ int migr_visitrecord(void *data, const 
        else return 0;
        return 1;
  }
  void migr_xml_end(void *data, const char *el)
  {
        const char *ptr;
  
        /*** CONFIG ***/
  
-       if (!strcasecmp(el, "config")) {
-               config.c_enable_fulltext = 0;   /* always disable */
-               put_config();
-               syslog(LOG_INFO, "Completed import of server configuration\n");
+       if (!strcasecmp(el, "config"))
+       {
+               syslog(LOG_DEBUG, "\033[31m IMPORT OF CONFIG END ELEMENT FIXME\033\0m");
+               CtdlSetConfigInt("c_enable_fulltext", 0);       /* always disable FIXME put this somewhere more appropriate */
        }
  
-       else if ((!strncasecmp(el, HKEY("c_"))) && 
-                migr_config(data, el))
-               ; /* Nothing to do anymore */
-               
-       /*** CONTROL ***/
-       else if ((!strncasecmp(el, HKEY("control"))) && 
-                migr_controlrecord(data, el))
-               ; /* Nothing to do anymore */
        /*** USER ***/
        else if ((!strncasecmp(el, HKEY("u_"))) && 
                 migr_userrecord(data, el))
  
        /*** MESSAGES ***/
        
 -      else if (!strcasecmp(el, "msg_msgnum"))                 import_msgnum = atol(ChrPtr(migr_chardata));
 +      else if (!strcasecmp(el, "msg_msgnum"))                 smi.meta_msgnum = import_msgnum = atol(ChrPtr(migr_chardata));
        else if (!strcasecmp(el, "msg_meta_refcount"))          smi.meta_refcount = atoi(ChrPtr(migr_chardata));
 +      else if (!strcasecmp(el, "msg_meta_rfc822_length"))     smi.meta_rfc822_length = atoi(ChrPtr(migr_chardata));
        else if (!strcasecmp(el, "msg_meta_content_type"))      safestrncpy(smi.meta_content_type, ChrPtr(migr_chardata), sizeof smi.meta_content_type);
 +      else if (!strcasecmp(el, "msg_mimetype"))               safestrncpy(smi.mimetype, ChrPtr(migr_chardata), sizeof smi.mimetype);
  
        else if (!strcasecmp(el, "msg_text"))
        {
 +              long rc;
 +              struct CtdlMessage *msg;
  
                FlushStrBuf(migr_MsgData);
 -              StrBufDecodeBase64To(migr_MsgData, migr_MsgData);
 -
 -              cdb_store(CDB_MSGMAIN,
 -                        &import_msgnum,
 -                        sizeof(long),
 -                        ChrPtr(migr_MsgData), 
 -                        StrLength(migr_MsgData) + 1);
 -
 -              smi.meta_msgnum = import_msgnum;
 -              PutMetaData(&smi);
 +              StrBufDecodeBase64To(migr_chardata, migr_MsgData);
 +
 +              msg = CtdlDeserializeMessage(import_msgnum, -1,
 +                                           ChrPtr(migr_MsgData), 
 +                                           StrLength(migr_MsgData));
 +              if (msg != NULL) {
 +                      rc = CtdlSaveThisMessage(msg, import_msgnum, 0);
 +                      if (rc == 0) {
 +                              PutMetaData(&smi);
 +                      }
 +                      CM_Free(msg);
 +              }
 +              else {
 +                      rc = -1;
 +              }
  
                syslog(LOG_INFO,
 -                     "Imported message #%ld, size=%d, refcount=%d, content-type: %s\n",
 +                     "%s message #%ld, size=%d, refcount=%d, bodylength=%ld, content-type: %s / %s \n",
 +                     (rc!= 0)?"failed to import ":"Imported ",
                       import_msgnum,
                       StrLength(migr_MsgData),
                       smi.meta_refcount,
 -                     smi.meta_content_type);
 +                     smi.meta_rfc822_length,
 +                     smi.meta_content_type,
 +                     smi.mimetype);
 +              memset(&smi, 0, sizeof(smi));
        }
  
        /*** MORE GENERAL STUFF ***/
@@@ -1037,9 -854,6 +870,9 @@@ void migr_do_import(void) 
  
  
  
 +/******************************************************************************
 + *                         Dispatcher, Common code                            *
 + ******************************************************************************/
  /*
   * Dump out the pathnames of directories which can be copied "as is"
   */
@@@ -1056,200 -870,12 +889,200 @@@ void migr_do_listdirs(void) 
        cprintf("000\n");
  }
  
 +/******************************************************************************
 + *                    Repair database integrity                               *
 + ******************************************************************************/
  
 -/*
 - * Common code appears in this section
 - */
 +StrBuf *PlainMessageBuf = NULL;
 +HashList *UsedMessageIDS = NULL;
  
 +int migr_restore_message_metadata(long msgnum, int refcount)
 +{
 +      CitContext *CCC = MyContext();
 +      struct MetaData smi;
 +      struct CtdlMessage *msg;
 +      char *mptr = NULL;
 +
 +      /* We can use a static buffer here because there will never be more than
 +       * one of this operation happening at any given time, and it's really best
 +       * to just keep it allocated once instead of torturing malloc/free.
 +       * Call this function with msgnum "-1" to free the buffer when finished.
 +       */
 +      static int encoded_alloc = 0;
 +      static char *encoded_msg = NULL;
 +
 +      if (msgnum < 0) {
 +              if ((encoded_alloc == 0) && (encoded_msg != NULL)) {
 +                      free(encoded_msg);
 +                      encoded_alloc = 0;
 +                      encoded_msg = NULL;
 +                      // todo FreeStrBuf(&PlainMessageBuf); PlainMessageBuf = NULL;
 +              }
 +              return 0;
 +      }
 +
 +      if (PlainMessageBuf == NULL) {
 +              PlainMessageBuf = NewStrBufPlain(NULL, 10*SIZ);
 +      }
 +
 +      /* Ok, here we go ... */
 +
 +      msg = CtdlFetchMessage(msgnum, 1, 0);
 +      if (msg == NULL) {
 +              return 1;
 +      }
 +
 +      GetMetaData(&smi, msgnum);
 +      smi.meta_msgnum = msgnum;
 +      smi.meta_refcount = refcount;
 +      
 +      /* restore the content type from the message body: */
 +      mptr = bmstrcasestr(msg->cm_fields[eMesageText], "Content-type:");
 +      if (mptr != NULL) {
 +              char *aptr;
 +              safestrncpy(smi.meta_content_type, &mptr[13], sizeof smi.meta_content_type);
 +              striplt(smi.meta_content_type);
 +              aptr = smi.meta_content_type;
 +              while (!IsEmptyStr(aptr)) {
 +                      if ((*aptr == ';')
 +                          || (*aptr == ' ')
 +                          || (*aptr == 13)
 +                          || (*aptr == 10)) {
 +                              memset(aptr, 0, sizeof(smi.meta_content_type) - (aptr - smi.meta_content_type));
 +                      }
 +                      else aptr++;
 +              }
 +      }
 +
 +      CCC->redirect_buffer = PlainMessageBuf;
 +      CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, QP_EADDR);
 +      smi.meta_rfc822_length = StrLength(CCC->redirect_buffer);
 +      CCC->redirect_buffer = NULL;
 +
 +
 +      syslog(LOG_INFO,
 +             "Setting message #%ld meta data to: refcount=%d, bodylength=%ld, content-type: %s / %s \n",
 +             smi.meta_msgnum,
 +             smi.meta_refcount,
 +             smi.meta_rfc822_length,
 +             smi.meta_content_type,
 +             smi.mimetype);
 +
 +      PutMetaData(&smi);
 +
 +      CM_Free(msg);
 +
 +      return 0;
 +}
 +
 +void migr_check_room_msg(long msgnum, void *userdata) {
 +      fprintf(migr_global_message_list, "%ld %s\n", msgnum, CC->room.QRname);
 +}
  
 +
 +void migr_check_rooms_backend(struct ctdlroom *buf, void *data) {
 +
 +      /* message list goes inside this tag */
 +
 +      CtdlGetRoom(&CC->room, buf->QRname);
 +      CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, migr_check_room_msg, NULL);
 +}
 +
 +void RemoveMessagesFromRooms(StrBuf *RoomNameVec, long msgnum) {
 +      struct MetaData smi;
 +      const char *Pos = NULL;
 +      StrBuf *oneRoom = NewStrBuf();
 +
 +      syslog(LOG_INFO, "removing message pointer %ld from these rooms: %s", msgnum, ChrPtr(RoomNameVec));
 +
 +      while (Pos != StrBufNOTNULL){
 +              StrBufExtract_NextToken(oneRoom, RoomNameVec, &Pos, '|');
 +              CtdlDeleteMessages(ChrPtr(oneRoom), &msgnum, 1, "");
 +      };
 +      GetMetaData(&smi, msgnum);
 +      TDAP_AdjRefCount(msgnum, -smi.meta_refcount);
 +}
 +
 +void migr_do_restore_meta(void) {
 +      char buf[SIZ];
 +      int failGetMessage;
 +      long msgnum;
 +      int lastnum = 0;
 +      int refcount = 0;
 +      CitContext *Ctx;
 +      char *prn;
 +      StrBuf *RoomNames;
 +      char cmd[SIZ];
 +
 +      migr_global_message_list = fopen(migr_tempfilename1, "w");
 +      if (migr_global_message_list != NULL) {
 +              CtdlForEachRoom(migr_check_rooms_backend, NULL);
 +              fclose(migr_global_message_list);
 +      }
 +
 +      /*
 +       * Process the 'global' message list.  (Sort it and remove dups.
 +       * Dups are ok because a message may be in more than one room, but
 +       * this will be handled by exporting the reference count, not by
 +       * exporting the message multiple times.)
 +       */
 +      snprintf(cmd, sizeof cmd, "sort -n <%s >%s", migr_tempfilename1, migr_tempfilename2);
 +      if (system(cmd) != 0) syslog(LOG_ALERT, "Error %d\n", errno);
 +
 +      RoomNames = NewStrBuf();
 +      Ctx = CC;
 +      migr_global_message_list = fopen(migr_tempfilename2, "r");
 +      if (migr_global_message_list != NULL) {
 +              syslog(LOG_INFO, "Opened %s\n", migr_tempfilename1);
 +              while ((Ctx->kill_me == 0) && 
 +                     (fgets(buf, sizeof(buf), migr_global_message_list) != NULL)) {
 +                      msgnum = atol(buf);
 +                      if (msgnum == 0L) 
 +                              continue;
 +                      if (lastnum == 0) {
 +                              lastnum = msgnum;
 +                      }
 +                      prn = strchr(buf, ' ');
 +                      if (lastnum != msgnum) {
 +                              failGetMessage = migr_restore_message_metadata(lastnum, refcount);
 +                              if (failGetMessage) {
 +                                      RemoveMessagesFromRooms(RoomNames, lastnum);
 +                              }
 +                              refcount = 1;
 +                              lastnum = msgnum;
 +                              if (prn != NULL)
 +                                      StrBufPlain(RoomNames, prn + 1, -1);
 +                              StrBufTrim(RoomNames);
 +                      }
 +                      else {
 +                              if (prn != NULL) {
 +                                      if (StrLength(RoomNames) > 0)
 +                                              StrBufAppendBufPlain(RoomNames, HKEY("|"), 0);
 +                                      StrBufAppendBufPlain(RoomNames, prn, -1, 1);
 +                                      StrBufTrim(RoomNames);
 +                              }
 +                              refcount ++;
 +                      }
 +                      lastnum = msgnum;
 +              }
 +              failGetMessage = migr_restore_message_metadata(msgnum, refcount);
 +              if (failGetMessage) {
 +                      RemoveMessagesFromRooms(RoomNames, lastnum);
 +              }
 +              fclose(migr_global_message_list);
 +      }
 +
 +      migr_restore_message_metadata(-1L, -1); /* This frees the encoding buffer */
 +      cprintf("%d system analysis completed", CIT_OK);
 +      Ctx->kill_me = 1;
 +}
 +
 +
 +
 +
 +/******************************************************************************
 + *                         Dispatcher, Common code                            *
 + ******************************************************************************/
  void cmd_migr(char *cmdbuf) {
        char cmd[32];
        
                else if (!strcasecmp(cmd, "listdirs")) {
                        migr_do_listdirs();
                }
 +              else if (!strcasecmp(cmd, "restoremeta")) {
 +                      migr_do_restore_meta();
 +              }
                else {
                        cprintf("%d illegal command\n", ERROR + ILLEGAL_VALUE);
                }
        }
  }
  
 +/******************************************************************************
 + *                              Module Hook                                  *
 + ******************************************************************************/
  
  CTDL_MODULE_INIT(migrate)
  {
index 10d957e710a1495b0a9c6c6996d431b2c4eeb2fb,30b92b7203c89e4e6d7b84eb726fb8754551cade..9ca6ba5a957af81458a21d1323a9a639e9f851af
@@@ -2,7 -2,7 +2,7 @@@
   * This module handles shared rooms, inter-Citadel mail, and outbound
   * mailing list processing.
   *
-  * Copyright (c) 2000-2012 by the citadel.org team
+  * Copyright (c) 2000-2015 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.
@@@ -218,7 -218,7 +218,7 @@@ void network_deliver_digest(SpoolContro
  
        /* Where do we want bounces and other noise to be heard?
         * Surely not the list members! */
-       snprintf(bounce_to, sizeof bounce_to, "room_aide@%s", config.c_fqdn);
+       snprintf(bounce_to, sizeof bounce_to, "room_aide@%s", CtdlGetConfigStr("c_fqdn"));
  
        /* Now submit the message */
        valid = validate_recipients(ChrPtr(sc->Users[digestrecp]), NULL, 0);
@@@ -366,7 -366,7 +366,7 @@@ void network_deliver_list(struct CtdlMe
  
        /* Where do we want bounces and other noise to be heard?
         *  Surely not the list members! */
-       snprintf(bounce_to, sizeof bounce_to, "room_aide@%s", config.c_fqdn);
+       snprintf(bounce_to, sizeof bounce_to, "room_aide@%s", CtdlGetConfigStr("c_fqdn"));
  
        /* Now submit the message */
        valid = validate_recipients(ChrPtr(sc->Users[listrecp]), NULL, 0);
@@@ -403,8 -403,8 +403,8 @@@ void network_process_participate(SpoolC
         */
        ok_to_participate = 0;
        if (!CM_IsEmpty(msg, eNodeName)) {
-               if (!strcasecmp(msg->cm_fields[eNodeName],
-                               config.c_nodename)) {
+               if (!strcasecmp(msg->cm_fields[eNodeName], CtdlGetConfigStr("c_nodename")))
+               {
                        ok_to_participate = 1;
                }
                
@@@ -595,7 -595,7 +595,7 @@@ void network_spool_msg(long msgnum
  
        sc = (SpoolControl *)userdata;
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
  
        if (msg == NULL)
        {
index 86cad97b4a7144f83f91963e776c09f0c9279f7c,9698c3694f1f3aceb4f3100459a539505601f4f5..eeb35ba71b8fd060254ca953c498ffcdfae5812c
@@@ -2,15 -2,15 +2,15 @@@
   * This module handles shared rooms, inter-Citadel mail, and outbound
   * mailing list processing.
   *
-  * Copyright (c) 2000-2012 by the citadel.org team
+  * Copyright (c) 2000-2015 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 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.
+  * 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.
   *
   * ** NOTE **   A word on the S_NETCONFIGS semaphore:
   * This is a fairly high-level type of critical section.  It ensures that no
  #endif
  
  
-       snprintf(bouncesource, sizeof bouncesource, "%s@%s", BOUNCESOURCE, config.c_nodename);
 +/*
 + * Bounce a message back to the sender
 + */
 +void network_bounce(struct CtdlMessage **pMsg, char *reason)
 +{
 +      struct CitContext *CCC = CC;
 +      char buf[SIZ];
 +      char bouncesource[SIZ];
 +      char recipient[SIZ];
 +      recptypes *valid = NULL;
 +      char force_room[ROOMNAMELEN];
 +      static int serialnum = 0;
 +      long len;
 +      struct CtdlMessage *msg = *pMsg;
 +      *pMsg = NULL;
 +      QNM_syslog(LOG_DEBUG, "entering network_bounce()\n");
 +
 +      if (msg == NULL) return;
 +
-                      config.c_fqdn);
++      snprintf(bouncesource, sizeof bouncesource, "%s@%s", BOUNCESOURCE, CtdlGetConfigStr("c_nodename"));
 +
 +      /* 
 +       * Give it a fresh message ID
 +       */
 +      len = snprintf(buf, sizeof(buf),
 +                     "%ld.%04lx.%04x@%s",
 +                     (long)time(NULL),
 +                     (long)getpid(),
 +                     ++serialnum,
-       CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
++                     CtdlGetConfigStr("c_fqdn"));
 +
 +      CM_SetField(msg, emessageId, buf, len);
 +
 +      /*
 +       * FIXME ... right now we're just sending a bounce; we really want to
 +       * include the text of the bounced message.
 +       */
 +      CM_SetField(msg, eMesageText, reason, strlen(reason));
 +      msg->cm_format_type = 0;
 +
 +      /*
 +       * Turn the message around
 +       */
 +      CM_FlushField(msg, eRecipient);
 +      CM_FlushField(msg, eDestination);
 +
 +      len = snprintf(recipient, sizeof(recipient), "%s@%s",
 +                     msg->cm_fields[eAuthor],
 +                     msg->cm_fields[eNodeName]);
 +
 +      CM_SetField(msg, eAuthor, HKEY(BOUNCESOURCE));
-               strcpy(force_room, config.c_aideroom);
++      CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
 +      CM_SetField(msg, eMsgSubject, HKEY("Delivery Status Notification (Failure)"));
 +
 +      Netmap_AddMe(msg, HKEY("unknown_user"));
 +
 +      /* Now submit the message */
 +      valid = validate_recipients(recipient, NULL, 0);
 +      if (valid != NULL) if (valid->num_error != 0) {
 +              free_recipients(valid);
 +              valid = NULL;
 +      }
 +      if ( (valid == NULL) || (!strcasecmp(recipient, bouncesource)) ) {
-               strcpy(force_room, config.c_aideroom);
++              strcpy(force_room, CtdlGetConfigStr("c_aideroom"));
 +      }
 +      else {
 +              strcpy(force_room, "");
 +      }
 +      if ( (valid == NULL) && IsEmptyStr(force_room) ) {
++              strcpy(force_room, CtdlGetConfigStr("c_aideroom"));
 +      }
 +      CtdlSubmitMsg(msg, valid, force_room, 0);
 +
 +      /* Clean up */
 +      if (valid != NULL) free_recipients(valid);
 +      CM_Free(msg);
 +      QNM_syslog(LOG_DEBUG, "leaving network_bounce()\n");
 +}
 +
 +
  void ParseLastSent(const CfgLineType *ThisOne, StrBuf *Line, const char *LinePos, OneRoomNetCfg *OneRNCFG)
  {
        RoomNetCfgLine *nptr;
@@@ -248,10 -168,10 +248,10 @@@ void Netmap_AddMe(struct CtdlMessage *m
        if (CM_IsEmpty(msg, eMessagePath)) {
                CM_SetField(msg, eMessagePath, defl, defllen);
        }
-       node_len = configlen.c_nodename;
+       node_len = strlen(CtdlGetConfigStr("c_nodename"));
        if (node_len >= SIZ) 
                node_len = SIZ - 1;
-       memcpy(buf, config.c_nodename, node_len);
+       memcpy(buf, CtdlGetConfigStr("c_nodename"), node_len);
        buf[node_len] = '!';
        buf[node_len + 1] = '\0';
        CM_PrependToField(msg, eMessagePath, buf, node_len + 1);
@@@ -387,7 -307,7 +387,7 @@@ void CalcListID(SpoolControl *sc
                StrBufAppendBufPlain(sc->ListID, HKEY("room_"), 0);
                StrBufAppendBuf(sc->ListID, RoomName, 0);
                StrBufAppendBufPlain(sc->ListID, HKEY("."), 0);
-               StrBufAppendBufPlain(sc->ListID, config.c_fqdn, -1, 0);
+               StrBufAppendBufPlain(sc->ListID, CtdlGetConfigStr("c_fqdn"), -1, 0);
                /*
                 * this used to be:
                 * roomname <Room-Number.list-id.fqdn>
                StrBufAppendBufPlain(sc->Users[roommailalias], HKEY("room_"), 0);
                StrBufAppendBuf(sc->Users[roommailalias], RoomName, 0);
                StrBufAppendBufPlain(sc->Users[roommailalias], HKEY("@"), 0);
-               StrBufAppendBufPlain(sc->Users[roommailalias], config.c_fqdn, -1, 0);
+               StrBufAppendBufPlain(sc->Users[roommailalias], CtdlGetConfigStr("c_fqdn"), -1, 0);
  
                StrBufLowerCase(sc->Users[roommailalias]);
        }
@@@ -454,8 -374,7 +454,8 @@@ void network_spoolout_room(SpoolContro
        }
        else
        {
 -              snprintf(buf, sizeof buf, "room_%s@%s", CCC->room.QRname, CtdlGetConfigStr("c_fqdn"));
 +              snprintf(buf, sizeof buf, "room_%s@%s",
-                        CCC->room.QRname, config.c_fqdn);
++                       CCC->room.QRname, CtdlGetConfigStr("c_fqdn"));
        }
  
        for (i=0; buf[i]; ++i) {
        }
  }
  
 +
 +/*
 + * Check the use table.  This is a list of messages which have recently
 + * arrived on the system.  It is maintained and queried to prevent the same
 + * message from being entered into the database multiple times if it happens
 + * to arrive multiple times by accident.
 + */
 +int network_usetable(struct CtdlMessage *msg)
 +{
 +      StrBuf *msgid;
 +      struct CitContext *CCC = CC;
 +      time_t now;
 +
 +      /* Bail out if we can't generate a message ID */
 +      if ((msg == NULL) || CM_IsEmpty(msg, emessageId))
 +      {
 +              return(0);
 +      }
 +
 +      /* Generate the message ID */
 +      msgid = NewStrBufPlain(CM_KEY(msg, emessageId));
 +      if (haschar(ChrPtr(msgid), '@') == 0) {
 +              StrBufAppendBufPlain(msgid, HKEY("@"), 0);
 +              if (!CM_IsEmpty(msg, eNodeName)) {
 +                      StrBufAppendBufPlain(msgid, CM_KEY(msg, eNodeName), 0);
 +              }
 +              else {
 +                      FreeStrBuf(&msgid);
 +                      return(0);
 +              }
 +      }
 +      now = time(NULL);
 +      if (CheckIfAlreadySeen("Networker Import",
 +                             msgid,
 +                             now, 0,
 +                             eUpdate,
 +                             CCC->cs_pid, 0) != 0)
 +      {
 +              FreeStrBuf(&msgid);
 +              return(1);
 +      }
 +      FreeStrBuf(&msgid);
 +
 +      return(0);
 +}
 +
 +
  /*
   * Process a buffer containing a single message from a single file
   * from the inbound queue 
@@@ -612,7 -484,7 +612,7 @@@ void network_process_buffer(char *buffe
  
        /* Check for message routing */
        if (!CM_IsEmpty(msg, eDestination)) {
-               if (strcasecmp(msg->cm_fields[eDestination], config.c_nodename)) {
+               if (strcasecmp(msg->cm_fields[eDestination], CtdlGetConfigStr("c_nodename"))) {
  
                        /* route the message */
                        Buf = NewStrBufPlain(CM_KEY(msg,eDestination));
                        else {  /* invalid destination node name */
                                FreeStrBuf(&Buf);
  
 -                              network_bounce(msg,
 +                              network_bounce(&msg,
  "A message you sent could not be delivered due to an invalid destination node"
  " name.  Please check the address and try sending the message again.\n");
 -                              msg = NULL;
                                return;
  
                        }
        else if (!CM_IsEmpty(msg, eRecipient)) {
                recp = validate_recipients(msg->cm_fields[eRecipient], NULL, 0);
                if (recp != NULL) if (recp->num_error != 0) {
 -                      network_bounce(msg,
 +                      network_bounce(&msg,
                                "A message you sent could not be delivered due to an invalid address.\n"
                                "Please check the address and try sending the message again.\n");
 -                      msg = NULL;
                        free_recipients(recp);
                        QNM_syslog(LOG_DEBUG, "Bouncing message due to invalid recipient address.\n");
                        return;
index c6ca869da4b9946342b3dd6fbc14028a4a18e80a,58d2094afc13cedaf8de96e4f0f7928c7a7bdd13..1d843b46116d072f9b44f172df4689c1c5abf19a
@@@ -2,15 -2,15 +2,15 @@@
   * This module handles shared rooms, inter-Citadel mail, and outbound
   * mailing list processing.
   *
-  * Copyright (c) 2000-2012 by the citadel.org team
+  * Copyright (c) 2000-2015 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 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.
+  * 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.
   *
   * ** NOTE **   A word on the S_NETCONFIGS semaphore:
   * This is a fairly high-level type of critical section.  It ensures that no
@@@ -96,6 -96,54 +96,6 @@@ typedef struct __roomlists 
  struct RoomProcList *rplist = NULL;
  
  
 -
 -/*
 - * Check the use table.  This is a list of messages which have recently
 - * arrived on the system.  It is maintained and queried to prevent the same
 - * message from being entered into the database multiple times if it happens
 - * to arrive multiple times by accident.
 - */
 -int network_usetable(struct CtdlMessage *msg)
 -{
 -      StrBuf *msgid;
 -      struct CitContext *CCC = CC;
 -      time_t now;
 -
 -      /* Bail out if we can't generate a message ID */
 -      if ((msg == NULL) || CM_IsEmpty(msg, emessageId))
 -      {
 -              return(0);
 -      }
 -
 -      /* Generate the message ID */
 -      msgid = NewStrBufPlain(CM_KEY(msg, emessageId));
 -      if (haschar(ChrPtr(msgid), '@') == 0) {
 -              StrBufAppendBufPlain(msgid, HKEY("@"), 0);
 -              if (!CM_IsEmpty(msg, eNodeName)) {
 -                      StrBufAppendBufPlain(msgid, CM_KEY(msg, eNodeName), 0);
 -              }
 -              else {
 -                      FreeStrBuf(&msgid);
 -                      return(0);
 -              }
 -      }
 -      now = time(NULL);
 -      if (CheckIfAlreadySeen("Networker Import",
 -                             msgid,
 -                             now, 0,
 -                             eCheckUpdate,
 -                             CCC->cs_pid, 0) != 0)
 -      {
 -              FreeStrBuf(&msgid);
 -              return(1);
 -      }
 -      FreeStrBuf(&msgid);
 -
 -      return(0);
 -}
 -
 -
 -
  /*
   * Send the *entire* contents of the current room to one specific network node,
   * ignoring anything we know about which messages have already undergone
@@@ -292,6 -340,89 +292,6 @@@ void destroy_network_queue_room_locked 
  }
  
  
 -
 -/*
 - * Bounce a message back to the sender
 - */
 -void network_bounce(struct CtdlMessage *msg, char *reason)
 -{
 -      struct CitContext *CCC = CC;
 -      char buf[SIZ];
 -      char bouncesource[SIZ];
 -      char recipient[SIZ];
 -      recptypes *valid = NULL;
 -      char force_room[ROOMNAMELEN];
 -      static int serialnum = 0;
 -      long len;
 -
 -      QNM_syslog(LOG_DEBUG, "entering network_bounce()\n");
 -
 -      if (msg == NULL) return;
 -
 -      snprintf(bouncesource, sizeof bouncesource, "%s@%s", BOUNCESOURCE, CtdlGetConfigStr("c_nodename"));
 -
 -      /* 
 -       * Give it a fresh message ID
 -       */
 -      len = snprintf(buf, sizeof(buf),
 -                     "%ld.%04lx.%04x@%s",
 -                     (long)time(NULL),
 -                     (long)getpid(),
 -                     ++serialnum,
 -                     CtdlGetConfigStr("c_fqdn")
 -      );
 -
 -      CM_SetField(msg, emessageId, buf, len);
 -
 -      /*
 -       * FIXME ... right now we're just sending a bounce; we really want to
 -       * include the text of the bounced message.
 -       */
 -      CM_SetField(msg, eMesageText, reason, strlen(reason));
 -      msg->cm_format_type = 0;
 -
 -      /*
 -       * Turn the message around
 -       */
 -      CM_FlushField(msg, eRecipient);
 -      CM_FlushField(msg, eDestination);
 -
 -      len = snprintf(recipient, sizeof(recipient), "%s@%s",
 -                     msg->cm_fields[eAuthor],
 -                     msg->cm_fields[eNodeName]);
 -
 -      CM_SetField(msg, eAuthor, HKEY(BOUNCESOURCE));
 -      CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
 -      CM_SetField(msg, eMsgSubject, HKEY("Delivery Status Notification (Failure)"));
 -
 -      Netmap_AddMe(msg, HKEY("unknown_user"));
 -
 -      /* Now submit the message */
 -      valid = validate_recipients(recipient, NULL, 0);
 -      if (valid != NULL) if (valid->num_error != 0) {
 -              free_recipients(valid);
 -              valid = NULL;
 -      }
 -      if ( (valid == NULL) || (!strcasecmp(recipient, bouncesource)) )
 -      {
 -              strcpy(force_room, CtdlGetConfigStr("c_aideroom"));
 -      }
 -      else {
 -              strcpy(force_room, "");
 -      }
 -      if ( (valid == NULL) && IsEmptyStr(force_room) ) {
 -              strcpy(force_room, CtdlGetConfigStr("c_aideroom"));
 -      }
 -      CtdlSubmitMsg(msg, valid, force_room, 0);
 -
 -      /* Clean up */
 -      if (valid != NULL) free_recipients(valid);
 -      CM_Free(msg);
 -      QNM_syslog(LOG_DEBUG, "leaving network_bounce()\n");
 -}
 -
 -
 -
  /*
   * network_do_queue()
   * 
@@@ -313,10 -444,11 +313,11 @@@ void network_do_queue(void
         * Run the full set of processing tasks no more frequently
         * than once every n seconds
         */
-       if ( (time(NULL) - last_run) < config.c_net_freq ) {
+       if ( (time(NULL) - last_run) < CtdlGetConfigLong("c_net_freq") )
+       {
                full_processing = 0;
                syslog(LOG_DEBUG, "Network full processing in %ld seconds.\n",
-                      config.c_net_freq - (time(NULL)- last_run)
+                      CtdlGetConfigLong("c_net_freq") - (time(NULL)- last_run)
                );
        }
  
index a895581989a563b27496086f649b48e449e10e47,15f91d466a9e6c3c6c680252b3ce8a78623e0260..dee22bdfc4fedc72808d3be289d995fb8e7c2b6f
@@@ -1,7 -1,7 +1,7 @@@
  //
  // NNTP server module (RFC 3977)
  //
- // Copyright (c) 2014 by the citadel.org team
+ // Copyright (c) 2014-2015 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.
@@@ -200,7 -200,7 +200,7 @@@ void nntp_greeting(void
        }
  
        // Display the standard greeting
-       cprintf("200 %s NNTP Citadel server is not finished yet\r\n", config.c_fqdn);
+       cprintf("200 %s NNTP Citadel server is not finished yet\r\n", CtdlGetConfigStr("c_fqdn"));
  }
  
  
@@@ -284,7 -284,7 +284,7 @@@ void nntp_authinfo_user(const char *use
                cprintf("482 Already logged in\r\n");
                return;
        case login_too_many_users:
-               cprintf("481 Too many users are already online (maximum is %d)\r\n", config.c_maxsessions);
+               cprintf("481 Too many users are already online (maximum is %d)\r\n", CtdlGetConfigInt("c_maxsessions"));
                return;
        case login_ok:
                cprintf("381 Password required for %s\r\n", CC->curr_user);
@@@ -977,7 -977,7 +977,7 @@@ void nntp_xover_backend(long msgnum, vo
        if (msgnum < lr->lo) return;
        if ((lr->hi != 0) && (msgnum > lr->hi)) return;
  
 -      struct CtdlMessage *msg = CtdlFetchMessage(msgnum, 0);
 +      struct CtdlMessage *msg = CtdlFetchMessage(msgnum, 0, 1);
        if (msg == NULL) {
                return;
        }
@@@ -1178,7 -1178,7 +1178,7 @@@ CTDL_MODULE_INIT(nntp
  {
        if (!threading)
        {
-               CtdlRegisterServiceHook(config.c_nntp_port,
+               CtdlRegisterServiceHook(CtdlGetConfigInt("c_nntp_port"),
                                        NULL,
                                        nntp_greeting,
                                        nntp_command_loop,
                                        CitadelServiceNNTP);
  
  #ifdef HAVE_OPENSSL
-               CtdlRegisterServiceHook(config.c_nntps_port,
+               CtdlRegisterServiceHook(CtdlGetConfigInt("c_nntps_port"),
                                        NULL,
                                        nntps_greeting,
                                        nntp_command_loop,
index 58cf69094c070980402524949f11fa00615e851e,f7587b7f27a9c95c9012fec225f84f59183805ab..700c5741983a79d7b7f304ea2973c1d2c71d3875
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * Consolidate mail from remote POP3 accounts.
   *
-  * Copyright (c) 2007-2011 by the citadel.org team
+  * Copyright (c) 2007-2015 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 as published
   * 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.
-  *
-  * You should have received a copy of the GNU General Public License
-  * along with this program; if not, write to the Free Software
-  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  #include <stdlib.h>
@@@ -418,7 -414,6 +414,7 @@@ eNextState POP3_FetchNetworkUsetableEnt
        const char *HKey;
        void *vData;
        pop3aggr *RecvMsg = (pop3aggr *) IO->Data;
 +      time_t seenstamp = 0;
  
        SetPOP3State(IO, eUseTable);
  
                if (server_shutting_down)
                        return eAbort;
  
 -              if (CheckIfAlreadySeen("POP3 Item Seen",
 -                                     RecvMsg->CurrMsg->MsgUID,
 -                                     EvGetNow(IO),
 -                                     EvGetNow(IO) - USETABLE_ANTIEXPIRE,
 -                                     eCheckUpdate,
 -                                     IO->ID, CCID)
 -                  != 0)
 +              RecvMsg->CurrMsg = (FetchItem*)vData;
 +
 +              seenstamp = CheckIfAlreadySeen("POP3 Item Seen",
 +                                             RecvMsg->CurrMsg->MsgUID,
 +                                             EvGetNow(IO),
 +                                             EvGetNow(IO) - USETABLE_ANTIEXPIRE,
 +                                             eCheckUpdate,
 +                                             IO->ID, CCID);
 +              if (seenstamp != 0)
                {
                        /* Item has already been seen */
                        RecvMsg->CurrMsg->NeedFetch = 0;
@@@ -542,8 -535,6 +538,8 @@@ eNextState POP3C_SendGetOneMsg(pop3agg
  
        SetPOP3State(IO, eGetMsg);
  
 +      EVP3CM_syslog(LOG_DEBUG, "fast forwarding to the next unknown message");
 +
        RecvMsg->CurrMsg = NULL;
        while ((RecvMsg->Pos != NULL) && 
               GetNextHashPos(RecvMsg->MsgNumbers,
  
        if ((RecvMsg->CurrMsg != NULL ) && (RecvMsg->CurrMsg->NeedFetch == 1))
        {
 +              EVP3CM_syslog(LOG_DEBUG, "fetching next");
                /* Message has not been seen.
                 * Tell the server to fetch the message... */
                StrBufPrintf(RecvMsg->IO.SendBuf.Buf,
                return eReadMessage;
        }
        else {
 +              EVP3CM_syslog(LOG_DEBUG, "no more messages to fetch.");
                RecvMsg->State = ReadQuitState;
                return POP3_C_DispatchWriteDone(&RecvMsg->IO);
        }
@@@ -579,7 -568,7 +575,7 @@@ eNextState POP3C_ReadMessageBodyFollowi
        if (!POP3C_OK) return eTerminateConnection;
        RecvMsg->IO.ReadMsg = NewAsyncMsg(HKEY("."),
                                          RecvMsg->CurrMsg->MSGSize,
-                                         config.c_maxmsglen,
+                                         CtdlGetConfigLong("c_maxmsglen"),
                                          NULL, -1,
                                          1);
  
@@@ -659,7 -648,7 +655,7 @@@ eNextState POP3C_ReadDeleteState(pop3ag
        AsyncIO *IO = &RecvMsg->IO;
        POP3C_DBG_READ();
        RecvMsg->State = GetOneMessageIDState;
 -      return eReadMessage;
 +      return POP3_C_DispatchWriteDone(&RecvMsg->IO);
  }
  
  eNextState POP3C_SendQuit(pop3aggr *RecvMsg)
@@@ -1155,10 -1144,10 +1151,10 @@@ void pop3client_scan(void) 
  
        become_session(&pop3_client_CC);
  
-       if (config.c_pop3_fastest < config.c_pop3_fetch)
-               fastest_scan = config.c_pop3_fastest;
+       if (CtdlGetConfigLong("c_pop3_fastest") < CtdlGetConfigLong("c_pop3_fetch"))
+               fastest_scan = CtdlGetConfigLong("c_pop3_fastest");
        else
-               fastest_scan = config.c_pop3_fetch;
+               fastest_scan = CtdlGetConfigLong("c_pop3_fetch");
  
        /*
         * Run POP3 aggregation no more frequently than once every n seconds
  
  /*
        if ((palist->interval && time(NULL) > (last_run + palist->interval))
-                       || (time(NULL) > last_run + config.c_pop3_fetch))
+                       || (time(NULL) > last_run + CtdlGetConfigLong("c_pop3_fetch")))
                        pop3_do_fetching(palist->roomname, palist->pop3host,
                        palist->pop3user, palist->pop3pass, palist->keep);
                pptr = palist;
index 337ace94a765555d259a8c44b1a7f49617bb710f,ac4e7da7d0e35c27e3b520f29abfdf871c31ffa3..697b63b47b986111ca86f2e88609010b90e09f9b
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * Bring external RSS feeds into rooms.
   *
-  * Copyright (c) 2007-2012 by the citadel.org team
+  * Copyright (c) 2007-2015 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.
@@@ -365,7 -365,7 +365,7 @@@ int rss_format_item(AsyncIO *IO, networ
                CM_SetField(&SaveMsg->Msg, eAuthor, HKEY("rss"));
        }
  
-       CM_SetField(&SaveMsg->Msg, eNodeName, CFG_KEY(c_nodename));
+       CM_SetField(&SaveMsg->Msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
        if (SaveMsg->title != NULL) {
                long len;
                char *Sbj;
@@@ -685,7 -685,7 +685,7 @@@ eNextState RSSAggregator_AnalyseReply(A
                               guid,
                               EvGetNow(IO),
                               EvGetNow(IO) - USETABLE_ANTIEXPIRE,
 -                             eCheckUpdate,
 +                             eUpdate,
                               CCID, IO->ID)
            != 0)
        {
index a2523217f6a7fa973bc344f5af7cdd19f62ba972,ddb1e99ba06afd2e3ef40016dee3aa21e1f48a8b..94d8a5fa34a0738a7374df3e718a3088c1e5dfa9
@@@ -2,7 -2,7 +2,7 @@@
   * This module glues libSieve to the Citadel server in order to implement
   * the Sieve mailbox filtering language (RFC 3028).
   *
-  * Copyright (c) 1987-2012 by the citadel.org team
+  * Copyright (c) 1987-2015 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.
@@@ -124,7 -124,7 +124,7 @@@ int ctdl_redirect(sieve2_context_t *s, 
                return SIEVE2_ERROR_BADARGS;
        }
  
 -      msg = CtdlFetchMessage(cs->msgnum, 1);
 +      msg = CtdlFetchMessage(cs->msgnum, 1, 1);
        if (msg == NULL) {
                SV_syslog(LOG_WARNING, "REDIRECT failed: unable to fetch msg %ld", cs->msgnum);
                free_recipients(valid);
@@@ -553,7 -553,7 +553,7 @@@ void sieve_do_msg(long msgnum, void *us
        /*
         * Make sure you include message body so you can get those second-level headers ;)
         */
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) return;
  
        /*
        }
        if (haschar(my.envelope_from, '@') == 0) {
                strcat(my.envelope_from, "@");
-               strcat(my.envelope_from, config.c_fqdn);
+               strcat(my.envelope_from, CtdlGetConfigStr("c_fqdn"));
        }
  
        /* Keep track of the envelope-to address (use body-to if not found) */
        }
        if (haschar(my.envelope_to, '@') == 0) {
                strcat(my.envelope_to, "@");
-               strcat(my.envelope_to, config.c_fqdn);
+               strcat(my.envelope_to, CtdlGetConfigStr("c_fqdn"));
        }
  
        CM_Free(msg);
@@@ -749,7 -749,7 +749,7 @@@ void get_sieve_config_backend(long msgn
        long conflen;
  
        u->config_msgnum = msgnum;
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) {
                u->config_msgnum = (-1) ;
                return;
@@@ -1185,7 -1185,7 +1185,7 @@@ void cmd_msiv(char *argbuf) 
                extract_token(script_name, argbuf, 1, '|', sizeof script_name);
                if (!IsEmptyStr(script_name)) {
                        cprintf("%d Transmit script now\n", SEND_LISTING);
-                       script_content = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
+                       script_content = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0, 0);
                        msiv_putscript(&u, script_name, script_content);
                        changes_made = 1;
                }
index 2f9ea6532a052dfd586caa3a675b53375dcf3d8c,63422fbdcfd92127f52e57d2e2ce62ea79e8ad57..00f55e06a52c89d7be45603e731c0c709d778b24
@@@ -20,7 -20,7 +20,7 @@@
   * The VRFY and EXPN commands have been removed from this implementation
   * because nobody uses these commands anymore, except for spammers.
   *
-  * Copyright (c) 1998-2013 by the citadel.org team
+  * Copyright (c) 1998-2015 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.
@@@ -154,7 -154,7 +154,7 @@@ void smtp_greeting(int is_msa
        /* If this config option is set, reject connections from problem
         * addresses immediately instead of after they execute a RCPT
         */
-       if ( (config.c_rbl_at_greeting) && (sSMTP->is_msa == 0) ) {
+       if ( (CtdlGetConfigInt("c_rbl_at_greeting")) && (sSMTP->is_msa == 0) ) {
                if (rbl_check(message_to_spammer)) {
                        if (server_shutting_down)
                                cprintf("421 %s\r\n", message_to_spammer);
        /* Note: the FQDN *must* appear as the first thing after the 220 code.
         * Some clients (including citmail.c) depend on it being there.
         */
-       cprintf("220 %s ESMTP Citadel server ready.\r\n", config.c_fqdn);
+       cprintf("220 %s ESMTP Citadel server ready.\r\n", CtdlGetConfigStr("c_fqdn"));
  }
  
  
@@@ -284,7 -284,7 +284,7 @@@ void smtp_hello(long offset, long which
                        cprintf("250-Greetings and joyous salutations.\r\n");
                }
                cprintf("250-HELP\r\n");
-               cprintf("250-SIZE %ld\r\n", config.c_maxmsglen);
+               cprintf("250-SIZE %ld\r\n", CtdlGetConfigLong("c_maxmsglen"));
  
  #ifdef HAVE_OPENSSL
                /*
@@@ -318,7 -318,7 +318,7 @@@ void smtp_webcit_preferences_hack_backe
                return; // already got it
        }
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) {
                return;
        }
@@@ -674,7 -674,7 +674,7 @@@ void smtp_mail(long offset, long flags
        /* Otherwise, make sure outsiders aren't trying to forge mail from
         * this system (unless, of course, c_allow_spoofing is enabled)
         */
-       else if (config.c_allow_spoofing == 0) {
+       else if (CtdlGetConfigInt("c_allow_spoofing") == 0) {
                process_rfc822_addr(ChrPtr(sSMTP->from), user, node, name);
                syslog(LOG_DEBUG, "Claimed envelope sender is '%s' == '%s' @ '%s' ('%s')",
                        ChrPtr(sSMTP->from), user, node, name
@@@ -730,7 -730,7 +730,7 @@@ void smtp_rcpt(long offset, long flags
        /* RBL check */
        if ( (!CCC->logged_in)  /* Don't RBL authenticated users */
           && (!sSMTP->is_lmtp) ) {     /* Don't RBL LMTP clients */
-               if (config.c_rbl_at_greeting == 0) {    /* Don't RBL again if we already did it */
+               if (CtdlGetConfigInt("c_rbl_at_greeting") == 0) {       /* Don't RBL again if we already did it */
                        if (rbl_check(message_to_spammer)) {
                                if (server_shutting_down)
                                        cprintf("421 %s\r\n", message_to_spammer);
@@@ -826,7 -826,7 +826,7 @@@ void smtp_data(long offset, long flags
                                "       by %s; %s\n",
                                ChrPtr(sSMTP->helo_node),
                                (long int) CCC->cs_UDSclientUID,
-                               config.c_fqdn,
+                               CtdlGetConfigStr("c_fqdn"),
                                nowstamp);
                }
                else {
                                ChrPtr(sSMTP->helo_node),
                                CCC->cs_host,
                                CCC->cs_addr,
-                               config.c_fqdn,
+                               CtdlGetConfigStr("c_fqdn"),
                                nowstamp);
                }
        }
-       body = CtdlReadMessageBodyBuf(HKEY("."), config.c_maxmsglen, defbody, 1, NULL);
+       body = CtdlReadMessageBodyBuf(HKEY("."), CtdlGetConfigLong("c_maxmsglen"), defbody, 1, NULL);
        FreeStrBuf(&defbody);
        if (body == NULL) {
                cprintf("550 Unable to save message: internal error.\r\n");
         * to something ugly like "0000058008.Sent Items>" when the message
         * is read with a Citadel client.
         */
-       if ( (CCC->logged_in) && (config.c_rfc822_strict_from != CFG_SMTP_FROM_NOFILTER) ) {
+       if ( (CCC->logged_in) && (CtdlGetConfigInt("c_rfc822_strict_from") != CFG_SMTP_FROM_NOFILTER) ) {
                int validemail = 0;
                
                if (!CM_IsEmpty(msg, erFc822Addr)       &&
-                   ((config.c_rfc822_strict_from == CFG_SMTP_FROM_CORRECT) || 
-                    (config.c_rfc822_strict_from == CFG_SMTP_FROM_REJECT)    )  )
+                   ((CtdlGetConfigInt("c_rfc822_strict_from") == CFG_SMTP_FROM_CORRECT) || 
+                    (CtdlGetConfigInt("c_rfc822_strict_from") == CFG_SMTP_FROM_REJECT)    )  )
                {
                        if (!IsEmptyStr(CCC->cs_inet_email))
                                validemail = strcmp(CCC->cs_inet_email, msg->cm_fields[erFc822Addr]) == 0;
                        }
                }
  
-               if (!validemail && (config.c_rfc822_strict_from == CFG_SMTP_FROM_REJECT)) {
+               if (!validemail && (CtdlGetConfigInt("c_rfc822_strict_from") == CFG_SMTP_FROM_REJECT)) {
                        syslog(LOG_ERR, "invalid sender '%s' - rejecting this message", msg->cm_fields[erFc822Addr]);
                        cprintf("550 Invalid sender '%s' - rejecting this message.\r\n", msg->cm_fields[erFc822Addr]);
                        return;
                }
  
-               CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
-               CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode));
+               CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
+               CM_SetField(msg, eHumanNode, CtdlGetConfigStr("c_humannode"), strlen(CtdlGetConfigStr("c_humannode")));
                CM_SetField(msg, eOriginalRoom, HKEY(MAILROOM));
                if (sSMTP->preferred_sender_name != NULL)
                        CM_SetField(msg, eAuthor, SKEY(sSMTP->preferred_sender_name));
@@@ -1143,7 -1143,7 +1143,7 @@@ CTDL_MODULE_INIT(smtp
  #endif
  
  
-               CtdlRegisterServiceHook(config.c_smtp_port,     /* SMTP MTA */
+               CtdlRegisterServiceHook(CtdlGetConfigInt("c_smtp_port"),        /* SMTP MTA */
                                        NULL,
                                        smtp_mta_greeting,
                                        smtp_command_loop,
                                        CitadelServiceSMTP_MTA);
  
  #ifdef HAVE_OPENSSL
-               CtdlRegisterServiceHook(config.c_smtps_port,
+               CtdlRegisterServiceHook(CtdlGetConfigInt("c_smtps_port"),       /* SMTPS MTA */
                                        NULL,
                                        smtps_greeting,
                                        smtp_command_loop,
                                        CitadelServiceSMTPS_MTA);
  #endif
  
-               CtdlRegisterServiceHook(config.c_msa_port,      /* SMTP MSA */
+               CtdlRegisterServiceHook(CtdlGetConfigInt("c_msa_port"),         /* SMTP MSA */
                                        NULL,
                                        smtp_msa_greeting,
                                        smtp_command_loop,
index 10496eac5c693fdd8ffa7422eb6d53524144f970,a38dbe74262bf71c9ae7c3b3b42ca4aa9e46af74..d12e06aa58e2bd064939bdca6854393d9593cba5
   * The VRFY and EXPN commands have been removed from this implementation
   * because nobody uses these commands anymore, except for spammers.
   *
-  * Copyright (c) 1998-2012 by the citadel.org team
+  * Copyright (c) 1998-2015 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.
+  * 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"
@@@ -606,7 -600,7 +600,7 @@@ void smtpq_do_bounce(OneQueItem *MyQIte
        boundary = NewStrBufPlain(HKEY("=_Citadel_Multipart_"));
        StrBufAppendPrintf(boundary,
                           "%s_%04x%04x",
-                          config.c_fqdn,
+                          CtdlGetConfigStr("c_fqdn"),
                           getpid(),
                           ++seq);
  
  
        CM_SetField(bmsg, eOriginalRoom, HKEY(MAILROOM));
        CM_SetField(bmsg, eAuthor, HKEY("Citadel"));
-       CM_SetField(bmsg, eNodeName, CFG_KEY(c_nodename));
+       CM_SetField(bmsg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
        CM_SetField(bmsg, eMsgSubject, HKEY("Delivery Status Notification (Failure)"));
        CM_SetAsFieldSB(bmsg, eMesageText, &BounceMB);
  
  
        /* If not, post it in the Aide> room */
        if (successful_bounce == 0) {
-               CtdlSubmitMsg(bmsg, NULL, config.c_aideroom, QP_EADDR);
+               CtdlSubmitMsg(bmsg, NULL, CtdlGetConfigStr("c_aideroom"), QP_EADDR);
        }
  
        /* Free up the memory we used */
@@@ -842,7 -836,7 +836,7 @@@ void smtp_do_procmsg(long msgnum, void 
        SMTPC_syslog(LOG_DEBUG, "smtp_do_procmsg(%ld)\n", msgnum);
        ///strcpy(envelope_from, "");
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) {
                SMTPC_syslog(LOG_ERR, "tried %ld but no such message!\n",
                       msgnum);
index 202c806e9d756b72451d26578fb1ab6e4766fdd7,08cda5b080a3b4707a70b4f263c87d3cd37f2126..a86127fb42ad58f529e3e427eb0d2d45eb96eddc
@@@ -2,7 -2,7 +2,7 @@@
   * A server-side module for Citadel which supports address book information
   * using the standard vCard format.
   * 
-  * Copyright (c) 1999-2012 by the citadel.org team
+  * Copyright (c) 1999-2015 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.
   * set global flag calling for an aide to validate new users
   */
  void set_mm_valid(void) {
+       int flags = 0;
        begin_critical_section(S_CONTROL);
-       get_control();
-       CitControl.MMflags = CitControl.MMflags | MM_VALID ;
-       put_control();
+       flags = CtdlGetConfigInt("MMflags");
+       flags = flags | MM_VALID ;
+       CtdlSetConfigInt("MMflags", flags);
        end_critical_section(S_CONTROL);
  }
  
@@@ -185,7 -187,7 +187,7 @@@ int vcard_directory_add_user(char *inte
  void vcard_add_to_directory(long msgnum, void *data) {
        struct CtdlMessage *msg;
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg != NULL) {
                vcard_extract_internet_addresses(msg, vcard_directory_add_user);
        }
@@@ -385,7 -387,7 +387,7 @@@ int vcard_upload_beforesave(struct Ctdl
  
        /* If users cannot create their own accounts, they cannot re-register either. */
        if ( (yes_my_citadel_config) &&
-            (config.c_disable_newu) &&
+            (CtdlGetConfigInt("c_disable_newu")) &&
             (CCC->user.axlevel < AxAideU) &&
             (CCC->vcard_updated_by_ldap==0) )
        {
        /* Insert or replace RFC2739-compliant free/busy URL */
        if (yes_my_citadel_config) {
                sprintf(buf, "http://%s/%s.vfb",
-                       config.c_fqdn,
+                       CtdlGetConfigStr("c_fqdn"),
                        usbuf.fullname);
                for (i=0; buf[i]; ++i) {
                        if (buf[i] == ' ') buf[i] = '_';
@@@ -653,7 -655,7 +655,7 @@@ struct vCard *vcard_get_user(struct ctd
  
        if (VCmsgnum < 0L) return vcard_new();
  
 -      msg = CtdlFetchMessage(VCmsgnum, 1);
 +      msg = CtdlFetchMessage(VCmsgnum, 1, 1);
        if (msg == NULL) return vcard_new();
  
        v = vcard_load(msg->cm_fields[eMesageText]);
@@@ -723,7 -725,7 +725,7 @@@ void cmd_regi(char *argbuf) 
        }
  
        /* If users cannot create their own accounts, they cannot re-register either. */
-       if ( (config.c_disable_newu) && (CCC->user.axlevel < AxAideU) ) {
+       if ( (CtdlGetConfigInt("c_disable_newu")) && (CCC->user.axlevel < AxAideU) ) {
                cprintf("%d Self-service registration is not allowed here.\n",
                        ERROR + HIGHER_ACCESS_REQUIRED);
        }
@@@ -865,7 -867,7 +867,7 @@@ void vcard_newuser(struct ctdluser *usb
  
  #ifdef HAVE_GETPWUID_R
        /* If using host auth mode, we add an email address based on the login */
-       if (config.c_auth_mode == AUTHMODE_HOST) {
+       if (CtdlGetConfigInt("c_auth_mode") == AUTHMODE_HOST) {
                struct passwd pwd;
                char pwd_buffer[SIZ];
                
                syslog(LOG_DEBUG, "Searching for uid %d", usbuf->uid);
                if (getpwuid_r(usbuf->uid, &pwd, pwd_buffer, sizeof pwd_buffer, &result) == 0) {
  #endif // HAVE_GETPWUID_R
-                       snprintf(buf, sizeof buf, "%s@%s", pwd.pw_name, config.c_fqdn);
+                       snprintf(buf, sizeof buf, "%s@%s", pwd.pw_name, CtdlGetConfigStr("c_fqdn"));
                        vcard_add_prop(v, "email;internet", buf);
                        need_default_vcard=0;
                }
         * Is this an LDAP session?  If so, copy various LDAP attributes from the directory entry
         * into the user's vCard.
         */
-       if ((config.c_auth_mode == AUTHMODE_LDAP) || (config.c_auth_mode == AUTHMODE_LDAP_AD)) {
+       if ((CtdlGetConfigInt("c_auth_mode") == AUTHMODE_LDAP) || (CtdlGetConfigInt("c_auth_mode") == AUTHMODE_LDAP_AD)) {
              //uid_t ldap_uid;
            int found_user;
              char ldap_cn[512];
  #endif
        if (need_default_vcard!=0) {
          /* Everyone gets an email address based on their display name */
-         snprintf(buf, sizeof buf, "%s@%s", usbuf->fullname, config.c_fqdn);
+         snprintf(buf, sizeof buf, "%s@%s", usbuf->fullname, CtdlGetConfigStr("c_fqdn"));
          for (i=0; buf[i]; ++i) {
                if (buf[i] == ' ') buf[i] = '_';
          }
@@@ -938,7 -940,7 +940,7 @@@ void vcard_purge(struct ctdluser *usbuf
        msg->cm_format_type = 0;
        CM_SetField(msg, eAuthor, usbuf->fullname, strlen(usbuf->fullname));
        CM_SetField(msg, eOriginalRoom, HKEY(ADDRESS_BOOK_ROOM));
-       CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
+       CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
        CM_SetField(msg, eMesageText, HKEY("Purge this vCard\n"));
  
        len = snprintf(buf, sizeof buf, VCARD_EXT_FORMAT,
@@@ -1010,7 -1012,7 +1012,7 @@@ void vcard_delete_remove(char *room, lo
                return;
        }
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) return;
  
        if (CM_IsEmpty(msg, eMesageText))
@@@ -1137,7 -1139,7 +1139,7 @@@ void dvca_mime_callback(char *name, cha
  void dvca_callback(long msgnum, void *userdata) {
        struct CtdlMessage *msg = NULL;
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) return;
        mime_parser(CM_RANGE(msg, eMesageText),
                    *dvca_mime_callback,        /* callback function */
@@@ -1281,7 -1283,7 +1283,7 @@@ void vcard_session_login_hook(void) 
         * Is this an LDAP session?  If so, copy various LDAP attributes from the directory entry
         * into the user's vCard.
         */
-       if ((config.c_auth_mode == AUTHMODE_LDAP) || (config.c_auth_mode == AUTHMODE_LDAP_AD)) {
+       if ((CtdlGetConfigInt("c_auth_mode") == AUTHMODE_LDAP) || (CtdlGetConfigInt("c_auth_mode") == AUTHMODE_LDAP_AD)) {
                v = vcard_get_user(&CCC->user);
                if (v) {
                        if (Ctdl_LDAP_to_vCard(CCC->ldap_dn, v)) {
@@@ -1361,7 -1363,7 +1363,7 @@@ void strip_addresses_already_have(long 
  
        collected_addresses = (char *)userdata;
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) return;
        v = vcard_load(msg->cm_fields[eMesageText]);
        CM_Free(msg);
@@@ -1553,7 -1555,7 +1555,7 @@@ CTDL_MODULE_INIT(vcard
                }
  
                /* for postfix tcpdict */
-               CtdlRegisterServiceHook(config.c_pftcpdict_port,        /* Postfix */
+               CtdlRegisterServiceHook(CtdlGetConfigInt("c_pftcpdict_port"),   /* Postfix */
                                        NULL,
                                        check_get_greeting,
                                        check_get,
index 20a3103981044703f74fbb5208a2164ead4d0fa0,269777c944419fedd52b17db1009bba002c56c7a..4642d13d84d24c0b72ffbbc9399fc07e5c95db1a
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * Server-side module for Wiki rooms.  This handles things like version control. 
   * 
-  * Copyright (c) 2009-2012 by the citadel.org team
+  * Copyright (c) 2009-2015 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.
@@@ -127,7 -127,7 +127,7 @@@ int wiki_upload_beforesave(struct CtdlM
        /* See if we can retrieve the previous version. */
        old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields[eExclusiveID], &CCC->room);
        if (old_msgnum > 0L) {
 -              old_msg = CtdlFetchMessage(old_msgnum, 1);
 +              old_msg = CtdlFetchMessage(old_msgnum, 1, 1);
        }
        else {
                old_msg = NULL;
        history_msgnum = CtdlLocateMessageByEuid(history_page, &CCC->room);
        history_msg = NULL;
        if (history_msgnum > 0L) {
 -              history_msg = CtdlFetchMessage(history_msgnum, 1);
 +              history_msg = CtdlFetchMessage(history_msgnum, 1, 1);
        }
  
        /* Create a new history message if necessary */
                                           uuid,
                                           Now,
                                           CCC->user.fullname,
-                                          config.c_nodename);
+                                          CtdlGetConfigStr("c_nodename"));
  
                        memolen = CtdlEncodeBase64(encoded_memo, memo, memolen, 0);
  
@@@ -390,7 -390,7 +390,7 @@@ void wiki_history(char *pagename) 
        snprintf(history_page_name, sizeof history_page_name, "%s_HISTORY_", pagename);
        msgnum = CtdlLocateMessageByEuid(history_page_name, &CC->room);
        if (msgnum > 0L) {
 -              msg = CtdlFetchMessage(msgnum, 1);
 +              msg = CtdlFetchMessage(msgnum, 1, 1);
        }
        else {
                msg = NULL;
@@@ -522,7 -522,7 +522,7 @@@ void wiki_rev(char *pagename, char *rev
         */
        msgnum = CtdlLocateMessageByEuid(pagename, &CCC->room);
        if (msgnum > 0L) {
 -              msg = CtdlFetchMessage(msgnum, 1);
 +              msg = CtdlFetchMessage(msgnum, 1, 1);
        }
        else {
                msg = NULL;
        snprintf(history_page_name, sizeof history_page_name, "%s_HISTORY_", pagename);
        msgnum = CtdlLocateMessageByEuid(history_page_name, &CCC->room);
        if (msgnum > 0L) {
 -              msg = CtdlFetchMessage(msgnum, 1);
 +              msg = CtdlFetchMessage(msgnum, 1, 1);
        }
        else {
                msg = NULL;
                        CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname));
                        CM_SetField(msg, erFc822Addr, CCC->cs_inet_email, strlen(CCC->cs_inet_email));
                        CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname));
-                       CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
+                       CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
                        CM_SetField(msg, eExclusiveID, pagename, strlen(pagename));
                        msgnum = CtdlSubmitMsg(msg, NULL, "", 0);       /* Replace the current revision */
                }
index 85feda7086c0057b2cd170a63f039d47de30d7bf,b36228e273791b158af6a14be93ad96d5f305fc2..a3be435f73e7c3799e8c1ec4775aa61c0916b6d8
@@@ -158,7 -158,7 +158,7 @@@ void xmpp_destroy_buddy(char *presence_
        );
        cprintf("<query xmlns=\"jabber:iq:roster\">");
        cprintf("<item jid=\"%s\" subscription=\"remove\">", xmlesc(xmlbuf1, presence_jid, sizeof xmlbuf1));
-       cprintf("<group>%s</group>", xmlesc(xmlbuf1, config.c_humannode, sizeof xmlbuf1));
+       cprintf("<group>%s</group>", xmlesc(xmlbuf1, CtdlGetConfigStr("c_humannode"), sizeof xmlbuf1));
        cprintf("</item>");
        cprintf("</query>"
                "</iq>"
@@@ -229,7 -229,7 +229,7 @@@ void xmpp_fetch_mortuary_backend(long m
        char *ptr = NULL;
        char *lasts = NULL;
  
 -      msg = CtdlFetchMessage(msgnum, 1);
 +      msg = CtdlFetchMessage(msgnum, 1, 1);
        if (msg == NULL) {
                return;
        }
diff --combined citadel/msgbase.c
index 9d4451309fd8e831bd3618b67779097a9b7efa8c,494dbeea9b8fdc196e1404b30584edc3488e57d4..d8b1ac9d2bd6b573806c92294731f0b81f4c1972
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * Implements the message store.
   *
-  * Copyright (c) 1987-2012 by the citadel.org team
+  * Copyright (c) 1987-2015 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.
@@@ -22,6 -22,7 +22,7 @@@
  #include "ctdl_module.h"
  #include "citserver.h"
  #include "control.h"
+ #include "config.h"
  #include "clientsocket.h"
  #include "genstamp.h"
  #include "room_ops.h"
@@@ -737,7 -738,7 +738,7 @@@ int CtdlForEachMessage(int mode, long r
                                        free(msglist);
                                        return -1;
                                }
 -                              msg = CtdlFetchMessage(msglist[a], 1);
 +                              msg = CtdlFetchMessage(msglist[a], 1, 1);
                                if (msg != NULL) {
                                        if (CtdlMsgCmp(msg, compare)) {
                                                msglist[a] = 0L;
@@@ -1083,18 -1084,33 +1084,18 @@@ void mime_spew_section(char *name, cha
        }
  }
  
 -
 -/*
 - * Load a message from disk into memory.
 - * This is used by CtdlOutputMsg() and other fetch functions.
 - *
 - * NOTE: Caller is responsible for freeing the returned CtdlMessage struct
 - *       using the CtdlMessageFree() function.
 - */
 -struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body)
 +struct CtdlMessage *CtdlDeserializeMessage(long msgnum, int with_body, const char *Buffer, long Length)
  {
        struct CitContext *CCC = CC;
 -      struct cdbdata *dmsgtext;
        struct CtdlMessage *ret = NULL;
 -      char *mptr;
 -      char *upper_bound;
 +      const char *mptr;
 +      const char *upper_bound;
        cit_uint8_t ch;
        cit_uint8_t field_header;
        eMsgField which;
  
 -      MSG_syslog(LOG_DEBUG, "CtdlFetchMessage(%ld, %d)\n", msgnum, with_body);
 -      dmsgtext = cdb_fetch(CDB_MSGMAIN, &msgnum, sizeof(long));
 -      if (dmsgtext == NULL) {
 -              MSG_syslog(LOG_ERR, "CtdlFetchMessage(%ld, %d) Failed!\n", msgnum, with_body);
 -              return NULL;
 -      }
 -      mptr = dmsgtext->ptr;
 -      upper_bound = mptr + dmsgtext->len;
 +      mptr = Buffer;
 +      upper_bound = Buffer + Length;
  
        /* Parse the three bytes that begin EVERY message on disk.
         * The first is always 0xFF, the on-disk magic number.
        ch = *mptr++;
        if (ch != 255) {
                MSG_syslog(LOG_ERR, "Message %ld appears to be corrupted.\n", msgnum);
 -              cdb_free(dmsgtext);
                return NULL;
        }
        ret = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage));
        ret->cm_anon_type = *mptr++;    /* Anon type byte */
        ret->cm_format_type = *mptr++;  /* Format type byte */
  
 -
 -      if (dmsgtext->ptr[dmsgtext->len - 1] != '\0')
 -      {
 -              MSG_syslog(LOG_ERR, "CtdlFetchMessage(%ld, %d) Forcefully terminating message!!\n", msgnum, with_body);
 -              dmsgtext->ptr[dmsgtext->len - 1] = '\0';
 -      }
 -
        /*
         * The rest is zero or more arbitrary fields.  Load them in.
         * We're done when we encounter either a zero-length field or
  
        } while ((mptr < upper_bound) && (field_header != 'M'));
  
 +      return (ret);
 +}
 +
 +
 +/*
 + * Load a message from disk into memory.
 + * This is used by CtdlOutputMsg() and other fetch functions.
 + *
 + * NOTE: Caller is responsible for freeing the returned CtdlMessage struct
 + *       using the CtdlMessageFree() function.
 + */
 +struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body, int run_msg_hooks)
 +{
 +      struct CitContext *CCC = CC;
 +      struct cdbdata *dmsgtext;
 +      struct CtdlMessage *ret = NULL;
 +
 +      MSG_syslog(LOG_DEBUG, "CtdlFetchMessage(%ld, %d)\n", msgnum, with_body);
 +      dmsgtext = cdb_fetch(CDB_MSGMAIN, &msgnum, sizeof(long));
 +      if (dmsgtext == NULL) {
 +              MSG_syslog(LOG_ERR, "CtdlFetchMessage(%ld, %d) Failed!\n", msgnum, with_body);
 +              return NULL;
 +      }
 +
 +      if (dmsgtext->ptr[dmsgtext->len - 1] != '\0')
 +      {
 +              MSG_syslog(LOG_ERR, "CtdlFetchMessage(%ld, %d) Forcefully terminating message!!\n", msgnum, with_body);
 +              dmsgtext->ptr[dmsgtext->len - 1] = '\0';
 +      }
 +
 +      ret = CtdlDeserializeMessage(msgnum, with_body, dmsgtext->ptr, dmsgtext->len);
 +
        cdb_free(dmsgtext);
  
 +      if (ret == NULL) {
 +              return NULL;
 +      }
 +
        /* Always make sure there's something in the msg text field.  If
         * it's NULL, the message text is most likely stored separately,
         * so go ahead and fetch that.  Failing that, just set a dummy
        }
  
        /* Perform "before read" hooks (aborting if any return nonzero) */
 -      if (PerformMessageHooks(ret, NULL, EVT_BEFOREREAD) > 0) {
 +      if (run_msg_hooks && (PerformMessageHooks(ret, NULL, EVT_BEFOREREAD) > 0)) {
                CM_Free(ret);
                return NULL;
        }
@@@ -1597,10 -1585,10 +1598,10 @@@ int CtdlOutputMsg(long msg_num,              /* mes
         * request that we don't even bother loading the body into memory.
         */
        if (headers_only == HEADERS_FAST) {
 -              TheMessage = CtdlFetchMessage(msg_num, 0);
 +              TheMessage = CtdlFetchMessage(msg_num, 0, 1);
        }
        else {
 -              TheMessage = CtdlFetchMessage(msg_num, 1);
 +              TheMessage = CtdlFetchMessage(msg_num, 1, 1);
        }
  
        if (TheMessage == NULL) {
@@@ -1831,7 -1819,7 +1832,7 @@@ void OutputRFC822MsgHeaders
                                if (haschar(mptr, '@') == 0)
                                {
                                        sanitize_truncated_recipient(mptr);
-                                       cprintf("To: %s@%s", mptr, config.c_fqdn);
+                                       cprintf("To: %s@%s", mptr, CtdlGetConfigStr("c_fqdn"));
                                        cprintf("%s", nl);
                                }
                                else
@@@ -2179,7 -2167,7 +2180,7 @@@ int CtdlOutputPreLoadedMsg
        strcpy(suser, "");
        strcpy(luser, "");
        strcpy(fuser, "");
-       memcpy(snode, CFG_KEY(c_nodename) + 1);
+       memcpy(snode, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")) + 1);
        if (mode == MT_RFC822) 
                OutputRFC822MsgHeaders(
                        TheMessage,
@@@ -2438,7 -2426,7 +2439,7 @@@ int CtdlSaveMsgPointersInRoom(char *roo
                                msg = supplied_msg;
                        }
                        else {
 -                              msg = CtdlFetchMessage(msgid, 0);
 +                              msg = CtdlFetchMessage(msgid, 0, 1);
                        }
        
                        if (msg != NULL) {
@@@ -2504,101 -2492,75 +2505,101 @@@ int CtdlSaveMsgPointerInRoom(char *room
   * called by server-side modules.
   *
   */
 -long send_message(struct CtdlMessage *msg) {
 +long CtdlSaveThisMessage(struct CtdlMessage *msg, long msgid, int Reply) {
        struct CitContext *CCC = CC;
 -      long newmsgid;
        long retval;
 -      char msgidbuf[256];
 -      long msgidbuflen;
        struct ser_ret smr;
        int is_bigmsg = 0;
        char *holdM = NULL;
        long holdMLen = 0;
  
 -      /* Get a new message number */
 -      newmsgid = get_new_message_number();
 -      msgidbuflen = snprintf(msgidbuf, sizeof msgidbuf, "%08lX-%08lX@%s",
 -                             (long unsigned int) time(NULL),
 -                             (long unsigned int) newmsgid,
 -                             CtdlGetConfigStr("c_fqdn")
 -              );
 -
 -      /* Generate an ID if we don't have one already */
 -      if (CM_IsEmpty(msg, emessageId)) {
 -              CM_SetField(msg, emessageId, msgidbuf, msgidbuflen);
 -      }
 -
 -      /* If the message is big, set its body aside for storage elsewhere */
 -      if (!CM_IsEmpty(msg, eMesageText)) {
 -              if (msg->cm_lengths[eMesageText] > BIGMSG) {
 -                      is_bigmsg = 1;
 -                      holdM = msg->cm_fields[eMesageText];
 -                      msg->cm_fields[eMesageText] = NULL;
 -                      holdMLen = msg->cm_lengths[eMesageText];
 -                      msg->cm_lengths[eMesageText] = 0;
 -              }
 +      /*
 +       * If the message is big, set its body aside for storage elsewhere
 +       * and we hide the message body from the serializer
 +       */
 +      if (!CM_IsEmpty(msg, eMesageText) && msg->cm_lengths[eMesageText] > BIGMSG)
 +      {
 +              is_bigmsg = 1;
 +              holdM = msg->cm_fields[eMesageText];
 +              msg->cm_fields[eMesageText] = NULL;
 +              holdMLen = msg->cm_lengths[eMesageText];
 +              msg->cm_lengths[eMesageText] = 0;
        }
  
        /* Serialize our data structure for storage in the database */  
        CtdlSerializeMessage(&smr, msg);
  
        if (is_bigmsg) {
 +              /* put the message body back into the message */
                msg->cm_fields[eMesageText] = holdM;
                msg->cm_lengths[eMesageText] = holdMLen;
        }
  
        if (smr.len == 0) {
 -              cprintf("%d Unable to serialize message\n",
 -                      ERROR + INTERNAL_ERROR);
 +              if (Reply) {
 +                      cprintf("%d Unable to serialize message\n",
 +                              ERROR + INTERNAL_ERROR);
 +              }
 +              else {
 +                      MSGM_syslog(LOG_ERR, "CtdlSaveMessage() unable to serialize message");
 +
 +              }
                return (-1L);
        }
  
        /* Write our little bundle of joy into the message base */
 -      if (cdb_store(CDB_MSGMAIN, &newmsgid, (int)sizeof(long),
 -                    smr.ser, smr.len) < 0) {
 -              MSGM_syslog(LOG_ERR, "Can't store message\n");
 -              retval = 0L;
 -      } else {
 +      retval = cdb_store(CDB_MSGMAIN, &msgid, (int)sizeof(long),
 +                         smr.ser, smr.len);
 +      if (retval < 0) {
 +              MSG_syslog(LOG_ERR, "Can't store message %ld: %ld", msgid, retval);
 +      }
 +      else {
                if (is_bigmsg) {
 -                      cdb_store(CDB_BIGMSGS,
 -                                &newmsgid,
 -                                (int)sizeof(long),
 -                                holdM,
 -                                (holdMLen + 1)
 +                      retval = cdb_store(CDB_BIGMSGS,
 +                                         &msgid,
 +                                         (int)sizeof(long),
 +                                         holdM,
 +                                         (holdMLen + 1)
                                );
 +                      if (retval < 0) {
 +                              MSG_syslog(LOG_ERR, "failed to store message body for msgid %ld:  %ld",
 +                                         msgid, retval);
 +                      }
                }
 -              retval = newmsgid;
        }
  
        /* Free the memory we used for the serialized message */
        free(smr.ser);
  
-                                      config.c_fqdn
 +      return(retval);
 +}
 +
 +long send_message(struct CtdlMessage *msg) {
 +      long newmsgid;
 +      long retval;
 +      char msgidbuf[256];
 +      long msgidbuflen;
 +
 +      /* Get a new message number */
 +      newmsgid = get_new_message_number();
 +
 +      /* Generate an ID if we don't have one already */
 +      if (CM_IsEmpty(msg, emessageId)) {
 +              msgidbuflen = snprintf(msgidbuf, sizeof msgidbuf, "%08lX-%08lX@%s",
 +                                     (long unsigned int) time(NULL),
 +                                     (long unsigned int) newmsgid,
++                                     CtdlGetConfigStr("c_fqdn")
 +                      );
 +
 +              CM_SetField(msg, emessageId, msgidbuf, msgidbuflen);
 +      }
 +
 +      retval = CtdlSaveThisMessage(msg, newmsgid, 1);
 +
 +      if (retval == 0) {
 +              retval = newmsgid;
 +      }
 +
        /* Return the *local* message ID to the caller
         * (even if we're storing an incoming network message)
         */
   * serialized message in memory.  THE LATTER MUST BE FREED BY THE CALLER.
   */
  void CtdlSerializeMessage(struct ser_ret *ret,                /* return values */
 -                     struct CtdlMessage *msg) /* unserialized msg */
 +                        struct CtdlMessage *msg)      /* unserialized msg */
  {
        struct CitContext *CCC = CC;
        size_t wlen;
@@@ -2806,7 -2768,7 +2807,7 @@@ long CtdlSubmitMsg(struct CtdlMessage *
        if (TWITDETECT) {
                if (CCC->user.axlevel == AxProbU) {
                        strcpy(hold_rm, actual_rm);
-                       strcpy(actual_rm, config.c_twitroom);
+                       strcpy(actual_rm, CtdlGetConfigStr("c_twitroom"));
                        MSGM_syslog(LOG_DEBUG, "Diverting to twit room\n");
                }
        }
        if ((!CCC->internal_pgm) || (recps == NULL)) {
                if (CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 1, msg) != 0) {
                        MSGM_syslog(LOG_ERR, "ERROR saving message pointer!\n");
-                       CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg);
+                       CtdlSaveMsgPointerInRoom(CtdlGetConfigStr("c_aideroom"), newmsgid, 0, msg);
                }
        }
  
        {
                if (CCC->logged_in) 
                        snprintf(bounce_to, sizeof bounce_to, "%s@%s",
-                                CCC->user.fullname, config.c_nodename);
+                                CCC->user.fullname, CtdlGetConfigStr("c_nodename"));
                else 
                        snprintf(bounce_to, sizeof bounce_to, "%s@%s",
                                 msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]);
                        }
                        else {
                                MSG_syslog(LOG_DEBUG, "No user <%s>\n", recipient);
-                               CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg);
+                               CtdlSaveMsgPointerInRoom(CtdlGetConfigStr("c_aideroom"), newmsgid, 0, msg);
                        }
                }
                recps->recp_local = pch;
        }
        else {
                if (recps == NULL) {
-                       qualified_for_journaling = config.c_journal_pubmsgs;
+                       qualified_for_journaling = CtdlGetConfigInt("c_journal_pubmsgs");
                }
                else if (recps->num_local + recps->num_ignet + recps->num_internet > 0) {
-                       qualified_for_journaling = config.c_journal_email;
+                       qualified_for_journaling = CtdlGetConfigInt("c_journal_email");
                }
                else {
-                       qualified_for_journaling = config.c_journal_pubmsgs;
+                       qualified_for_journaling = CtdlGetConfigInt("c_journal_pubmsgs");
                }
        }
  
@@@ -3065,7 -3027,7 +3066,7 @@@ void quickie_message(const char *from
  
        if (fromaddr != NULL) CM_SetField(msg, erFc822Addr, fromaddr, strlen(fromaddr));
        if (room != NULL) CM_SetField(msg, eOriginalRoom, room, strlen(room));
-       CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
+       CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
        if (to != NULL) {
                CM_SetField(msg, eRecipient, to, strlen(to));
                recp = validate_recipients(to, NULL, 0);
@@@ -3538,8 -3500,8 +3539,8 @@@ struct CtdlMessage *CtdlMakeMessageLen
                CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname));
        }
  
-       CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
-       CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode));
+       CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
+       CM_SetField(msg, eHumanNode, CtdlGetConfigStr("c_humannode"), strlen(CtdlGetConfigStr("c_humannode")));
  
        if (rcplen > 0) {
                CM_SetField(msg, eRecipient, recipient, rcplen);
        }
        else {
                StrBuf *MsgBody;
-               MsgBody = CtdlReadMessageBodyBuf(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
+               MsgBody = CtdlReadMessageBodyBuf(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0, 0);
                if (MsgBody != NULL) {
                        CM_SetAsFieldSB(msg, eMesageText, &MsgBody);
                }
   * API function to delete messages which match a set of criteria
   * (returns the actual number of messages deleted)
   */
 -int CtdlDeleteMessages(char *room_name,               /* which room */
 +int CtdlDeleteMessages(const char *room_name,         /* which room */
                       long *dmsgnums,          /* array of msg numbers to be deleted */
                       int num_dmsgnums,        /* number of msgs to be deleted, or 0 for "any" */
                       char *content_type       /* or "" for any.  regular expressions expected. */
@@@ -4072,8 -4034,8 +4073,8 @@@ void CtdlWriteObject(char *req_room,                    
        msg->cm_format_type = 4;
        CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname));
        CM_SetField(msg, eOriginalRoom, req_room, strlen(req_room));
-       CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
-       CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode));
+       CM_SetField(msg, eNodeName, CtdlGetConfigStr("c_nodename"), strlen(CtdlGetConfigStr("c_nodename")));
+       CM_SetField(msg, eHumanNode, CtdlGetConfigStr("c_humannode"), strlen(CtdlGetConfigStr("c_humannode")));
        msg->cm_flags = flags;
        
        CM_SetAsFieldSB(msg, eMesageText, &encoded_message);
diff --combined citadel/room_ops.c
index c9bcd8000b4bb731c89e7e44830b1ed2ac1367a4,9979e03ea0658e486425b5c7cd2915702b16d217..3abaf307cf32a7c062104794d2f95ef8d20d7dcf
@@@ -1,7 -1,7 +1,7 @@@
  /* 
   * Server functions which perform operations on room objects.
   *
-  * Copyright (c) 1987-2012 by the citadel.org team
+  * Copyright (c) 1987-2015 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.
@@@ -32,7 -32,7 +32,7 @@@ struct floor *floorcache[MAXFLOORS]
  int CtdlDoIHavePermissionToReadMessagesInThisRoom(void) {
        if (    (!(CC->logged_in))
                && (!(CC->internal_pgm))
-               && (!config.c_guest_logins)
+               && (!CtdlGetConfigInt("c_guest_logins"))
        ) {
                return(om_not_logged_in);
        }
@@@ -139,7 -139,7 +139,7 @@@ void CtdlRoomAccess(struct ctdlroom *ro
                is_me = 1;
        }
  
-       if ((is_me) && (config.c_guest_logins) && (!CC->logged_in)) {
+       if ((is_me) && (CtdlGetConfigInt("c_guest_logins")) && (!CC->logged_in)) {
                is_guest = 1;
        }
  
        }
  
        /* Force the properties of the Aide room */
-       if (!strcasecmp(roombuf->QRname, config.c_aideroom)) {
+       if (!strcasecmp(roombuf->QRname, CtdlGetConfigStr("c_aideroom"))) {
                if (userbuf->axlevel >= AxAideU) {
                        retval = UA_KNOWN | UA_GOTOALLOWED | UA_POSTALLOWED | UA_DELETEALLOWED | UA_REPLYALLOWED;
                } else {
@@@ -339,9 -339,9 +339,9 @@@ void room_sanity_check(struct ctdlroom 
        /* Listing order of 0 is illegal except for base rooms */
        if (qrbuf->QRorder == 0)
                if (!(qrbuf->QRflags & QR_MAILBOX) &&
-                   strncasecmp(qrbuf->QRname, config.c_baseroom, ROOMNAMELEN)
+                   strncasecmp(qrbuf->QRname, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN)
                    &&
-                   strncasecmp(qrbuf->QRname, config.c_aideroom, ROOMNAMELEN))
+                   strncasecmp(qrbuf->QRname, CtdlGetConfigStr("c_aideroom"), ROOMNAMELEN))
                        qrbuf->QRorder = 64;
  }
  
@@@ -398,7 -398,7 +398,7 @@@ int CtdlGetRoom(struct ctdlroom *qrbuf
  /*
   * CtdlGetRoomLock()  -  same as getroom() but locks the record (if supported)
   */
 -int CtdlGetRoomLock(struct ctdlroom *qrbuf, char *room_name)
 +int CtdlGetRoomLock(struct ctdlroom *qrbuf, const char *room_name)
  {
        register int retval;
        retval = CtdlGetRoom(qrbuf, room_name);
@@@ -819,7 -819,7 +819,7 @@@ void CtdlUserGoto(char *where, int disp
        /* Know the room ... but not if it's the page log room, or if the
         * caller specified that we're only entering this room transiently.
         */
-       if ((strcasecmp(CCC->room.QRname, config.c_logpages))
+       if ((strcasecmp(CCC->room.QRname, CtdlGetConfigStr("c_logpages")))
           && (transiently == 0) ) {
                vbuf.v_flags = vbuf.v_flags & ~V_FORGET & ~V_LOCKOUT;
                vbuf.v_flags = vbuf.v_flags | V_ACCESS;
   */
  void convert_room_name_macros(char *towhere, size_t maxlen) {
        if (!strcasecmp(towhere, "_BASEROOM_")) {
-               safestrncpy(towhere, config.c_baseroom, maxlen);
+               safestrncpy(towhere, CtdlGetConfigStr("c_baseroom"), maxlen);
        }
        else if (!strcasecmp(towhere, "_MAIL_")) {
                safestrncpy(towhere, MAILROOM, maxlen);
                safestrncpy(towhere, USERDRAFTROOM, maxlen);
        }
        else if (!strcasecmp(towhere, "_BITBUCKET_")) {
-               safestrncpy(towhere, config.c_twitroom, maxlen);
+               safestrncpy(towhere, CtdlGetConfigStr("c_twitroom"), maxlen);
        }
        else if (!strcasecmp(towhere, "_CALENDAR_")) {
                safestrncpy(towhere, USERCALENDARROOM, maxlen);
@@@ -1039,8 -1039,8 +1039,8 @@@ int CtdlRenameRoom(char *old_name, cha
                }
  
                /* Reject change of floor for baseroom/aideroom */
-               if (!strncasecmp(old_name, config.c_baseroom, ROOMNAMELEN) ||
-                   !strncasecmp(old_name, config.c_aideroom, ROOMNAMELEN)) {
+               if (!strncasecmp(old_name, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN) ||
+                   !strncasecmp(old_name, CtdlGetConfigStr("c_aideroom"), ROOMNAMELEN)) {
                        new_floor = 0;
                }
  
                begin_critical_section(S_CONFIG);
        
                /* If baseroom/aideroom name changes, update config */
-               if (!strncasecmp(old_name, config.c_baseroom, ROOMNAMELEN)) {
-                       safestrncpy(config.c_baseroom, new_name, ROOMNAMELEN);
-                       put_config();
+               if (!strncasecmp(old_name, CtdlGetConfigStr("c_baseroom"), ROOMNAMELEN)) {
+                       CtdlSetConfigStr("c_baseroom", new_name);
                }
-               if (!strncasecmp(old_name, config.c_aideroom, ROOMNAMELEN)) {
-                       safestrncpy(config.c_aideroom, new_name, ROOMNAMELEN);
-                       put_config();
+               if (!strncasecmp(old_name, CtdlGetConfigStr("c_aideroom"), ROOMNAMELEN)) {
+                       CtdlSetConfigStr("c_aideroom", new_name);
                }
        
                end_critical_section(S_CONFIG);
diff --combined citadel/server_main.c
index 6a7d293fb8ef7cf6265fa3b4e4d044b1d117a339,a8e272978d4f2904fa8f4447513b0bbc0618cc69..a015876e5beedd803790e92aa0dda78093a5825d
  #include "user_ops.h"
  #include "ecrash.h"
  
+ uid_t ctdluid = 0;
  const char *CitadelServiceUDS="citadel-UDS";
  const char *CitadelServiceTCP="citadel-TCP";
 +
 +
 +
  void go_threading(void);
  
  /*
@@@ -51,6 -49,8 +52,8 @@@ int main(int argc, char **argv
        char ctdldir[PATH_MAX]=CTDLDIR;
        int syslog_facility = LOG_DAEMON;
        const char *eDebuglist[] = {NULL, NULL};
+       uid_t u = 0;
+       struct passwd *p = NULL;
  #ifdef HAVE_RUN_DIR
        struct stat filestats;
  #endif
@@@ -64,7 -64,7 +67,7 @@@
        InitializeMasterTSD();
  
        /* parse command-line arguments */
-       while ((a=getopt(argc, argv, "l:dh:x:t:B:Dr")) != EOF) switch(a) {
+       while ((a=getopt(argc, argv, "l:dh:x:t:B:Dru:")) != EOF) switch(a) {
  
                case 'l':
                        safestrncpy(facility, optarg, sizeof(facility));
                        drop_root_perms = 0;
                        break;
  
+               /* -u tells the server what uid to run under... */
+               case 'u':
+                       u = atoi(optarg);
+                       if (u > 0) {
+                               ctdluid = u;
+                       }
+                       else {
+                               p = getpwnam(optarg);
+                               if (p) {
+                                       u = p->pw_uid;
+                               }
+                       }
+                       if (u > 0) {
+                               ctdluid = u;
+                       }
+                       break;
                default:
                /* any other parameter makes it crash and burn */
                        fprintf(stderr, "citserver: usage: "
                                        "citserver "
                                        "[-l LogFacility] "
                                        "[-d] [-D] [-r] "
+                                       "[-u user] "
                                        "[-h HomeDir]\n"
                        );
                        exit(1);
        }
+       /* Last ditch effort to determine the user name ... if there's a user called "citadel" then use that */
+       if (ctdluid == 0) {
+               p = getpwnam("citadel");
+               if (!p) {
+                       p = getpwnam("bbs");
+               }
+               if (!p) {
+                       p = getpwnam("guest");
+               }
+               if (p) {
+                       u = p->pw_uid;
+               }
+               if (u > 0) {
+                       ctdluid = u;
+               }
+       }
+       if ((ctdluid == 0) && (drop_root_perms == 0)) {
+               fprintf(stderr, "citserver: cannot determine user to run as; please specify -r or -u options\n");
+               exit(CTDLEXIT_UNUSER);
+       }
        StartLibCitadel(basesize);
        openlog("citserver",
                ( running_as_daemon ? (LOG_PID) : (LOG_PID | LOG_PERROR) ),
        syslog(LOG_DEBUG, "Called as: %s", argv[0]);
        syslog(LOG_INFO, "%s", libcitadel_version_string());
  
-       /* Load site-specific configuration */
-       syslog(LOG_INFO, "Loading citadel.config");
-       get_config();
-       /* get_control() MUST MUST MUST be called BEFORE the databases are opened!! */
-       syslog(LOG_INFO, "Acquiring control record");
-       get_control();
-       put_config();
  #ifdef HAVE_RUN_DIR
        /* on some dists rundir gets purged on startup. so we need to recreate it. */
  
        if (stat(ctdl_run_dir, &filestats)==-1){
  #ifdef HAVE_GETPWUID_R
  #ifdef SOLARIS_GETPWUID
-               pwp = getpwuid_r(config.c_ctdluid, &pw, pwbuf, sizeof(pwbuf));
+               pwp = getpwuid_r(ctdluid, &pw, pwbuf, sizeof(pwbuf));
  #else // SOLARIS_GETPWUID
-               getpwuid_r(config.c_ctdluid, &pw, pwbuf, sizeof(pwbuf), &pwp);
+               getpwuid_r(ctdluid, &pw, pwbuf, sizeof(pwbuf), &pwp);
  #endif // SOLARIS_GETPWUID
  #else // HAVE_GETPWUID_R
                pwp = NULL;
                                      "unable to create run directory [%s]: %s", 
                                      ctdl_run_dir, strerror(errno));
  
-               if (chown(ctdl_run_dir, config.c_ctdluid, (pwp==NULL)?-1:pw.pw_gid) != 0)
+               if (chown(ctdl_run_dir, ctdluid, (pwp==NULL)?-1:pw.pw_gid) != 0)
                        syslog(LOG_EMERG, 
                                      "unable to set the access rights for [%s]: %s", 
                                      ctdl_run_dir, strerror(errno));
        /*
         * Bind the server to our favorite TCP port (usually 504).
         */
-       CtdlRegisterServiceHook(config.c_port_number,
+       CtdlRegisterServiceHook(CtdlGetConfigInt("c_port_number"),
                                NULL,
                                citproto_begin_session,
                                do_command_loop,
        /*
         * If we need host auth, start our chkpwd daemon.
         */
-       if (config.c_auth_mode == AUTHMODE_HOST) {
+       if (CtdlGetConfigInt("c_auth_mode") == AUTHMODE_HOST) {
                start_chkpwd_daemon();
        }
  
  
  #ifdef HAVE_GETPWUID_R
  #ifdef SOLARIS_GETPWUID
-               pwp = getpwuid_r(config.c_ctdluid, &pw, pwbuf, sizeof(pwbuf));
+               pwp = getpwuid_r(ctdluid, &pw, pwbuf, sizeof(pwbuf));
  #else // SOLARIS_GETPWUID
-               getpwuid_r(config.c_ctdluid, &pw, pwbuf, sizeof(pwbuf), &pwp);
+               getpwuid_r(ctdluid, &pw, pwbuf, sizeof(pwbuf), &pwp);
  #endif // SOLARIS_GETPWUID
  #else // HAVE_GETPWUID_R
                pwp = NULL;