#include <config.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include "assert.h"
#include "exitcodes.h"
#include "global.h"
#include "imapd.h"
#include "imap_err.h"
#include "imapurl.h"
#include "mailbox.h"
#include "mboxlist.h"
#include "sysexits.h"
#include "xmalloc.h"
#include "xstrlcpy.h"
#include "xstrlcat.h"
const int config_need_data = CONFIG_NEED_PARTITION_DATA;
int verbose = 0;
static int dump_me(char *name, int matchlen, int maycreate, void *rock);
static void print_seq(const char *tag, const char *attrib,
unsigned *seq, int n);
int usage(const char *name);
int index_getuidsequence(struct mailbox *mailbox,
struct searchargs *searchargs,
unsigned **uid_list);
static struct namespace dump_namespace;
int imapd_exists;
struct protstream *imapd_out = NULL;
struct auth_state *imapd_authstate = NULL;
char *imapd_userid = NULL;
int imapd_condstore_client = 0;
struct incremental_record {
int incruid;
};
int main(int argc, char *argv[])
{
int option;
char buf[MAX_MAILBOX_PATH+1];
int i, r;
char *alt_config = NULL;
struct incremental_record irec;
if (geteuid() == 0) fatal("must run as the Cyrus user", EX_USAGE);
while ((option = getopt(argc, argv, "v")) != EOF) {
switch (option) {
case 'v':
verbose++;
break;
case 'C':
alt_config = optarg;
break;
default:
usage(argv[0]);
break;
}
}
if (optind == argc) {
usage(argv[0]);
}
cyrus_init(alt_config, "dump", 0);
mboxlist_init(0);
mboxlist_open(NULL);
if ((r = mboxname_init_namespace(&dump_namespace, 1)) != 0) {
syslog(LOG_ERR, error_message(r));
fatal(error_message(r), EC_CONFIG);
}
irec.incruid = 0;
for (i = optind; i < argc; i++) {
strlcpy(buf, argv[i], sizeof(buf));
mboxname_hiersep_tointernal(&dump_namespace, buf,
config_virtdomains ?
strcspn(buf, "@") : 0);
(*dump_namespace.mboxlist_findall)(&dump_namespace, buf, 1, 0, 0,
dump_me, &irec);
}
mboxlist_close();
mboxlist_done();
cyrus_done();
return 0;
}
int usage(const char *name)
{
fprintf(stderr, "usage: %s [-v] [mboxpattern ...]\n", name);
exit(EC_USAGE);
}
static void generate_boundary(char *boundary, size_t size)
{
assert(size >= 100);
snprintf(boundary, size, "dump-%ld-%ld-%ld",
(long) getpid(), (long) time(NULL), (long) rand());
}
static int dump_me(char *name, int matchlen __attribute__((unused)),
int maycreate __attribute__((unused)), void *rock)
{
int r;
struct mailbox m;
char boundary[128];
struct imapurl url;
char imapurl[MAX_MAILBOX_PATH];
struct incremental_record *irec = (struct incremental_record *) rock;
struct searchargs searchargs;
unsigned *uids;
unsigned *uidseq;
int i, n, numuids;
memset(&m, 0, sizeof(struct mailbox));
r = mailbox_open_header(name, 0, &m);
if (r) {
if (verbose) {
printf("error opening %s: %s\n", name, error_message(r));
}
return 0;
}
r = mailbox_open_index(&m);
if (!r) r = mailbox_lock_pop(&m);
if (r) {
if (verbose) {
printf("error locking index %s: %s\n", name, error_message(r));
}
mailbox_close(&m);
return 0;
}
mailbox_read_index_header(&m);
index_operatemailbox(&m);
generate_boundary(boundary, sizeof(boundary));
printf("Content-Type: multipart/related; boundary=\"%s\"\n\n", boundary);
printf("--%s\n", boundary);
printf("Content-Type: text/xml\n");
printf("IMAP-Dump-Version: 0\n");
printf("\n");
printf("<imapdump uniqueid=\"%s\">\n", m.uniqueid);
memset(&url, 0, sizeof(struct imapurl));
url.server = config_servername;
url.mailbox = m.name;
imapurl_toURL(imapurl, &url);
printf(" <mailbox-url>%s</mailbox-url>\n", imapurl);
printf(" <incremental-uid>%d</incremental-uid>\n", irec->incruid);
printf(" <nextuid>%ld</nextuid>\n", m.last_uid + 1);
printf("\n");
memset(&searchargs, 0, sizeof(struct searchargs));
numuids = index_getuidsequence(&m, &searchargs, &uids);
print_seq("uidlist", NULL, uids, numuids);
printf("\n");
printf(" <flags>\n");
searchargs.system_flags_set = FLAG_ANSWERED;
n = index_getuidsequence(&m, &searchargs, &uidseq);
print_seq("flag", "name=\"\\Answered\" user=\"*\"", uidseq, n);
if (uidseq) free(uidseq);
searchargs.system_flags_set = FLAG_DELETED;
n = index_getuidsequence(&m, &searchargs, &uidseq);
print_seq("flag", "name=\"\\Deleted\" user=\"*\"", uidseq, n);
if (uidseq) free(uidseq);
searchargs.system_flags_set = FLAG_DRAFT;
n = index_getuidsequence(&m, &searchargs, &uidseq);
print_seq("flag", "name=\"\\Draft\" user=\"*\"", uidseq, n);
if (uidseq) free(uidseq);
searchargs.system_flags_set = FLAG_FLAGGED;
n = index_getuidsequence(&m, &searchargs, &uidseq);
print_seq("flag", "name=\"\\Flagged\" user=\"*\"", uidseq, n);
if (uidseq) free(uidseq);
printf(" </flags>\n");
printf("</imapdump>\n");
for (i = 0; i < numuids; i++) {
const char *base;
unsigned long len;
if (uids[i] < irec->incruid) {
continue;
}
printf("\n--%s\n", boundary);
printf("Content-Type: message/rfc822\n");
printf("Content-ID: %d\n", uids[i]);
printf("\n");
r = mailbox_map_message(&m, uids[i], &base, &len);
if (r) {
if (verbose) {
printf("error mapping message %d: %s\n", uids[i],
error_message(r));
}
break;
}
fwrite(base, 1, len, stdout);
mailbox_unmap_message(&m, uids[i], &base, &len);
}
printf("\n--%s--\n", boundary);
index_closemailbox(&m);
mailbox_close(&m);
return 0;
}
static void print_seq(const char *tag, const char *attrib,
unsigned *seq, int n)
{
int i;
printf(" <%s%s%s>", tag, attrib ? " " : "", attrib ? attrib : "");
for (i = 0; i < n; i++) {
printf("%u ", seq[i]);
}
printf("</%s>\n", tag);
}
#if 0
char *p, *str;
int str_sz;
int run_start = 0;
int first_time = 1;
p = str = (char *) xmalloc(sizeof(char) * 1024);
str_sz = 1024;
run_start = msgno_list[0];
for (i = 1; i < n; i++) {
if (msgno_list[i] == msgno_list[i-1] + 1) {
continue;
}
if (first_time) {
first_time = 0;
} else {
*p++ = ',';
}
if (run_start != msgno_list[i-1]) {
p += sprintf(p, "%d:%d", run_start, msgno_list[i-1]);
} else {
p += sprintf(p, "%d", msgno_list[i-1]);
}
if (p > (str + str_sz - 20)) {
int x;
x = p - str;
str = (char *) xrealloc(str, str_sz *= 2);
p = str + x;
}
run_start = msgno_list[i];
}
if (!first_time) {
*p++ = ',';
}
if (run_start != msgno_list[i-1]) {
sprintf(p, "%d:%d", run_start, msgno_list[i-1]);
} else {
sprintf(p, "%d", msgno_list[i-1]);
}
return str;
#endif
void printastring(const char *s __attribute__((unused)))
{
fatal("printastring not implemented in cyrdump", EC_SOFTWARE);
}