static int do_reconstruct(struct findall_data *data, void *rock)
{
    if (!data) return 0;
    struct reconstruct_rock *rrock = (struct reconstruct_rock *) rock;
    int r;
    struct mailbox *mailbox = NULL;
    char outpath[MAX_MAILBOX_PATH];
    const char *name = NULL;
    int make_changes = reconstruct_flags & RECONSTRUCT_MAKE_CHANGES;
    int prefer_mbentry = reconstruct_flags & RECONSTRUCT_PREFER_MBOXLIST;

    /* ignore partial matches */
    if (!data->is_exactmatch) return 0;

    /* ignore intermediates */
    if ((data->mbentry->mbtype & MBTYPE_INTERMEDIATE))
        return 0;
    /* ignore remote */
    if ((data->mbentry->mbtype & MBTYPE_REMOTE))
        return 0;

    signals_poll();

    name = mbname_intname(data->mbname);

    /* don't repeat */
    if (hash_lookup(name, &rrock->visited)) return 0;

    struct mboxlock *namespacelock = mboxname_usernamespacelock(name);

    if (setversion) {
        r = mailbox_open_iwl(name, &mailbox);
        if (r) {
            com_err(name, r, "Failed to open mailbox to set version");
            mboxname_release(&namespacelock);
            return 0;
        }
    }
    else {
        r = mailbox_reconstruct(name, reconstruct_flags, &mailbox);
        if (r) {
            com_err(name, r, "%s",
                    (r == IMAP_IOERROR) ? error_message(errno) : "Failed to reconstruct mailbox");
            mboxname_release(&namespacelock);
            return 0;
        }
    }

    mbentry_t *mbentry_byid = NULL;
    mbentry_t *mbentry_byname = NULL;

    r = mboxlist_lookup(name, &mbentry_byname, NULL);
    // this better succeed!
    if (r) {
        printf("Failed to re-read %s!\n", name);
        exit(1);
    }

    int mbentry_dirty = 0;

    // fix any uniqueid related mixups first!
    if (strcmpsafe(mailbox_uniqueid(mailbox), mbentry_byname->uniqueid)) {
        printf("Wrong uniqueid in mbentry, fixing %s (%s -> %s)\n",
               name, mbentry_byname->uniqueid, mailbox_uniqueid(mailbox));
        xzfree(mbentry_byname->uniqueid);
        mbentry_byname->uniqueid = xstrdupnull(mailbox_uniqueid(mailbox));
        mbentry_dirty = 1;
    }

    // fetch by uniqueid and compare
    r = mboxlist_lookup_by_uniqueid(mbentry_byname->uniqueid, &mbentry_byid, NULL);
    if (r == IMAP_MAILBOX_NONEXISTENT) {
        printf("Missing mboxlist entry for uniqueid - will rewrite %s (%s)\n",
               name, mbentry_byname->uniqueid);
        mbentry_dirty = 1;
    }
    else if (r) {
        printf("Error reading mailboxesdb for %s\n", name);
        exit(1);
    }
    else if (strcmpsafe(mbentry_byid->name, name)) {
        printf("Wrong uniqueid! %s (should be %s)\n", mbentry_byid->name, name);
        if (updateuniqueids) {
            mailbox_make_uniqueid(mailbox);
            xzfree(mbentry_byname->uniqueid);
            mbentry_byname->uniqueid = xstrdupnull(mailbox_uniqueid(mailbox));
            mbentry_dirty = 1;
            syslog (LOG_ERR, "uniqueid clash with %s - changed %s (%s => %s)",
                    mbentry_byid->name, mailbox_name(mailbox), mbentry_byid->uniqueid, mailbox_uniqueid(mailbox));
        }
        else {
            syslog (LOG_ERR, "uniqueid clash with %s for %s (%s)",
                    mbentry_byid->name, mailbox_name(mailbox), mailbox_uniqueid(mailbox));
            exit(1);
        }
    }
    else {
        // see if anything is actually different
        if (mbentry_byname->uidvalidity != mbentry_byid->uidvalidity) {
            printf("mismatched uidvalidity byid %s (%u %u)\n",
                   name, mbentry_byname->uidvalidity, mbentry_byid->uidvalidity);
            mbentry_dirty = 1;
        }
        if (mbentry_byname->mbtype != mbentry_byid->mbtype) {
            printf("mismatched mbtype byid %s (%u %u)\n",
                   name, mbentry_byname->mbtype, mbentry_byid->mbtype);
            mbentry_dirty = 1;
        }
        if (strcmpsafe(mbentry_byname->partition, mbentry_byid->partition)) {
            printf("mismatched partition byid %s (%s %s)\n",
                   name, mbentry_byname->partition, mbentry_byid->partition);
            mbentry_dirty = 1;
        }
        if (strcmpsafe(mbentry_byname->server, mbentry_byid->server)) {
            printf("mismatched server byid %s (%s %s)\n",
                   name, mbentry_byname->server, mbentry_byid->server);
            mbentry_dirty = 1;
        }
        if (strcmpsafe(mbentry_byname->acl, mbentry_byid->acl)) {
            printf("mismatched acl byid %s (%s %s)\n",
                   name, mbentry_byname->acl, mbentry_byid->acl);
            mbentry_dirty = 1;
        }
    }
    mboxlist_entry_free(&mbentry_byid);

    if (mailbox->i.uidvalidity != mbentry_byname->uidvalidity) {
        if (!mailbox->i.uidvalidity || (prefer_mbentry && mbentry_byname->uidvalidity)) {
            printf("Wrong uidvalidity in mailbox, fixing %s (%u -> %u)\n",
                   name, mailbox->i.uidvalidity, mbentry_byname->uidvalidity);
            mailbox->i.uidvalidity = mbentry_byname->uidvalidity;
            mailbox_index_dirty(mailbox);
        }
        else {
            printf("Wrong uidvalidity in mbentry, fixing %s (%u -> %u)\n",
                   name, mbentry_byname->uidvalidity, mailbox->i.uidvalidity);
            mbentry_byname->uidvalidity = mailbox->i.uidvalidity;
            mbentry_dirty = 1;
        }
    }

    if (strcmpsafe(mailbox_acl(mailbox), mbentry_byname->acl)) {
        if (prefer_mbentry) {
            printf("Wrong acl in mbentry %s (%s %s)\n",
                   name, mailbox_acl(mailbox), mbentry_byname->acl);
            // this sets the header to dirty
            mailbox_set_acl(mailbox, mbentry_byname->acl);
        }
        else {
            printf("Wrong acl in mbentry %s (%s %s)\n",
                   name, mbentry_byname->acl, mailbox_acl(mailbox));
            xzfree(mbentry_byname->acl);
            mbentry_byname->acl = xstrdupnull(mailbox_acl(mailbox));
            mbentry_dirty = 1;
        }
    }

    if (mbentry_dirty && make_changes) {
        r = mboxlist_update(mbentry_byname, 1);
        if (r) syslog(LOG_ERR, "IOERROR: failed to update mbentry for %s (%s)", name, error_message(r));
    }
    mboxlist_entry_free(&mbentry_byname);

    /* Convert internal name to external */
    char *extname = mboxname_to_external(name, &recon_namespace, NULL);
    if (!(reconstruct_flags & RECONSTRUCT_QUIET))
        printf("%s\n", extname);

    strncpy(outpath, mailbox_meta_fname(mailbox, META_HEADER), MAX_MAILBOX_NAME);

    if (setversion && setversion != mailbox->i.minor_version) {
        int oldversion = mailbox->i.minor_version;
        /* need to re-set the version! */
        int r = mailbox_setversion(mailbox, setversion);
        if (r) {
            printf("FAILED TO REPACK %s with new version %s\n", extname, error_message(r));
        }
        else {
            printf("Converted %s version %d to %d\n", extname, oldversion, setversion);
        }
    }
    if (make_changes) {
        mailbox_commit(mailbox);
    }
    else {
        mailbox_abort(mailbox);
    }
    mailbox_close(&mailbox);
    free(extname);
    mboxname_release(&namespacelock);

    if (rrock->discovered) {
        char fnamebuf[MAX_MAILBOX_PATH];
        char *ptr;
        DIR *dirp;
        struct dirent *dirent;
        struct stat sbuf;

        ptr = strstr(outpath, "cyrus.header");
        if (!ptr) return 0;
        *ptr = 0;

        r = chdir(outpath);
        if (r) return 0;

        /* we recurse down this directory to see if there's any mailboxes
           under this not in the mailboxes database */
        dirp = opendir(".");
        if (!dirp) return 0;

        while ((dirent = readdir(dirp)) != NULL) {
            /* mailbox directories never have a dot in them */
            if (strchr(dirent->d_name, '.')) continue;
            if (stat(dirent->d_name, &sbuf) < 0) continue;
            if (!S_ISDIR(sbuf.st_mode)) continue;

            /* ok, we found a directory that doesn't have a dot in it;
               is there a cyrus.header file? */
            snprintf(fnamebuf, MAX_MAILBOX_PATH, "%s%s",
                     dirent->d_name, FNAME_HEADER);
            if (stat(fnamebuf, &sbuf) < 0) continue;

            /* ok, we have a real mailbox directory */
            char buf[MAX_MAILBOX_NAME];
            snprintf(buf, MAX_MAILBOX_NAME, "%s.%s",
                     name, dirent->d_name);

            /* does fnamebuf exist as a mailbox in mboxlist? */
            do {
                r = mboxlist_lookup(buf, NULL, NULL);
            } while (r == IMAP_AGAIN);
            if (!r) continue; /* mailbox exists; it'll be reconstructed
                                 with a -r */

            if (r != IMAP_MAILBOX_NONEXISTENT) break; /* erg? */
            else r = 0; /* reset error condition */

            printf("discovered %s\n", buf);
            strarray_append(rrock->discovered, buf);
        }
        closedir(dirp);
    }

    /* mark it as visited
     * we don't care about the value, it just needs to be a non-NULL pointer
     */
    hash_insert(name, &rrock, &rrock->visited);

    return 0;
}
static int do_reconstruct(struct findall_data *data, void *rock)
{
    if (!data) return 0;
    struct reconstruct_rock *rrock = (struct reconstruct_rock *) rock;
    int r;
    struct mailbox *mailbox = NULL;
    char outpath[MAX_MAILBOX_PATH];
    const char *name = NULL;
    int make_changes = reconstruct_flags & RECONSTRUCT_MAKE_CHANGES;
    int prefer_mbentry = reconstruct_flags & RECONSTRUCT_PREFER_MBOXLIST;

     
    if (!data->is_exactmatch) return 0;

     
    if ((data->mbentry->mbtype & MBTYPE_INTERMEDIATE))
        return 0;
     
    if ((data->mbentry->mbtype & MBTYPE_REMOTE))
        return 0;

    signals_poll();

    name = mbname_intname(data->mbname);

     
    if (hash_lookup(name, &rrock->visited)) return 0;

    struct mboxlock *namespacelock = mboxname_usernamespacelock(name);

    if (setversion) {
        r = mailbox_open_iwl(name, &mailbox);
        if (r) {
            com_err(name, r, "Failed to open mailbox to set version");
            mboxname_release(&namespacelock);
            return 0;
        }
    }
    else {
        r = mailbox_reconstruct(name, reconstruct_flags, &mailbox);
        if (r) {
            com_err(name, r, "%s",
                    (r == IMAP_IOERROR) ? error_message(errno) : "Failed to reconstruct mailbox");
            mboxname_release(&namespacelock);
            return 0;
        }
    }

    mbentry_t *mbentry_byid = NULL;
    mbentry_t *mbentry_byname = NULL;

    r = mboxlist_lookup(name, &mbentry_byname, NULL);
     
    if (r) {
        printf("Failed to re-read %s!\n", name);
        exit(1);
    }

    int mbentry_dirty = 0;

     
    if (strcmpsafe(mailbox_uniqueid(mailbox), mbentry_byname->uniqueid)) {
        printf("Wrong uniqueid in mbentry, fixing %s (%s -> %s)\n",
               name, mbentry_byname->uniqueid, mailbox_uniqueid(mailbox));
        xzfree(mbentry_byname->uniqueid);
        mbentry_byname->uniqueid = xstrdupnull(mailbox_uniqueid(mailbox));
        mbentry_dirty = 1;
    }

     
    r = mboxlist_lookup_by_uniqueid(mbentry_byname->uniqueid, &mbentry_byid, NULL);
    if (r == IMAP_MAILBOX_NONEXISTENT) {
        printf("Missing mboxlist entry for uniqueid - will rewrite %s (%s)\n",
               name, mbentry_byname->uniqueid);
        mbentry_dirty = 1;
    }
    else if (r) {
        printf("Error reading mailboxesdb for %s\n", name);
        exit(1);
    }
    else if (strcmpsafe(mbentry_byid->name, name)) {
        printf("Wrong uniqueid! %s (should be %s)\n", mbentry_byid->name, name);
        if (updateuniqueids) {
            mailbox_make_uniqueid(mailbox);
            xzfree(mbentry_byname->uniqueid);
            mbentry_byname->uniqueid = xstrdupnull(mailbox_uniqueid(mailbox));
            mbentry_dirty = 1;
            syslog (LOG_ERR, "uniqueid clash with %s - changed %s (%s => %s)",
                    mbentry_byid->name, mailbox_name(mailbox), mbentry_byid->uniqueid, mailbox_uniqueid(mailbox));
        }
        else {
            syslog (LOG_ERR, "uniqueid clash with %s for %s (%s)",
                    mbentry_byid->name, mailbox_name(mailbox), mailbox_uniqueid(mailbox));
            exit(1);
        }
    }
    else {
         
        if (mbentry_byname->uidvalidity != mbentry_byid->uidvalidity) {
            printf("mismatched uidvalidity byid %s (%u %u)\n",
                   name, mbentry_byname->uidvalidity, mbentry_byid->uidvalidity);
            mbentry_dirty = 1;
        }
        if (mbentry_byname->mbtype != mbentry_byid->mbtype) {
            printf("mismatched mbtype byid %s (%u %u)\n",
                   name, mbentry_byname->mbtype, mbentry_byid->mbtype);
            mbentry_dirty = 1;
        }
        if (strcmpsafe(mbentry_byname->partition, mbentry_byid->partition)) {
            printf("mismatched partition byid %s (%s %s)\n",
                   name, mbentry_byname->partition, mbentry_byid->partition);
            mbentry_dirty = 1;
        }
        if (strcmpsafe(mbentry_byname->server, mbentry_byid->server)) {
            printf("mismatched server byid %s (%s %s)\n",
                   name, mbentry_byname->server, mbentry_byid->server);
            mbentry_dirty = 1;
        }
        if (strcmpsafe(mbentry_byname->acl, mbentry_byid->acl)) {
            printf("mismatched acl byid %s (%s %s)\n",
                   name, mbentry_byname->acl, mbentry_byid->acl);
            mbentry_dirty = 1;
        }
    }
    mboxlist_entry_free(&mbentry_byid);

    if (mailbox->i.uidvalidity != mbentry_byname->uidvalidity) {
        if (!mailbox->i.uidvalidity || (prefer_mbentry && mbentry_byname->uidvalidity)) {
            printf("Wrong uidvalidity in mailbox, fixing %s (%u -> %u)\n",
                   name, mailbox->i.uidvalidity, mbentry_byname->uidvalidity);
            mailbox->i.uidvalidity = mbentry_byname->uidvalidity;
            mailbox_index_dirty(mailbox);
        }
        else {
            printf("Wrong uidvalidity in mbentry, fixing %s (%u -> %u)\n",
                   name, mbentry_byname->uidvalidity, mailbox->i.uidvalidity);
            mbentry_byname->uidvalidity = mailbox->i.uidvalidity;
            mbentry_dirty = 1;
        }
    }

    if (strcmpsafe(mailbox_acl(mailbox), mbentry_byname->acl)) {
        if (prefer_mbentry) {
            printf("Wrong acl in mbentry %s (%s %s)\n",
                   name, mailbox_acl(mailbox), mbentry_byname->acl);
             
            mailbox_set_acl(mailbox, mbentry_byname->acl);
        }
        else {
            printf("Wrong acl in mbentry %s (%s %s)\n",
                   name, mbentry_byname->acl, mailbox_acl(mailbox));
            xzfree(mbentry_byname->acl);
            mbentry_byname->acl = xstrdupnull(mailbox_acl(mailbox));
            mbentry_dirty = 1;
        }
    }

    if (mbentry_dirty && make_changes) {
        r = mboxlist_update(mbentry_byname, 1);
        if (r) syslog(LOG_ERR, "IOERROR: failed to update mbentry for %s (%s)", name, error_message(r));
    }
    mboxlist_entry_free(&mbentry_byname);

     
    char *extname = mboxname_to_external(name, &recon_namespace, NULL);
    if (!(reconstruct_flags & RECONSTRUCT_QUIET))
        printf("%s\n", extname);

    strncpy(outpath, mailbox_meta_fname(mailbox, META_HEADER), MAX_MAILBOX_NAME);

    if (setversion && setversion != mailbox->i.minor_version) {
        int oldversion = mailbox->i.minor_version;
         
        int r = mailbox_setversion(mailbox, setversion);
        if (r) {
            printf("FAILED TO REPACK %s with new version %s\n", extname, error_message(r));
        }
        else {
            printf("Converted %s version %d to %d\n", extname, oldversion, setversion);
        }
    }
    if (make_changes) {
        mailbox_commit(mailbox);
    }
    else {
        mailbox_abort(mailbox);
    }
    mailbox_close(&mailbox);
    free(extname);
    mboxname_release(&namespacelock);

    if (rrock->discovered) {
        char fnamebuf[MAX_MAILBOX_PATH];
        char *ptr;
        DIR *dirp;
        struct dirent *dirent;
        struct stat sbuf;

        ptr = strstr(outpath, "cyrus.header");
        if (!ptr) return 0;
        *ptr = 0;

        r = chdir(outpath);
        if (r) return 0;

         
        dirp = opendir(".");
        if (!dirp) return 0;

        while ((dirent = readdir(dirp)) != NULL) {
             
            if (strchr(dirent->d_name, '.')) continue;
            if (stat(dirent->d_name, &sbuf) < 0) continue;
            if (!S_ISDIR(sbuf.st_mode)) continue;

             
            snprintf(fnamebuf, MAX_MAILBOX_PATH, "%s%s",
                     dirent->d_name, FNAME_HEADER);
            if (stat(fnamebuf, &sbuf) < 0) continue;

             
            char buf[MAX_MAILBOX_NAME];
            snprintf(buf, MAX_MAILBOX_NAME, "%s.%s",
                     name, dirent->d_name);

             
            do {
                r = mboxlist_lookup(buf, NULL, NULL);
            } while (r == IMAP_AGAIN);
            if (!r) continue;  

            if (r != IMAP_MAILBOX_NONEXISTENT) break;  
            else r = 0;  

            printf("discovered %s\n", buf);
            strarray_append(rrock->discovered, buf);
        }
        closedir(dirp);
    }

     
    hash_insert(name, &rrock, &rrock->visited);

    return 0;
}