X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fcontrol.c;h=ec3179f8c37288f9df580283fc0a382320d1735a;hb=36908e5d8ca8ad1207d7f8466c0858c71c9588b4;hp=8e0b487265003d7db54c9d884a850ef40843444f;hpb=769dfac89d383517c1cb40de963ee3253f2340e8;p=citadel.git diff --git a/citadel/control.c b/citadel/control.c index 8e0b48726..ec3179f8c 100644 --- a/citadel/control.c +++ b/citadel/control.c @@ -1,7 +1,7 @@ /* * This module handles states which are global to the entire server. * - * Copyright (c) 1987-2016 by the citadel.org team + * Copyright (c) 1987-2021 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. @@ -40,88 +40,88 @@ struct legacy_ctrl_format { }; +/* + * data that gets passed back and forth between control_find_highest() and its caller + */ +struct cfh { + long highest_roomnum_found; + long highest_msgnum_found; +}; + + /* * Callback to get highest room number when rebuilding message base metadata + * + * sanity_diag_mode (can be set by -s flag at startup) may be: + * 0 = attempt to fix inconsistencies + * 1 = show inconsistencies but don't repair them, exit after complete + * 2 = show inconsistencies but don't repair them, continue execution */ -void control_find_highest(struct ctdlroom *qrbuf, void *data) -{ - struct ctdlroom room; +void control_find_highest(struct ctdlroom *qrbuf, void *data) { + struct cfh *cfh = (struct cfh *)data; struct cdbdata *cdbfr; long *msglist; int num_msgs=0; int c; - int room_fixed = 0; - int message_fixed = 0; - - if (qrbuf->QRnumber > CtdlGetConfigLong("MMnextroom")) - { - CtdlSetConfigLong("MMnextroom", qrbuf->QRnumber); - room_fixed = 1; + + if (qrbuf->QRnumber > cfh->highest_roomnum_found) { + cfh->highest_roomnum_found = qrbuf->QRnumber; } - - CtdlGetRoom (&room, qrbuf->QRname); - + /* Load the message list */ - cdbfr = cdb_fetch(CDB_MSGLISTS, &room.QRnumber, sizeof(long)); + cdbfr = cdb_fetch(CDB_MSGLISTS, &qrbuf->QRnumber, sizeof(long)); if (cdbfr != NULL) { msglist = (long *) cdbfr->ptr; num_msgs = cdbfr->len / sizeof(long); - } else { + } + else { return; /* No messages at all? No further action. */ } - if (num_msgs>0) - { - for (c=0; c CtdlGetConfigLong("MMhighest")) - { - CtdlSetConfigLong("MMhighest", msglist[c]); - message_fixed = 1; + if (num_msgs > 0) { + for (c=0; c cfh->highest_msgnum_found) { + cfh->highest_msgnum_found = msglist[c]; } } } + cdb_free(cdbfr); - if (room_fixed) { - syslog(LOG_INFO, "Control record checking....Fixed room counter\n"); - } - if (message_fixed) { - syslog(LOG_INFO, "Control record checking....Fixed message count\n"); - } - return; } /* * Callback to get highest user number. */ - -void control_find_user (struct ctdluser *EachUser, void *out_data) -{ - int user_fixed = 0; - - if (EachUser->usernum > CtdlGetConfigLong("MMnextuser")) - { - CtdlSetConfigLong("MMnextuser", EachUser->usernum); - user_fixed = 1; +void control_find_user(char *username, void *out_data) { + struct ctdluser EachUser; + + if (CtdlGetUser(&EachUser, username) != 0) { + return; + } + + if (EachUser.usernum > CtdlGetConfigLong("MMnextuser")) { + syslog(LOG_DEBUG, "control: fixing MMnextuser %ld > %ld , found in %s", + EachUser.usernum, CtdlGetConfigLong("MMnextuser"), EachUser.fullname + ); + if (!sanity_diag_mode) { + CtdlSetConfigLong("MMnextuser", EachUser.usernum); + } } - if(user_fixed) - syslog(LOG_INFO, "Control record checking....Fixed user count\n"); } /* * If we have a legacy format control record on disk, import it. */ -void migrate_legacy_control_record(void) -{ +void migrate_legacy_control_record(void) { FILE *fp = NULL; struct legacy_ctrl_format c; memset(&c, 0, sizeof(c)); - fp = fopen(file_citadel_control, "rb+"); + fp = fopen("citadel.control", "rb+"); if (fp != NULL) { - syslog(LOG_INFO, "Legacy format control record found -- importing to db"); + syslog(LOG_INFO, "control: legacy format record found -- importing to db"); fread(&c, sizeof(struct legacy_ctrl_format), 1, fp); CtdlSetConfigLong( "MMhighest", c.MMhighest); @@ -133,8 +133,8 @@ void migrate_legacy_control_record(void) 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); + if (unlink("citadel.control") != 0) { + fprintf(stderr, "Unable to remove legacy control record after migrating it.\n"); fprintf(stderr, "Exiting to prevent data corruption.\n"); exit(CTDLEXIT_CONFIG); } @@ -145,11 +145,36 @@ void migrate_legacy_control_record(void) /* * check_control - check the control record has sensible values for message, user and room numbers */ -void check_control(void) -{ - syslog(LOG_INFO, "Sanity checking the recorded highest message, user, and room numbers\n"); - CtdlForEachRoom(control_find_highest, NULL); +void check_control(void) { + + syslog(LOG_INFO, "control: sanity checking the recorded highest message and room numbers"); + struct cfh cfh; + memset(&cfh, 0, sizeof(struct cfh)); + CtdlForEachRoom(control_find_highest, &cfh); + + if (cfh.highest_roomnum_found > CtdlGetConfigLong("MMnextroom")) { + syslog(LOG_DEBUG, "control: fixing MMnextroom %ld > %ld", cfh.highest_roomnum_found, CtdlGetConfigLong("MMnextroom")); + if (!sanity_diag_mode) { + CtdlSetConfigLong("MMnextroom", cfh.highest_roomnum_found); + } + } + + if (cfh.highest_msgnum_found > CtdlGetConfigLong("MMhighest")) { + syslog(LOG_DEBUG, "control: fixing MMhighest %ld > %ld", cfh.highest_msgnum_found, CtdlGetConfigLong("MMhighest")); + if (!sanity_diag_mode) { + CtdlSetConfigLong("MMhighest", cfh.highest_msgnum_found); + } + } + + syslog(LOG_INFO, "control: sanity checking the recorded highest user number"); ForEachUser(control_find_user, NULL); + + syslog(LOG_INFO, "control: sanity checks complete"); + + if (sanity_diag_mode == 1) { + syslog(LOG_INFO, "control: sanity check diagnostic mode is active - exiting now"); + abort(); + } } @@ -171,7 +196,7 @@ long get_new_message_number(void) /* * CtdlGetCurrentMessageNumber() - Obtain the current highest message number in the system * This provides a quick way to initialise a variable that might be used to indicate - * messages that should not be processed. EG. a new Sieve script will use this + * messages that should not be processed. For example, an inbox rules 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?) @@ -225,10 +250,6 @@ int confbool(char *v) /* * Get or set global configuration options - * - * IF YOU ADD OR CHANGE FIELDS HERE, YOU *MUST* DOCUMENT YOUR CHANGES AT: - * http://www.citadel.org/doku.php/documentation:appproto:system_config - * */ void cmd_conf(char *argbuf) { @@ -306,15 +327,15 @@ void cmd_conf(char *argbuf) 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("0\n"); 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("\n"); + cprintf("\n"); + cprintf("\n"); + cprintf("\n"); cprintf("%d\n", CtdlGetConfigInt("c_rbl_at_greeting")); - cprintf("%s\n", CtdlGetConfigStr("c_master_user")); - cprintf("%s\n", CtdlGetConfigStr("c_master_pass")); + cprintf("\n"); + cprintf("\n"); cprintf("%s\n", CtdlGetConfigStr("c_pager_program")); cprintf("%d\n", CtdlGetConfigInt("c_imap_keep_from")); cprintf("%d\n", CtdlGetConfigInt("c_xmpp_c2s_port")); @@ -512,31 +533,31 @@ void cmd_conf(char *argbuf) CtdlSetConfigInt("c_pftcpdict_port", atoi(buf)); break; case 51: - CtdlSetConfigInt("c_managesieve_port", atoi(buf)); + /* niu */ break; case 52: CtdlSetConfigInt("c_auth_mode", atoi(buf)); break; case 53: - CtdlSetConfigStr("c_funambol_host", buf); + /* niu */ break; case 54: - CtdlSetConfigInt("c_funambol_port", atoi(buf)); + /* niu */ break; case 55: - CtdlSetConfigStr("c_funambol_source", buf); + /* niu */ break; case 56: - CtdlSetConfigStr("c_funambol_auth", buf); + /* niu */ break; case 57: CtdlSetConfigInt("c_rbl_at_greeting", confbool(buf)); break; case 58: - CtdlSetConfigStr("c_master_user", buf); + /* niu */ break; case 59: - CtdlSetConfigStr("c_master_pass", buf); + /* niu */ break; case 60: CtdlSetConfigStr("c_pager_program", buf); @@ -619,24 +640,29 @@ void cmd_conf(char *argbuf) extract_token(confname, argbuf, 1, '|', sizeof confname); unbuffer_output(); cprintf("%d %s\n", SEND_LISTING, confname); - confptr = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0, 0); + confptr = CtdlReadMessageBody(HKEY("000"), CtdlGetConfigLong("c_maxmsglen"), NULL, 0); CtdlPutSysConfig(confname, confptr); free(confptr); } // CONF GETVAL - retrieve configuration variables from the database - else if (!strcasecmp(cmd, "GETVAL")) { + // CONF LOADVAL - same thing but can handle variables bigger than 1 KB + else if ( (!strcasecmp(cmd, "GETVAL")) || (!strcasecmp(cmd, "LOADVAL")) ) { extract_token(confname, argbuf, 1, '|', sizeof confname); char *v = CtdlGetConfigStr(confname); - if (v) { + if ( (v) && (!strcasecmp(cmd, "GETVAL")) ) { cprintf("%d %s|\n", CIT_OK, v); } + else if ( (v) && (!strcasecmp(cmd, "LOADVAL")) ) { + cprintf("%d %d\n", BINARY_FOLLOWS, (int)strlen(v)); + client_write(v, strlen(v)); + } else { cprintf("%d |\n", ERROR); } } - // CONF PUTVAL - store configuration variables from the database + // CONF PUTVAL - store configuration variables in the database else if (!strcasecmp(cmd, "PUTVAL")) { if (num_tokens(argbuf, '|') < 3) { cprintf("%d name and value required\n", ERROR); @@ -649,6 +675,23 @@ void cmd_conf(char *argbuf) } } + // CONF STOREVAL - store configuration variables in the database bigger than 1 KB + else if (!strcasecmp(cmd, "STOREVAL")) { + if (num_tokens(argbuf, '|') < 3) { + cprintf("%d name and length required\n", ERROR); + } + else { + extract_token(confname, argbuf, 1, '|', sizeof confname); + int bytes = extract_int(argbuf, 2); + char *valbuf = malloc(bytes + 1); + cprintf("%d %d\n", SEND_BINARY, bytes); + client_read(valbuf, bytes); + valbuf[bytes+1] = 0; + CtdlSetConfigStr(confname, valbuf); + free(valbuf); + } + } + // CONF LISTVAL - list configuration variables in the database and their values else if (!strcasecmp(cmd, "LISTVAL")) { struct cdbdata *cdbcfg; @@ -659,10 +702,12 @@ void cmd_conf(char *argbuf) cprintf("%d all configuration variables\n", LISTING_FOLLOWS); 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; - cprintf("%s|%s\n", key, value); + if (cdbcfg->len < 1020) { + keylen = strlen(cdbcfg->ptr); + key = cdbcfg->ptr; + value = cdbcfg->ptr + keylen + 1; + cprintf("%s|%s\n", key, value); + } cdb_free(cdbcfg); } cprintf("000\n"); @@ -761,10 +806,6 @@ void cmd_gvdn(char *argbuf) /* MODULE INITIALIZATION STUFF */ /*****************************************************************************/ -void control_cleanup(void) -{ - DeleteHash(&CfgNameHash); -} CTDL_MODULE_INIT(control) { if (!threading) { @@ -776,8 +817,6 @@ CTDL_MODULE_INIT(control) CtdlRegisterProtoHook(cmd_gvdn, "GVDN", "get valid domain names"); CtdlRegisterProtoHook(cmd_conf, "CONF", "get/set system configuration"); - CtdlRegisterCleanupHook(control_cleanup); - } /* return our id for the Log */ return "control";