int do_check_replycache(const char *timespec)
{
	u64_t log_count;
	timestring_t timestring;

	if (find_time(timespec, &timestring) != 0) {
		qerrorf("\nFailed to find a timestring: [%s] is not <hours>h<minutes>m.\n",
		       timespec);
		serious_errors = 1;
		return -1;
	}

	if (no_to_all) {
		qprintf("\nCounting RC entries older than [%s]...\n", timestring);
		if (db_count_replycache(timestring, &log_count) < 0) {
			qerrorf("Failed. An error occured. Check the log.\n");
			serious_errors = 1;
			return -1;
		}
		qprintf("Ok. [%llu] RC entries are older than [%s].\n",
		    log_count, timestring);
	}
	if (yes_to_all) {
		qprintf("\nRemoving RC entries older than [%s]...\n", timestring);
		if (! db_cleanup_replycache(timestring)) {
			qerrorf("Failed. Please check the log.\n");
			serious_errors = 1;
			return -1;
		}

		qprintf("Ok. RC entries were older than [%s] cleaned.\n", timestring);
	}
	return 0;
}
int do_set_deleted(void)
{
	u64_t messages_set_to_delete;

	if (no_to_all) {
		// TODO: Count messages to delete.
		qprintf("\nCounting deleted messages that need the DELETE status set...\n");
		if (! db_count_deleted(&messages_set_to_delete)) {
			qerrorf ("Failed. An error occured. Please check log.\n");
			serious_errors = 1;
			return -1;
		}
		qprintf("Ok. [%llu] messages need to be set for deletion.\n", messages_set_to_delete);
	}
	if (yes_to_all) {
		qprintf("\nSetting DELETE status for deleted messages...\n");
		if (! db_set_deleted()) {
			qerrorf ("Failed. An error occured. Please check log.\n");
			serious_errors = 1;
			return -1;
		}
		qprintf("Ok. Messages set for deletion.\n");
		qprintf("Re-calculating used quota for all users...\n");
		if (dm_quota_rebuild() < 0) {
			qerrorf ("Failed. An error occured. Please check log.\n");
			serious_errors = 1;
			return -1;
		}
		qprintf("Ok. Used quota updated for all users.\n");
	}
	return 0;
}
Exemple #3
0
int do_check_iplog(const char *timespec)
{
	uint64_t log_count;
	TimeString_T timestring;

	if (find_time(timespec, &timestring) != 0) {
		qerrorf("\nFailed to find a timestring: [%s] is not <hours>h<minutes>m.\n",
		       timespec);
		serious_errors = 1;
		return -1;
	}

	if (no_to_all) {
		qprintf("\nCounting IP entries older than [%s]...\n", timestring);
		if (db_count_iplog(timestring, &log_count) < 0) {
			qerrorf("Failed. An error occured. Check the log.\n");
			serious_errors = 1;
			return -1;
		}
		qprintf("Ok. [%" PRIu64 "] IP entries are older than [%s].\n",
		    log_count, timestring);
	}
	if (yes_to_all) {
		qprintf("\nRemoving IP entries older than [%s]...\n", timestring);
		if (! db_cleanup_iplog(timestring)) {
			qerrorf("Failed. Please check the log.\n");
			serious_errors = 1;
			return -1;
		}

		qprintf("Ok. IP entries older than [%s] removed.\n",
		       timestring);
	}
	return 0;
}
int do_dangling_aliases(void)
{
	int count = 0;
	int result = 0;
	GList *aliases = NULL;

	if (no_to_all)
		qprintf("\nCounting aliases with nonexistent delivery userid's...\n");
	if (yes_to_all)
		qprintf("\nRemoving aliases with nonexistent delivery userid's...\n");

	aliases = auth_get_known_aliases();
	aliases = g_list_dedup(aliases, (GCompareFunc)strcmp, TRUE);
	aliases = g_list_first(aliases);
	while (aliases) {
		char deliver_to[21];
		GList *dangling = find_dangling_aliases(aliases->data);

		dangling = g_list_first(dangling);
		while (dangling) {
			count++;
			g_snprintf(deliver_to, 21, "%llu", *(u64_t *)dangling->data);
			qverbosef("Dangling alias [%s] delivers to nonexistent user [%s]\n",
				(char *)aliases->data, deliver_to);
			if (yes_to_all) {
				if (auth_removealias_ext(aliases->data, deliver_to) < 0) {
					qerrorf("Error: could not remove alias [%s] deliver to [%s] \n",
						(char *)aliases->data, deliver_to);
					serious_errors = 1;
					result = -1;
				}
			}
			if (!g_list_next(dangling))
				break;
			dangling = g_list_next(dangling);
		}
		g_list_destroy(g_list_first(dangling));

		if (! g_list_next(aliases))
			break;
		aliases = g_list_next(aliases);
	}
	g_list_destroy(g_list_first(aliases));

	if (count > 0) {
		qerrorf("Ok. Found [%d] dangling aliases.\n", count);
		has_errors = 1;
	} else {
		qprintf("Ok. Found [%d] dangling aliases.\n", count);
	}

	return result;
}
int do_header_cache(void)
{
	time_t start, stop;
	GList *lost = NULL;
	
	if (do_rfc_size()) {
		serious_errors = 1;
		return -1;
	}
	if (do_envelope()) {
		serious_errors = 1;
		return -1;
	}
	
	if (no_to_all) 
		qprintf("\nChecking DBMAIL for cached header values...\n");
	if (yes_to_all) 
		qprintf("\nRepairing DBMAIL for cached header values...\n");
	
	time(&start);

	if (db_icheck_headercache(&lost) < 0) {
		qerrorf("Failed. An error occured. Please check log.\n");
		serious_errors = 1;
		return -1;
	}

	if (g_list_length(lost) > 0) {
		qerrorf("Ok. Found [%d] un-cached physmessages.\n", g_list_length(lost));
		has_errors = 1;
	} else {
		qprintf("Ok. Found [%d] un-cached physmessages.\n", g_list_length(lost));
	}

	if (yes_to_all) {
		if (db_set_headercache(lost) < 0) {
			qerrorf("Error caching the header values ");
			serious_errors = 1;
		}
	}

	g_list_free(lost);

	time(&stop);
	qverbosef("--- checking cached headervalues took %g seconds\n",
	       difftime(stop, start));

	return 0;
}
GList *find_dangling_aliases(const char * const name)
{
	int result;
	char *username;
	GList *uids = NULL;
	GList *fwds = NULL;
	GList *dangling = NULL;

	/* For each alias, figure out if it resolves to a valid user
	 * or some forwarding address. If neither, remove it. */

	result = auth_check_user_ext(name,&uids,&fwds,0);
	
	if (!result) {
		qerrorf("Nothing found searching for [%s].\n", name);
		serious_errors = 1;
		return dangling;
	}

	uids = g_list_first(uids);
	while (uids) {
		username = auth_get_userid(*(u64_t *)uids->data);
		if (!username)
			dangling = g_list_prepend(dangling, uids->data);

		g_free(username);
		if (! g_list_next(uids))
			break;
		uids = g_list_next(uids);
	}

	return dangling;
}
static int do_envelope(void)
{
	time_t start, stop;
	GList *lost = NULL;

	if (no_to_all) {
		qprintf("\nChecking DBMAIL for cached envelopes...\n");
	}
	if (yes_to_all) {
		qprintf("\nRepairing DBMAIL for cached envelopes...\n");
	}
	time(&start);

	if (db_icheck_envelope(&lost) < 0) {
		qerrorf("Failed. An error occured. Please check log.\n");
		serious_errors = 1;
		return -1;
	}

	if (g_list_length(lost) > 0) {
		qerrorf("Ok. Found [%d] missing envelope values.\n", g_list_length(lost));
		has_errors = 1;
	} else {
		qprintf("Ok. Found [%d] missing envelope values.\n", g_list_length(lost));
	}

	if (yes_to_all) {
		if (db_set_envelope(lost) < 0) {
			qerrorf("Error setting the envelope cache");
			has_errors = 1;
		}
	}

	g_list_free(g_list_first(lost));

	time(&stop);
	qverbosef("--- checking envelope cache took %g seconds\n",
	       difftime(stop, start));
	
	return 0;

}
static int do_rfc_size(void)
{
	time_t start, stop;
	GList *lost = NULL;

	if (no_to_all) {
		qprintf("\nChecking DBMAIL for rfcsize field...\n");
	}
	if (yes_to_all) {
		qprintf("\nRepairing DBMAIL for rfcsize field...\n");
	}
	time(&start);

	if (db_icheck_rfcsize(&lost) < 0) {
		qerrorf("Failed. An error occured. Please check log.\n");
		serious_errors = 1;
		return -1;
	}

	if (g_list_length(lost) > 0) {
		qerrorf("Ok. Found [%d] missing rfcsize values.\n", g_list_length(lost));
		has_errors = 1;
	} else {
		qprintf("Ok. Found [%d] missing rfcsize values.\n", g_list_length(lost));
	}

	if (yes_to_all) {
		if (db_update_rfcsize(lost) < 0) {
			qerrorf("Error setting the rfcsize values");
			has_errors = 1;
		}
	}

	g_list_destroy(lost);

	time(&stop);
	qverbosef("--- checking rfcsize field took %g seconds\n",
	       difftime(stop, start));
	
	return 0;

}
int do_purge_deleted(void)
{
	u64_t deleted_messages;

	if (no_to_all) {
		qprintf("\nCounting messages with DELETE status...\n");
		if (! db_deleted_count(&deleted_messages)) {
			qerrorf ("Failed. An error occured. Please check log.\n");
			serious_errors = 1;
			return -1;
		}
		qprintf("Ok. [%llu] messages have DELETE status.\n", deleted_messages);
	}
	if (yes_to_all) {
		qprintf("\nDeleting messages with DELETE status...\n");
		if (! db_deleted_purge()) {
			qerrorf ("Failed. An error occured. Please check log.\n");
			serious_errors = 1;
			return -1;
		}
		qprintf("Ok. Messages deleted.\n");
	}
	return 0;
}
int do_rehash(void)
{
	if (yes_to_all) {
		qprintf ("Rebuild hash keys for stored message chunks...\n");
		if (db_rehash_store() == DM_EQUERY) {
			qerrorf("Failed. Please check the log.\n");
			serious_errors = 1;
			return -1;
		}
		qprintf ("Ok. Hash keys rebuild successfully.\n");
	}

	return 0;

}
int do_vacuum_db(void)
{
	if (no_to_all) {
		qprintf("\nVacuum and optimize not performed.\n");
	}
	if (yes_to_all) {
		qprintf("\nVacuuming and optimizing database...\n");
		fflush(stdout);
		if (db_cleanup() < 0) {
			qerrorf("Failed. Please check the log.\n");
			serious_errors = 1;
			return -1;
		}

		qprintf("Ok. Database cleaned up.\n");
	}
	return 0;
}
int do_check_integrity(void)
{
	time_t start, stop;
	GList *lost = NULL;
	const char *action;
	gboolean cleanup;
	long count = 0;

	if (yes_to_all) {
		action = "Repairing";
		cleanup = TRUE;
	} else {
		action = "Checking";
		cleanup = FALSE;
	}

	qprintf("\n%s DBMAIL message integrity...\n", action);

	/* This is what we do:
	 3. Check for loose physmessages
	 4. Check for loose partlists
	 5. Check for loose mimeparts
	 */

	/* part 3 */
	start = stop;
	qprintf("\n%s DBMAIL physmessage integrity...\n", action);
	if ((count = db_icheck_physmessages(cleanup)) < 0) {
		qerrorf("Failed. An error occurred. Please check log.\n");
		serious_errors = 1;
		return -1;
	}
	if (count > 0) {
		qerrorf("Ok. Found [%ld] unconnected physmessages.\n", count);
		if (cleanup) {
			qerrorf("Ok. Orphaned physmessages deleted.\n");
		}
	} else {
		qprintf("Ok. Found [%ld] unconnected physmessages.\n", count);
	}

	time(&stop);
	qverbosef("--- %s unconnected physmessages took %g seconds\n",
		action, difftime(stop, start));
	/* end part 3 */

	/* part 4 */
	start = stop;
	qprintf("\n%s DBMAIL partlists integrity...\n", action);
	if ((count = db_icheck_partlists(cleanup)) < 0) {
		qerrorf("Failed. An error occurred. Please check log.\n");
		serious_errors = 1;
		return -1;
	}
	if (count > 0) {
		qerrorf("Ok. Found [%ld] unconnected partlists.\n", count);
		if (cleanup) {
			qerrorf("Ok. Orphaned partlists deleted.\n");
		}
	} else {
		qprintf("Ok. Found [%ld] unconnected partlists.\n", count);
	}

	time(&stop);
	qverbosef("--- %s unconnected partlists took %g seconds\n",
		action, difftime(stop, start));
	/* end part 4 */

	/*  part 5 */
	start = stop;
	qprintf("\n%s DBMAIL mimeparts integrity...\n", action);
	if ((count = db_icheck_mimeparts(cleanup)) < 0) {
		qerrorf("Failed. An error occurred. Please check log.\n");
		serious_errors = 1;
		return -1;
	}
	if (count > 0) {
		qerrorf("Ok. Found [%ld] unconnected mimeparts.\n", count);
		if (cleanup) {
			qerrorf("Ok. Orphaned mimeparts deleted.\n");
		}
	} else {
		qprintf("Ok. Found [%ld] unconnected mimeparts.\n", count);
	}

	time(&stop);
	qverbosef("--- %s unconnected mimeparts took %g seconds\n",
		action, difftime(stop, start));
	/* end part 5 */

	g_list_destroy(lost);
	lost = NULL;

	time(&stop);
	qverbosef("--- %s block integrity took %g seconds\n", action, difftime(stop, start));
	/* end part 6 */

	return 0;
}
Exemple #13
0
static int mailbox_dump(u64_t mailbox_idnr, const char *dumpfile,
		const char *search, int delete_after_dump)
{
	FILE *ostream;
	DbmailMailbox *mb = NULL;
	ImapSession *s = NULL;
	int result = 0;

	/* 
	 * For dbmail the usual filesystem semantics don't really 
	 * apply. Mailboxes can contain other mailboxes as well as
	 * messages. For now however, this is solved by appending
	 * the mailboxname with .mbox
	 *
	 * TODO: facilitate maildir type exports
	 */
	mb = dbmail_mailbox_new(mailbox_idnr);
	if (search) {
		s = dbmail_imap_session_new();
		s->ci = client_init(NULL);
		if (! (imap4_tokenizer_main(s, search))) {
			qerrorf("error parsing search string");
			dbmail_imap_session_delete(&s);
			dbmail_mailbox_free(mb);
			return 1;
		}
	
		if (dbmail_mailbox_build_imap_search(mb, s->args, &(s->args_idx), SEARCH_UNORDERED) < 0) {
			qerrorf("invalid search string");
			dbmail_imap_session_delete(&s);
			dbmail_mailbox_free(mb);
			return 1;
		}
		dbmail_mailbox_search(mb);
		dbmail_imap_session_delete(&s);	
	}

	if (strcmp(dumpfile, "-") == 0) {
		ostream = stdout;
	} else if (! (ostream = fopen(dumpfile, "a"))) {
		int err = errno;
		qerrorf("opening [%s] failed [%s]\n", dumpfile, strerror(err));
		result = -1;
		goto cleanup;
	}

	if (dbmail_mailbox_dump(mb, ostream) < 0) {
		qerrorf("Export failed\n");
		result = -1;
		goto cleanup;
	}

	if (delete_after_dump) {
		int deleted_flag[IMAP_NFLAGS];
		memset(deleted_flag, 0, IMAP_NFLAGS * sizeof(int));
		deleted_flag[IMAP_FLAG_DELETED] = 1;

		GList *ids = g_tree_keys(MailboxState_getIds(mb->mbstate));

                while (ids) {
			// Flag the selected messages \\Deleted
			// Following this, dbmail-util -d sets deleted status
			if (delete_after_dump & 1) {
				if (db_set_msgflag(*(u64_t *)ids->data, deleted_flag, NULL, IMAPFA_ADD, NULL) < 0) {
					qerrorf("Error setting flags for message [%llu]\n", *(u64_t *)ids->data);
					result = -1;
				}
			}

			// Set deleted status on each message
			// Following this, dbmail-util -p sets purge status
			if (delete_after_dump & 2) {
				if (! db_set_message_status(*(u64_t *)ids->data, MESSAGE_STATUS_DELETE)) {
					qerrorf("Error setting status for message [%llu]\n", *(u64_t *)ids->data);
					result = -1;
				}
			}

			if (!g_list_next(ids))
				break;
			ids = g_list_next(ids);
		}

		g_list_free(g_list_first(ids));
	}

cleanup:
	if (mb)
		dbmail_mailbox_free(mb);
	if ((ostream) && (ostream != stdout))
		fclose(ostream);

	return result;
}
Exemple #14
0
int main(int argc, char *argv[])
{
	int opt = 0, opt_prev = 0;
	int show_help = 0;
	int result = 0, delete_after_dump = 0, recursive = 0;
	char *user=NULL, *mailbox=NULL, *outfile=NULL, *basedir=NULL, *search=NULL;

	openlog(PNAME, LOG_PID, LOG_MAIL);
	setvbuf(stdout, 0, _IONBF, 0);

	g_mime_init(0);

	/* get options */
	opterr = 0;		/* suppress error message from getopt() */
	while ((opt = getopt(argc, argv,
		"-u:m:o:b:s:dDr" /* Major modes */
		"f:qvVh" /* Common options */ )) != -1) {
		/* The initial "-" of optstring allows unaccompanied
		 * options and reports them as the optarg to opt 1 (not '1') */
		if (opt == 1)
			opt = opt_prev;
		opt_prev = opt;

		switch (opt) {
		/* export specific options */
		case 'u':
			if (optarg && strlen(optarg))
				user = optarg;
			break;

		case 'm':
			if (optarg && strlen(optarg))
				mailbox = optarg;
			break;
		case 'b':
			if (optarg && strlen(optarg))
				basedir = optarg;
			break;
		case 'o':
			if (optarg && strlen(optarg))
				outfile = optarg;
			break;
		case 'd':
			delete_after_dump |= 1;
			break;
		case 'D':
			delete_after_dump |= 2;
			break;
		case 'r':
			recursive = 1;
			break;
		case 's':
			if (optarg && strlen(optarg))
				search = optarg;
			else {
				qerrorf("dbmail-mailbox: -s requires a value\n\n");
				result = 1;
			}
			break;

		/* Common options */
		case 'f':
			if (optarg && strlen(optarg) > 0)
				configFile = optarg;
			else {
				qerrorf("dbmail-mailbox: -f requires a filename\n\n");
				result = 1;
			}
			break;

		case 'h':
			show_help = 1;
			break;

		case 'q':
			/* If we get q twice, be really quiet! */
			if (quiet)
				reallyquiet = 1;
			if (!verbose)
				quiet = 1;
			break;

		case 'v':
			if (!quiet)
				verbose = 1;
			break;

		case 'V':
			/* Show the version and return non-zero. */
			PRINTF_THIS_IS_DBMAIL;
			result = 1;
			break;
		default:
			/* printf("unrecognized option [%c], continuing...\n",optopt); */
			break;
		}

		/* If there's a non-negative return code,
		 * it's time to free memory and bail out. */
		if (result)
			goto freeall;
	}	

	/* If nothing is happening, show the help text. */
	if (!user || (basedir && outfile) || show_help) {
		do_showhelp();
		result = 1;
		goto freeall;
	}
 
	/* read the config file */
        if (config_read(configFile) == -1) {
                qerrorf("Failed. Unable to read config file %s\n", configFile);
                result = -1;
                goto freeall;
        }
                
	SetTraceLevel("DBMAIL");
	GetDBParams();

	/* open database connection */
	if (db_connect() != 0) {
		qerrorf ("Failed. Could not connect to database (check log)\n");
		result = -1;
		goto freeall;
	}

	/* open authentication connection */
	if (auth_connect() != 0) {
		qerrorf("Failed. Could not connect to authentication (check log)\n");
		result = -1;
		goto freeall;
	}

	/* Loop over all user accounts if there's a wildcard. */
	if (strchr(user, '?') || strchr(user, '*')) {
		GList *all_users = auth_get_known_users();
		GList *matching_users = match_glob_list(user, all_users);
		GList *users = g_list_first(matching_users);

		if (!users) {
			qerrorf("Error: no users matching [%s] were found.\n", user);
			g_list_destroy(all_users);
			result = -1;
			goto freeall;
		}

		while (users) {
			result = do_export(users->data, mailbox,
				basedir, outfile, search,
				delete_after_dump, recursive);

			if (!g_list_next(users))
				break;
			users = g_list_next(users);
		}

		g_list_destroy(all_users);
		g_list_destroy(matching_users);
	} else {
		/* No globbing, just run with this one user. */
		result = do_export(user, mailbox,
			basedir, outfile, search,
			delete_after_dump, recursive);
	}

	/* Here's where we free memory and quit.
	 * Be sure that all of these are NULL safe! */
freeall:

	db_disconnect();
	auth_disconnect();
	config_free();
	g_mime_shutdown();

	if (result < 0)
		qerrorf("Command failed.\n");
	return result;
}
Exemple #15
0
static int do_export(char *user, char *base_mailbox, char *basedir, char *outfile, char *search, int delete_after_dump, int recursive)
{
	u64_t user_idnr = 0, owner_idnr = 0, mailbox_idnr = 0;
	char *dumpfile = NULL, *mailbox = NULL, *search_mailbox = NULL, *dir = NULL;
	GList *children = NULL;
	int result = 0;

	/* Verify the existence of this user */
	if (! auth_user_exists(user, &user_idnr)) {
		qerrorf("Error: user [%s] does not exist.\n", user);
		result = -1;
		goto cleanup;
	}

	mailbox = g_new0(char, IMAP_MAX_MAILBOX_NAMELEN);

	if (!base_mailbox) {
		/* Always recursive without a mailbox base */
		search_mailbox = g_strdup("*");
	} else if (recursive) {
		/* Base and everything below */
		search_mailbox = g_strdup_printf("%s*", base_mailbox);
	} else if (!recursive) {
		/* Should yield same results as plain db_findmailbox */
		search_mailbox = g_strdup_printf("%s", base_mailbox);
	}

	/* FIXME: What are the possible error conditions here? */
	db_findmailbox_by_regex(user_idnr, search_mailbox, &children, 0);

	/* Decision process for basedir vs. outfile:
	 *   If we're dumping one mailbox for one user, it goes to
	 *   stdout.  If we've been given -o -, dump everything to
	 *   stdout (e.g., one giant mbox).  If we've been given foo
	 */

	if (!outfile && !basedir) {
		/* Default is to use basedir of . */
		basedir = ".";
	} else if (outfile) {
		/* Everything goes into this one file */
		dumpfile = outfile;
	}

	children = g_list_first(children);

	qerrorf("Exporting [%u] mailboxes for [%s]\n", g_list_length(children), user);

	while (children) {
		mailbox_idnr = *(u64_t *)children->data;
		db_getmailboxname(mailbox_idnr, user_idnr, mailbox);			
		if (! db_get_mailbox_owner(mailbox_idnr, &owner_idnr)) {
			qerrorf("Error checking mailbox ownership");
			goto cleanup;
		}
		if (owner_idnr == user_idnr) {
			if (basedir) {
				/* Prepare the directory */
				dumpfile = g_strdup_printf("%s/%s/%s.mbox", basedir, user, mailbox);

				dir = g_path_get_dirname(dumpfile);
				if (g_mkdir_with_parents(dir, 0700)) {
					qerrorf("can't create directory [%s]\n", dir);
					result = -1;
					goto cleanup;
				}
			}

			qerrorf(" export mailbox %s -> %s\n", mailbox, dumpfile);
			if ((result = mailbox_dump(mailbox_idnr, dumpfile, search, delete_after_dump)) != 0) {
				qerrorf("error exporting mailbox %s -> %s\n", mailbox, dumpfile);
				goto cleanup;
			}

			if (delete_after_dump) db_update("UPDATE %smailboxes SET seq=seq+1 WHERE mailbox_idnr=%d",DBPFX,mailbox_idnr);

			if (basedir) {
				g_free(dir);
				g_free(dumpfile);
			}
		}
		if (! g_list_next(children)) break;
		children = g_list_next(children);
	}

cleanup:
	g_list_destroy(children);
	g_free(search_mailbox);
	g_free(mailbox);

	return result;
}
int main(int argc, char *argv[])
{
	int check_integrity = 0;
	int check_iplog = 0, check_replycache = 0;
	char *timespec_iplog = NULL, *timespec_replycache = NULL;
	int vacuum_db = 0, purge_deleted = 0, set_deleted = 0, dangling_aliases = 0, rehash = 0;
	int show_help = 0;
	int do_nothing = 1;
	int is_header = 0;
	int migrate = 0, migrate_limit = 10000;
	static struct option long_options[] = {
		{ "rehash", 0, 0, 0 },
		{ 0, 0, 0, 0 }
	};
	int opt_index = 0;
	int opt;

	g_mime_init(0);
	openlog(PNAME, LOG_PID, LOG_MAIL);
	setvbuf(stdout, 0, _IONBF, 0);

	/* get options */
	opterr = 0;		/* suppress error message from getopt() */
	while ((opt = getopt_long(argc, argv, "-acbtl:r:pudsMm:" "i" "f:qnyvVh", long_options, &opt_index)) != -1) {
		/* The initial "-" of optstring allows unaccompanied
		 * options and reports them as the optarg to opt 1 (not '1') */
		switch (opt) {
		case 0:
			do_nothing = 0;
			if (strcmp(long_options[opt_index].name,"rehash")==0)
				rehash = 1;
			break;
		case 'a':
			/* This list should be kept up to date. */
			vacuum_db = 1;
			purge_deleted = 1;
			set_deleted = 1;
			dangling_aliases = 1;
			check_integrity = 1;
			is_header = 1;
			do_nothing = 0;
			break;

		case 'c':
			vacuum_db = 1;
			do_nothing = 0;
			break;

		case 'b':
			is_header = 1;
			do_nothing = 0;
			break;

		case 'p':
			purge_deleted = 1;
			do_nothing = 0;
			break;

		case 'd':
			set_deleted = 1;
			do_nothing = 0;
			break;

		case 's':
			dangling_aliases = 1;
			do_nothing = 0;
			break;

		case 't':
			check_integrity = 1;
			do_nothing = 0;
			break;

		case 'u':
			/* deprecated */
			break;

		case 'l':
			check_iplog = 1;
			do_nothing = 0;
			if (optarg)
				timespec_iplog = g_strdup(optarg);
			break;

		case 'r':
			check_replycache = 1;
			do_nothing = 0;
			if (optarg)
				timespec_replycache = g_strdup(optarg);
			break;

		case 'M':
			migrate = 1;
			do_nothing = 0;
			break;
		case 'm':
			if (optarg)
				migrate_limit = atoi(optarg);
			break;

		case 'i':
			qerrorf("Interactive console is not supported in this release.\n");
			return 1;

		/* Common options */
		case 'h':
			show_help = 1;
			do_nothing = 0;
			break;

		case 'n':
			no_to_all = 1;
			break;

		case 'y':
			yes_to_all = 1;
			break;

		case 'q':
                        /* If we get q twice, be really quiet! */
                        if (quiet)
	                                reallyquiet = 1;
                        if (!verbose)
	                                quiet = 1;
			break;

		case 'f':
			if (optarg && strlen(optarg) > 0)
				configFile = optarg;
			else {
				qerrorf("dbmail-util: -f requires a filename\n\n" );
				return 1;
			}
			break;

		case 'v':
			verbose = 1;
			break;

		case 'V':
			PRINTF_THIS_IS_DBMAIL;
			return 1;

		default:
			printf("unrecognized option [%c]\n", optopt); 
			show_help = 1;
			break;
		}
	}

	if (do_nothing || show_help || (no_to_all && yes_to_all)) {
		do_showhelp();
		return 1;
	}

 	/* Don't make any changes unless specifically authorized. */
 	if (!yes_to_all) {
		qprintf("Choosing dry-run mode. No changes will be made at this time.\n");
		no_to_all = 1;
 	}

	config_read(configFile);
	SetTraceLevel("DBMAIL");
	GetDBParams();

	qverbosef("Opening connection to database... \n");
	if (db_connect() != 0) {
		qerrorf("Failed. An error occured. Please check log.\n");
		return -1;
	}

	qverbosef("Opening connection to authentication... \n");
	if (auth_connect() != 0) {
		qerrorf("Failed. An error occured. Please check log.\n");
		return -1;
	}

	qverbosef("Ok. Connected.\n");

	if (check_integrity) do_check_integrity();
	if (purge_deleted) do_purge_deleted();
	if (is_header) do_header_cache();
	if (set_deleted) do_set_deleted();
	if (dangling_aliases) do_dangling_aliases();
	if (check_iplog) do_check_iplog(timespec_iplog);
	if (check_replycache) do_check_replycache(timespec_replycache);
	if (vacuum_db) do_vacuum_db();
	if (rehash) do_rehash();
	if (migrate) do_migrate(migrate_limit);

	if (!has_errors && !serious_errors) {
		qprintf("\nMaintenance done. No errors found.\n");
	} else {
		qerrorf("\nMaintenance done. Errors were found");
		if (serious_errors) {
			qerrorf(" but not fixed due to failures.\n");
			qerrorf("Please check the logs for further details, "
				"turning up the trace level as needed.\n");
			// Indicate that something went really wrong
			has_errors = 3;
		} else if (no_to_all) {
			qerrorf(" but not fixed.\n");
			qerrorf("Run again with the '-y' option to "
				"repair the errors.\n");
			// Indicate that the program should be run with -y
			has_errors = 2;
		} else if (yes_to_all) {
			qerrorf(" and fixed.\n");
			qerrorf("We suggest running dbmail-util again to "
				"confirm that all errors were repaired.\n");
			// Indicate that the program should be run again
			has_errors = 1;
		}
	}

	auth_disconnect();
	db_disconnect();
	config_free();
	g_mime_shutdown();
	
	return has_errors;
}
Exemple #17
0
int do_check_integrity(void)
{
	time_t start, stop;
	GList *lost = NULL;
	const char *action;
	gboolean cleanup;
	long count = 0;

	if (yes_to_all) {
		action = "Repairing";
		cleanup = TRUE;
	} else {
		action = "Checking";
		cleanup = FALSE;
	}

	qprintf("\n%s DBMAIL message integrity...\n", action);

	/* This is what we do:
	 3. Check for loose physmessages
	 4. Check for loose partlists
	 5. Check for loose mimeparts
	 6. Check for loose headernames
	 7. Check for loose headervalues
	 */

	/* part 3 */
	time(&start);
	qprintf("\n%s DBMAIL physmessage integrity...\n", action);
	if ((count = db_icheck_physmessages(cleanup)) < 0) {
		qerrorf("Failed. An error occurred. Please check log.\n");
		serious_errors = 1;
		return -1;
	}
	if (count > 0) {
		qerrorf("Ok. Found [%ld] unconnected physmessages.\n", count);
		if (cleanup) {
			qerrorf("Ok. Orphaned physmessages deleted.\n");
		}
	} else {
		qprintf("Ok. Found [%ld] unconnected physmessages.\n", count);
	}

	time(&stop);
	qverbosef("--- %s unconnected physmessages took %g seconds\n",
		action, difftime(stop, start));
	/* end part 3 */

	/* part 4 */
	start = stop;
	qprintf("\n%s DBMAIL partlists integrity...\n", action);
	if ((count = db_icheck_partlists(cleanup)) < 0) {
		qerrorf("Failed. An error occurred. Please check log.\n");
		serious_errors = 1;
		return -1;
	}
	if (count > 0) {
		qerrorf("Ok. Found [%ld] unconnected partlists.\n", count);
		if (cleanup) {
			qerrorf("Ok. Orphaned partlists deleted.\n");
		}
	} else {
		qprintf("Ok. Found [%ld] unconnected partlists.\n", count);
	}

	time(&stop);
	qverbosef("--- %s unconnected partlists took %g seconds\n",
		action, difftime(stop, start));
	/* end part 4 */

	/*  part 5 */
	start = stop;
	qprintf("\n%s DBMAIL mimeparts integrity...\n", action);
	if ((count = db_icheck_mimeparts(cleanup)) < 0) {
		qerrorf("Failed. An error occurred. Please check log.\n");
		serious_errors = 1;
		return -1;
	}
	if (count > 0) {
		qerrorf("Ok. Found [%ld] unconnected mimeparts.\n", count);
		if (cleanup) {
			qerrorf("Ok. Orphaned mimeparts deleted.\n");
		}
	} else {
		qprintf("Ok. Found [%ld] unconnected mimeparts.\n", count);
	}

	time(&stop);
	qverbosef("--- %s unconnected mimeparts took %g seconds\n",
		action, difftime(stop, start));
	/* end part 5 */

	/* part 6 */
        Field_T config;
	bool cache_readonly = false;
	config_get_value("header_cache_readonly", "DBMAIL", config);
	if (strlen(config)) {
		if (MATCH(config, "true") || MATCH(config, "yes")) {
			cache_readonly = true;
		}
	}

        if (! cache_readonly) {
		start = stop;
		qprintf("\n%s DBMAIL headernames integrity...\n", action);
		if ((count = db_icheck_headernames(cleanup)) < 0) {
			qerrorf("Failed. An error occurred. Please check log.\n");
			serious_errors = 1;
			return -1;
		}

		qprintf("Ok. Found [%ld] unconnected headernames.\n", count);
		if (count > 0 && cleanup) {
			qerrorf("Ok. Orphaned headernames deleted.\n");
		}

		time(&stop);
		qverbosef("--- %s unconnected headernames took %g seconds\n",
			action, difftime(stop, start));
	}
	/* end part 6 */

	/* part 7 */
	start = stop;
	qprintf("\n%s DBMAIL headervalues integrity...\n", action);
	if ((count = db_icheck_headervalues(cleanup)) < 0) {
		qerrorf("Failed. An error occurred. Please check log.\n");
		serious_errors = 1;
		return -1;
	}

	qprintf("Ok. Found [%ld] unconnected headervalues.\n", count);
	if (count > 0 && cleanup) {
		qerrorf("Ok. Orphaned headervalues deleted.\n");
	}

	time(&stop);
	qverbosef("--- %s unconnected headervalues took %g seconds\n",
		action, difftime(stop, start));
	/* end part 7 */

	g_list_destroy(lost);
	lost = NULL;

	time(&stop);
	qverbosef("--- %s block integrity took %g seconds\n", action, difftime(stop, start));

	return 0;
}