示例#1
0
EXPORTED void strarray_free(strarray_t *sa)
{
    if (!sa)
	return;
    strarray_fini(sa);
    free(sa);
}
示例#2
0
文件: script.c 项目: gnb/cyrus-imapd
int sieve_execute_bytecode(sieve_execute_t *exe, sieve_interp_t *interp,
			   void *script_context, void *message_context) 
{
    action_list_t *actions = NULL;
    notify_list_t *notify_list = NULL;
    /*   notify_action_t *notify_action;*/
    action_t lastaction = -1;
    int ret;
    char actions_string[ACTIONS_STRING_LEN] = "";
    const char *errmsg = NULL;
    strarray_t imapflags = STRARRAY_INITIALIZER;
    
    if (!interp) return SIEVE_FAIL;

    if (interp->notify) {
	notify_list = new_notify_list();
	if (notify_list == NULL) {
	    return do_sieve_error(SIEVE_NOMEM, interp,
				  script_context, message_context, &imapflags,
				  actions, notify_list, lastaction, 0,
				  actions_string, errmsg);
	}
    }

    actions = new_action_list();
    if (actions == NULL) {
	ret = do_sieve_error(SIEVE_NOMEM, interp,
			     script_context, message_context, &imapflags,
			     actions, notify_list, lastaction, 0,
			     actions_string, errmsg);
    }
    else {
	ret = sieve_eval_bc(exe, 0, interp,
			    script_context, message_context,
			    &imapflags, actions, notify_list, &errmsg);

	if (ret < 0) {
	    ret = do_sieve_error(SIEVE_RUN_ERROR, interp,
				 script_context, message_context, &imapflags,
				 actions, notify_list, lastaction, 0,
				 actions_string, errmsg);
	}
	else {
	    ret = do_action_list(interp,
				 script_context, message_context, 
				 &imapflags, actions, notify_list,
				 actions_string, errmsg);
	}
    }

    strarray_fini(&imapflags);

    return ret;
}
示例#3
0
EXPORTED void varlist_fini(variable_list_t *vl) {
    if (!vl) {
	return;
    }
    if (vl->name) {
	free(vl->name);
	vl->name = NULL;
    }
    if (vl->var) {
	strarray_fini(vl->var);
	vl->var = NULL;
    }
    varlist_free(vl->next);
    vl->next = NULL;
}
示例#4
0
EXPORTED int run_command(const char *argv0, ...)
{
    va_list va;
    const char *p;
    strarray_t argv = STRARRAY_INITIALIZER;
    pid_t pid;
    int r = 0;

    strarray_append(&argv, argv0);

    va_start(va, argv0);
    while ((p = va_arg(va, const char *)))
        strarray_append(&argv, p);
    va_end(va);

    pid = fork();
    if (pid < 0) {
        syslog(LOG_ERR, "Failed to fork: %m");
        r = IMAP_SYS_ERROR;
        goto out;
    }

    if (!pid) {
        /* in child */
        r = execv(argv0, argv.data);
        syslog(LOG_ERR, "Failed to execute %s: %m", argv0);
        exit(1);
    }
    else {
        /* in parent */
        r = wait_for_child(argv0, pid);
    }

out:
    strarray_fini(&argv);
    return r;
}
示例#5
0
int main(int argc, char **argv)
{
    int opt;
    char *alt_config = NULL;
    int r = IMAP_NOTFOUND;
    strarray_t mboxnames = STRARRAY_INITIALIZER;
    const char *query = NULL;
    int background = 1;
    const char *channel = "squatter";
    const char *synclogfile = NULL;
    int init_flags = CYRUSINIT_PERROR;
    int multi_folder = 0;
    int user_mode = 0;
    int compact_flags = 0;
    const char *fromfile = NULL;
    strarray_t *srctiers = NULL;
    const char *desttier = NULL;
    enum { UNKNOWN, INDEXER, INDEXFROM, SEARCH, ROLLING, SYNCLOG,
           START_DAEMON, STOP_DAEMON, RUN_DAEMON, COMPACT } mode = UNKNOWN;

    if ((geteuid()) == 0 && (become_cyrus(/*is_master*/0) != 0)) {
        fatal("must run as the Cyrus user", EC_USAGE);
    }

    setbuf(stdout, NULL);

    while ((opt = getopt(argc, argv, "C:I:N:RAXT:S:Fc:de:f:mn:rsiavz:t:ou")) != EOF) {
        switch (opt) {
        case 'C':               /* alt config file */
            alt_config = optarg;
            break;

        case 'A':
            compact_flags |= SEARCH_COMPACT_AUDIT;
            break;

        case 'F':
            compact_flags |= SEARCH_COMPACT_FILTER;
            break;

        case 'X':
            compact_flags |= SEARCH_COMPACT_REINDEX;
            break;

        case 'N':
            name_starts_from = optarg;
            break;

        case 'I':               /* indexer, using specified mbox/uids in file */
            if (mode != UNKNOWN && mode != INDEXFROM) usage(argv[0]);
            fromfile = optarg;
            mode = INDEXFROM;
            break;

        case 'R':               /* rolling indexer */
            if (mode != UNKNOWN) usage(argv[0]);
            mode = ROLLING;
            incremental_mode = 1; /* always incremental if rolling */
            break;

        case 'S':               /* sleep time in seconds */
            sleepmicroseconds = (atof(optarg) * 1000000);
            break;

        case 'T':               /* temporary root directory for search */
            temp_root_dir = optarg;
            break;

        /* This option is deliberately undocumented, for testing only */
        case 'c':               /* daemon control mode */
            if (mode != UNKNOWN) usage(argv[0]);
            if (!strcmp(optarg, "start"))
                mode = START_DAEMON;
            else if (!strcmp(optarg, "stop"))
                mode = STOP_DAEMON;
            else if (!strcmp(optarg, "run"))
                mode = RUN_DAEMON;
            else
                usage(argv[0]);
            break;

        case 'd':               /* foreground (with -R) */
            background = 0;
            break;

        /* This option is deliberately undocumented, for testing only */
        case 'e':               /* add a search term */
            if (mode != UNKNOWN && mode != SEARCH) usage(argv[0]);
            query = optarg;
            mode = SEARCH;
            break;

        case 'f': /* alternate synclogfile used in SYNCLOG mode */
            synclogfile = optarg;
            mode = SYNCLOG;
            break;

        /* This option is deliberately undocumented, for testing only */
        case 'm':               /* multi-folder in SEARCH mode */
            if (mode != UNKNOWN && mode != SEARCH) usage(argv[0]);
            multi_folder = 1;
            mode = SEARCH;
            break;

        case 'n':               /* sync channel name (with -R) */
            channel = optarg;
            break;

        case 'o':               /* copy one DB rather than compressing */
            compact_flags |= SEARCH_COMPACT_COPYONE;
            break;

        case 'v':               /* verbose */
            verbose++;
            break;

        case 'r':               /* recurse */
            if (mode != UNKNOWN && mode != INDEXER) usage(argv[0]);
            recursive_flag = 1;
            mode = INDEXER;
            break;

        case 'i':               /* incremental mode */
            incremental_mode = 1;
            break;

        case 'a':               /* use /squat annotation */
            if (mode != UNKNOWN && mode != INDEXER) usage(argv[0]);
            annotation_flag = 1;
            mode = INDEXER;
            break;

        case 'z':
            if (mode != UNKNOWN && mode != COMPACT) usage(argv[0]);
            desttier = optarg;
            mode = COMPACT;
            break;

        case 't':
            if (mode != UNKNOWN && mode != COMPACT) usage(argv[0]);
            srctiers = strarray_split(optarg, ",", 0);
            mode = COMPACT;
            break;

        case 'u':
            user_mode = 1;
            break;

        default:
            usage("squatter");
        }
    }

    compact_flags |= SEARCH_VERBOSE(verbose);

    if (mode == UNKNOWN)
        mode = INDEXER;

    /* fork and close fds if required */
    if (mode == ROLLING && background) {
        become_daemon();
        init_flags &= ~CYRUSINIT_PERROR;
    }

    if (mode == COMPACT && (!desttier || !srctiers)) {
        /* need both src and dest for compact */
        usage("squatter");
    }

    cyrus_init(alt_config, "squatter", init_flags, CONFIG_NEED_PARTITION_DATA);

    /* Set namespace -- force standard (internal) */
    if ((r = mboxname_init_namespace(&squat_namespace, 1)) != 0) {
        fatal(error_message(r), EC_CONFIG);
    }

    annotate_init(NULL, NULL);
    annotatemore_open();

    mboxlist_init(0);
    mboxlist_open(NULL);

    if (mode == ROLLING || mode == SYNCLOG) {
        signals_set_shutdown(&shut_down);
        signals_add_handlers(0);
    }

    switch (mode) {
    case UNKNOWN:
        break;
    case INDEXER:
        /* -r requires at least one mailbox */
        if (recursive_flag && optind == argc) usage(argv[0]);
        expand_mboxnames(&mboxnames, argc-optind, (const char **)argv+optind, user_mode);
        syslog(LOG_NOTICE, "indexing mailboxes");
        r = do_indexer(&mboxnames);
        syslog(LOG_NOTICE, "done indexing mailboxes");
        break;
    case INDEXFROM:
        syslog(LOG_NOTICE, "indexing messages");
        r = do_indexfrom(fromfile);
        syslog(LOG_NOTICE, "done indexing messages");
        break;
    case SEARCH:
        if (recursive_flag && optind == argc) usage(argv[0]);
        expand_mboxnames(&mboxnames, argc-optind, (const char **)argv+optind, user_mode);
        r = do_search(query, !multi_folder, &mboxnames);
        break;
    case ROLLING:
        do_rolling(channel);
        /* never returns */
        break;
    case SYNCLOG:
        r = do_synclogfile(synclogfile);
        break;
    case START_DAEMON:
        if (optind != argc) usage("squatter");
        search_start_daemon(verbose);
        break;
    case STOP_DAEMON:
        if (optind != argc) usage("squatter");
        search_stop_daemon(verbose);
        break;
    case RUN_DAEMON:
        if (optind != argc) usage("squatter");
        do_run_daemon();
        break;
    case COMPACT:
        if (recursive_flag && optind == argc) usage(argv[0]);
        expand_mboxnames(&mboxnames, argc-optind, (const char **)argv+optind, user_mode);
        r = do_compact(&mboxnames, srctiers, desttier, compact_flags);
        break;
    }

    strarray_fini(&mboxnames);
    shut_down(r ? EC_TEMPFAIL : 0);
}
示例#6
0
static int do_notify(void)
{
    struct sockaddr_un sun_data;
    socklen_t sunlen = sizeof(sun_data);
    char buf[NOTIFY_MAXSIZE+1], *cp, *tail;
    int r, i;
    char *method, *class, *priority, *user, *mailbox, *message;
    strarray_t options = STRARRAY_INITIALIZER;
    long nopt;
    char *reply;
    char *fname;
    notifymethod_t *nmethod;

    while (1) {
        method = class = priority = user = mailbox = message = reply = NULL;
        nopt = 0;

        if (signals_poll() == SIGHUP) {
            /* caught a SIGHUP, return */
            return 0;
        }
        r = recvfrom(soc, buf, NOTIFY_MAXSIZE, 0,
                     (struct sockaddr *) &sun_data, &sunlen);
        if (r == -1) {
            return (errno);
        }
        buf[r] = '\0';

        tail = buf + r - 1;

        /*
         * parse request of the form:
         *
         * method NUL class NUL priority NUL user NUL mailbox NUL
         *   nopt NUL N(option NUL) message NUL
         */
        method = (cp = buf);

        if (cp) class = (cp = fetch_arg(cp, tail));
        if (cp) priority = (cp = fetch_arg(cp, tail));
        if (cp) user = (cp = fetch_arg(cp, tail));
        if (cp) mailbox = (cp = fetch_arg(cp, tail));

        if (cp) cp = fetch_arg(cp, tail); /* skip to nopt */
        if (cp) nopt = strtol(cp, NULL, 10);
        if (nopt < 0 || errno == ERANGE) cp = NULL;

        for (i = 0; cp && i < nopt; i++)
            strarray_appendm(&options, cp = fetch_arg(cp, tail));

        if (cp) message = (cp = fetch_arg(cp, tail));
        if (cp) fname = (cp = fetch_arg(cp, tail));

        if (!message) {
            syslog(LOG_ERR, "malformed notify request");
            strarray_fini(&options);
            return 0;
        }

        if (!*method)
            nmethod = default_method;
        else {
            nmethod = methods;
            while (nmethod->name) {
                if (!strcasecmp(nmethod->name, method)) break;
                nmethod++;
            }
        }

        syslog(LOG_DEBUG, "do_notify using method '%s'",
               nmethod->name ? nmethod->name: "unknown");

        if (nmethod->name) {
            reply = nmethod->notify(class, priority, user, mailbox,
                                    nopt, options.data, message, fname);
        }
#if 0  /* we don't care about responses right now */
        else {
示例#7
0
EXPORTED int command_popen(struct command **cmdp, const char *mode,
                           const char *cwd, const char *argv0, ...)
{
    va_list va;
    const char *p;
    strarray_t argv = STRARRAY_INITIALIZER;
    pid_t pid;
    int r = 0;
    struct command *cmd;
    int do_stdin = (strchr(mode, 'w') != NULL);
    int do_stdout = (strchr(mode, 'r') != NULL);
    int stdin_pipe[2] = { -1, -1 };
    int stdout_pipe[2] = { -1, -1 };

    strarray_append(&argv, argv0);

    va_start(va, argv0);
    while ((p = va_arg(va, const char *)))
        strarray_append(&argv, p);
    va_end(va);

    if (do_stdin) {
        r = pipe(stdin_pipe);
        if (r) {
            syslog(LOG_ERR, "Failed to pipe(): %m");
            r = IMAP_SYS_ERROR;
            goto out;
        }
    }

    if (do_stdout) {
        r = pipe(stdout_pipe);
        if (r) {
            syslog(LOG_ERR, "Failed to pipe(): %m");
            r = IMAP_SYS_ERROR;
            goto out;
        }
    }

    pid = fork();
    if (pid < 0) {
        syslog(LOG_ERR, "Failed to fork: %m");
        r = IMAP_SYS_ERROR;
        goto out;
    }

    if (!pid) {
        /* in child */
        if (do_stdin) {
            close(stdin_pipe[PIPE_WRITE]);
            dup2(stdin_pipe[PIPE_READ], STDIN_FILENO);
            close(stdin_pipe[PIPE_READ]);
        }
        if (do_stdout) {
            close(stdout_pipe[PIPE_READ]);
            dup2(stdout_pipe[PIPE_WRITE], STDOUT_FILENO);
            close(stdout_pipe[PIPE_WRITE]);
        }

        if (cwd) {
            r = chdir(cwd);
            if (r) syslog(LOG_ERR, "Failed to chdir(%s): %m", cwd);
        }

        r = execv(argv0, argv.data);
        syslog(LOG_ERR, "Failed to execute %s: %m", argv0);
        exit(1);
    }

    /* in parent */
    cmd = xzmalloc(sizeof(struct command));
    cmd->argv0 = xstrdup(argv0);
    cmd->pid = pid;
    if (do_stdin)
        cmd->stdin_prot = prot_new(stdin_pipe[PIPE_WRITE], /*write*/1);
    if (do_stdout)
        cmd->stdout_prot = prot_new(stdout_pipe[PIPE_READ], /*write*/0);
    *cmdp = cmd;

out:
    if (stdin_pipe[PIPE_READ] >= 0) close(stdin_pipe[PIPE_READ]);
    if (stdout_pipe[PIPE_WRITE] >= 0) close(stdout_pipe[PIPE_WRITE]);
    if (r) {
        if (stdin_pipe[PIPE_WRITE] >= 0) close(stdin_pipe[PIPE_WRITE]);
        if (stdout_pipe[PIPE_READ] >= 0) close(stdout_pipe[PIPE_READ]);
    }
    strarray_fini(&argv);
    return r;
}
示例#8
0
static int do_action_list(sieve_interp_t *interp,
                          void *script_context,
                          void *message_context,
                          strarray_t *imapflags,
                          action_list_t *actions,
                          notify_list_t *notify_list,
                          /* notify_action_t *notify_action,*/
                          char *actions_string,
                          const char *errmsg)
{
    action_list_t *a;
    action_t lastaction = -1;
    int ret = 0;
    int implicit_keep = 1;

    strcpy(actions_string,"Action(s) taken:\n");

    /* now perform actions attached to m */
    a = actions;
    while (a != NULL) {
        lastaction = a->a;
        errmsg = NULL;
        implicit_keep = implicit_keep && !a->cancel_keep;
        switch (a->a) {
        case ACTION_REJECT:
            if (!interp->reject)
                return SIEVE_INTERNAL_ERROR;
            ret = interp->reject(&a->u.rej,
                                 interp->interp_context,
                                 script_context,
                                 message_context,
                                 &errmsg);
            free(interp->lastitem);
            interp->lastitem = xstrdup(a->u.rej.msg);

            if (ret == SIEVE_OK)
                snprintf(actions_string+strlen(actions_string),
                         ACTIONS_STRING_LEN-strlen(actions_string),
                         "Rejected with: %s\n", a->u.rej.msg);

            break;
        case ACTION_FILEINTO:
            if (!interp->fileinto)
                return SIEVE_INTERNAL_ERROR;
            ret = interp->fileinto(&a->u.fil,
                                   interp->interp_context,
                                   script_context,
                                   message_context,
                                   &errmsg);
            free(interp->lastitem);
            interp->lastitem = xstrdup(a->u.fil.mailbox);

            if (ret == SIEVE_OK)
                snprintf(actions_string+strlen(actions_string),
                         ACTIONS_STRING_LEN-strlen(actions_string),
                         "Filed into: %s\n",a->u.fil.mailbox);
            break;
        case ACTION_KEEP:
            if (!interp->keep)
                return SIEVE_INTERNAL_ERROR;
            ret = interp->keep(&a->u.keep,
                               interp->interp_context,
                               script_context,
                               message_context,
                               &errmsg);
            free(interp->lastitem);
            interp->lastitem = NULL;
            if (ret == SIEVE_OK)
                snprintf(actions_string+strlen(actions_string),
                         ACTIONS_STRING_LEN-strlen(actions_string),
                         "Kept\n");
            break;
        case ACTION_REDIRECT:
            if (!interp->redirect)
                return SIEVE_INTERNAL_ERROR;
            ret = interp->redirect(&a->u.red,
                                   interp->interp_context,
                                   script_context,
                                   message_context,
                                   &errmsg);
            free(interp->lastitem);
            interp->lastitem = xstrdup(a->u.red.addr);
            if (ret == SIEVE_OK)
                snprintf(actions_string+strlen(actions_string),
                         ACTIONS_STRING_LEN-strlen(actions_string),
                         "Redirected to %s\n", a->u.red.addr);
            break;
        case ACTION_DISCARD:
            if (interp->discard) /* discard is optional */
                ret = interp->discard(NULL, interp->interp_context,
                                      script_context,
                                      message_context,
                                      &errmsg);
            free(interp->lastitem);
            interp->lastitem = NULL;
            if (ret == SIEVE_OK)
                snprintf(actions_string+strlen(actions_string),
                         ACTIONS_STRING_LEN-strlen(actions_string),
                         "Discarded\n");
            break;

        case ACTION_VACATION:
            {
                if (!interp->vacation)
                    return SIEVE_INTERNAL_ERROR;

                /* first, let's figure out if we should respond to this */
                ret = interp->vacation->autorespond(&a->u.vac.autoresp,
                                                    interp->interp_context,
                                                    script_context,
                                                    message_context,
                                                    &errmsg);
                free(interp->lastitem);
                interp->lastitem = NULL;

                if (ret == SIEVE_OK) {
                    /* send the response */
                    ret = interp->vacation->send_response(&a->u.vac.send,
                                                          interp->interp_context,
                                                          script_context,
                                                          message_context,
                                                          &errmsg);

                    if (ret == SIEVE_OK)
                        snprintf(actions_string+strlen(actions_string),
                                 ACTIONS_STRING_LEN-strlen(actions_string),
                                 "Sent vacation reply\n");

                } else if (ret == SIEVE_DONE) {
                    snprintf(actions_string+strlen(actions_string),
                             ACTIONS_STRING_LEN-strlen(actions_string),
                             "Vacation reply suppressed\n");

                    ret = SIEVE_OK;
                }

                break;
            }


        case ACTION_SETFLAG:
            strarray_fini(imapflags);
            break;
        case ACTION_ADDFLAG:
            strarray_add_case(imapflags, a->u.fla.flag);
            free(interp->lastitem);
            interp->lastitem = xstrdup(a->u.fla.flag);
            break;
        case ACTION_REMOVEFLAG:
            strarray_remove_all_case(imapflags, a->u.fla.flag);
            free(interp->lastitem);
            interp->lastitem = xstrdup(a->u.fla.flag);
            break;
        case ACTION_MARK:
            {
                int n = interp->markflags->count;

                ret = SIEVE_OK;
                while (n) {
                    strarray_add_case(imapflags,
                                        interp->markflags->data[--n]);
                }
                free(interp->lastitem);
                interp->lastitem = NULL;
                break;
            }
        case ACTION_UNMARK:
          {

                int n = interp->markflags->count;
                ret = SIEVE_OK;
                while (n) {
                    strarray_remove_all_case(imapflags,
                                           interp->markflags->data[--n]);
                }
                free(interp->lastitem);
                interp->lastitem = NULL;
                break;
            }

        case ACTION_NONE:
            break;

        default:
            ret = SIEVE_INTERNAL_ERROR;
            break;
        }
        a = a->next;

        if (ret != SIEVE_OK) {
            /* uh oh! better bail! */
            break;
        }
    }

    return do_sieve_error(ret, interp,
                          script_context, message_context,
                          imapflags, actions, notify_list, lastaction,
                          implicit_keep, actions_string, errmsg);
}
示例#9
0
static void myfreestate(struct auth_state *auth_state)
{
    strarray_fini(&auth_state->groups);
    free(auth_state);
}
示例#10
0
int main(int argc, char **argv)
{
    int opt, i, r;
    int dousers = 0;
    int rflag = 0;
    int mflag = 0;
    int fflag = 0;
    int xflag = 0;
    char buf[MAX_MAILBOX_PATH+1];
    strarray_t discovered = STRARRAY_INITIALIZER;
    char *alt_config = NULL;
    char *start_part = NULL;

    if ((geteuid()) == 0 && (become_cyrus(/*is_master*/0) != 0)) {
        fatal("must run as the Cyrus user", EC_USAGE);
    }

    construct_hash_table(&unqid_table, 2047, 1);

    while ((opt = getopt(argc, argv, "C:kp:rmfsxgGqRUMoOnV:u")) != EOF) {
        switch (opt) {
        case 'C': /* alt config file */
            alt_config = optarg;
            break;

        case 'p':
            start_part = optarg;
            break;

        case 'r':
            rflag = 1;
            break;

        case 'u':
            dousers = 1;
            break;

        case 'm':
            mflag = 1;
            break;

        case 'n':
            reconstruct_flags &= ~RECONSTRUCT_MAKE_CHANGES;
            break;

        case 'g':
            fprintf(stderr, "reconstruct: deprecated option -g ignored\n");
            break;

        case 'G':
            reconstruct_flags |= RECONSTRUCT_ALWAYS_PARSE;
            break;

        case 'f':
            fflag = 1;
            break;

        case 'x':
            xflag = 1;
            break;

        case 'k':
            fprintf(stderr, "reconstruct: deprecated option -k ignored\n");
            break;

        case 's':
            reconstruct_flags &= ~RECONSTRUCT_DO_STAT;
            break;

        case 'q':
            reconstruct_flags |= RECONSTRUCT_QUIET;
            break;

        case 'R':
            reconstruct_flags |= RECONSTRUCT_GUID_REWRITE;
            break;

        case 'U':
            reconstruct_flags |= RECONSTRUCT_GUID_UNLINK;
            break;

        case 'o':
            reconstruct_flags |= RECONSTRUCT_IGNORE_ODDFILES;
            break;

        case 'O':
            reconstruct_flags |= RECONSTRUCT_REMOVE_ODDFILES;
            break;

        case 'M':
            reconstruct_flags |= RECONSTRUCT_PREFER_MBOXLIST;
            break;

        case 'V':
            if (!strcasecmp(optarg, "max"))
                setversion = MAILBOX_MINOR_VERSION;
            else
                setversion = atoi(optarg);
            break;

        default:
            usage();
        }
    }

    cyrus_init(alt_config, "reconstruct", 0, CONFIG_NEED_PARTITION_DATA);
    global_sasl_init(1,0,NULL);

    /* Set namespace -- force standard (internal) */
    if ((r = mboxname_init_namespace(&recon_namespace, 1)) != 0) {
        syslog(LOG_ERR, "%s", error_message(r));
        fatal(error_message(r), EC_CONFIG);
    }

    sync_log_init();

    if (mflag) {
        if (rflag || fflag || optind != argc) {
            cyrus_done();
            usage();
        }
        do_mboxlist();
    }

    mboxlist_init(0);
    mboxlist_open(NULL);

    quotadb_init(0);
    quotadb_open(NULL);

#ifdef WITH_DAV
    caldav_init();
    carddav_init();
    webdav_init();
#endif

    /* Deal with nonexistent mailboxes */
    if (start_part) {
        /* We were handed a mailbox that does not exist currently */
        if(optind == argc) {
            fprintf(stderr,
                    "When using -p, you must specify a mailbox to attempt to reconstruct.");
            exit(EC_USAGE);
        }

        /* do any of the mailboxes exist in mboxlist already? */
        /* Do they look like mailboxes? */
        for (i = optind; i < argc; i++) {
            if (strchr(argv[i],'%') || strchr(argv[i],'*')) {
                fprintf(stderr, "Using wildcards with -p is not supported.\n");
                exit(EC_USAGE);
            }

            /* Translate mailboxname */
            char *intname = mboxname_from_external(argv[i], &recon_namespace, NULL);

            /* Does it exist */
            do {
                r = mboxlist_lookup(intname, NULL, NULL);
            } while (r == IMAP_AGAIN);

            if (r != IMAP_MAILBOX_NONEXISTENT) {
                fprintf(stderr,
                        "Mailbox %s already exists.  Cannot specify -p.\n",
                        argv[i]);
                exit(EC_USAGE);
            }
            free(intname);
        }

        /* None of them exist.  Create them. */
        for (i = optind; i < argc; i++) {
            /* Translate mailboxname */
            char *intname = mboxname_from_external(argv[i], &recon_namespace, NULL);

            /* don't notify mailbox creation here */
            r = mboxlist_createmailbox(intname, 0, start_part, 1,
                                       "cyrus", NULL, 0, 0, !xflag, 0, NULL);
            if (r) {
                fprintf(stderr, "could not create %s\n", argv[i]);
            }

            free(intname);
        }
    }

    /* Normal Operation */
    if (optind == argc) {
        if (rflag || dousers) {
            fprintf(stderr, "please specify a mailbox to recurse from\n");
            cyrus_done();
            exit(EC_USAGE);
        }
        assert(!rflag);
        strlcpy(buf, "*", sizeof(buf));
        mboxlist_findall(&recon_namespace, buf, 1, 0, 0,
                         do_reconstruct, NULL);
    }

    for (i = optind; i < argc; i++) {
        if (dousers) {
            mboxlist_usermboxtree(argv[i], do_reconstruct_p, NULL, MBOXTREE_TOMBSTONES|MBOXTREE_DELETED);
            continue;
        }
        char *domain = NULL;

        /* save domain */
        if (config_virtdomains) domain = strchr(argv[i], '@');

        strlcpy(buf, argv[i], sizeof(buf));

        /* reconstruct the first mailbox/pattern */
        mboxlist_findall(&recon_namespace, buf, 1, 0,
                         0, do_reconstruct,
                         fflag ? &discovered : NULL);
        if (rflag) {
            /* build a pattern for submailboxes */
            char *p = strchr(buf, '@');
            if (p) *p = '\0';
            strlcat(buf, ".*", sizeof(buf));

            /* append the domain */
            if (domain) strlcat(buf, domain, sizeof(buf));

            /* reconstruct the submailboxes */
            mboxlist_findall(&recon_namespace, buf, 1, 0,
                             0, do_reconstruct,
                             fflag ? &discovered : NULL);
        }
    }

    /* examine our list to see if we discovered anything */
    while (discovered.count) {
        char *name = strarray_shift(&discovered);
        int r = 0;

        /* create p (database only) and reconstruct it */
        /* partition is defined by the parent mailbox */
        /* don't notify mailbox creation here */
        r = mboxlist_createmailbox(name, 0, NULL, 1,
                                   "cyrus", NULL, 0, 0, !xflag, 0, NULL);
        if (r) {
            fprintf(stderr, "createmailbox %s: %s\n",
                    name, error_message(r));
        } else {
            mboxlist_findone(&recon_namespace, name, 1, 0,
                             0, do_reconstruct,
                             &discovered);
        }
        /* may have added more things into our list */

        free(name);
    }

    free_hash_table(&unqid_table, free);

    sync_log_done();

    mboxlist_close();
    mboxlist_done();

    quotadb_close();
    quotadb_done();

    partlist_local_done();
#ifdef WITH_DAV
    webdav_done();
    carddav_done();
    caldav_done();
#endif

    cyrus_done();

    strarray_fini(&discovered);

    return 0;
}