int propfind_by_collection(const mbentry_t *mbentry, void *rock)
{
    struct propfind_ctx *fctx = (struct propfind_ctx *) rock;
    const char *mboxname = mbentry->name;
    struct buf writebuf = BUF_INITIALIZER;
    struct mailbox *mailbox = NULL;
    char *p;
    size_t len;
    int r = 0, rights = 0;

    /* skip deleted items */
    if (mboxname_isdeletedmailbox(mbentry->name, 0) ||
        (mbentry->mbtype & MBTYPE_DELETED)) {
        goto done;
    }

    /* Check ACL on mailbox for current user */
    rights = httpd_myrights(httpd_authstate, mbentry);
    if ((rights & fctx->reqd_privs) != fctx->reqd_privs) goto done;

    /* We only match known types */
    if (!(mbentry->mbtype & fctx->req_tgt->namespace->mboxtype)) goto done;

    p = strrchr(mboxname, '.');
    if (!p) goto done;
    p++; /* skip dot */

    switch (fctx->req_tgt->namespace->id) {
    case URL_NS_DRIVE:
        if (fctx->req_tgt->flags == TGT_DRIVE_USER) {
            /* Special case of listing users with DAV #drives */
            p = strchr(mboxname+5, '.') + 1;  /* skip "user.XXX." */
            if (strcmp(p, fctx->req_tgt->mboxprefix)) goto done;
        }
        else if (p - mboxname > 1 + (int) strlen(fctx->req_tgt->mbentry->name)) {
            /* Reject folders that are more than one level deep */
            goto done;
        }
        break;

    default:
        /* Magic folder filter */
        if (httpd_extrafolder && strcasecmp(p, httpd_extrafolder)) goto done;
        break;
    }

    /* skip toplevels */
    if (config_getswitch(IMAPOPT_FASTMAILSHARING) && *p == '#')
        goto done;


    /* Open mailbox for reading */
    if ((r = mailbox_open_irl(mboxname, &mailbox))) {
        syslog(LOG_INFO, "mailbox_open_irl(%s) failed: %s",
               mboxname, error_message(r));
    }

    fctx->mbentry = mbentry;
    fctx->mailbox = mailbox;
    fctx->record = NULL;

    if (!fctx->req_tgt->resource) {
        /* we always have zzzz if it's already in the URL */
        int haszzzz = fctx->req_tgt->flags & TGT_USER_ZZZZ;

        mbname_t *mbname = mbname_from_intname(mboxname);
        if (!mbname_domain(mbname))
            mbname_set_domain(mbname, httpd_extradomain);

        /* we also need to deal with the discovery case,
         * where mboxname doesn't match request path */
        if (fctx->req_tgt->userid &&
            strcmpsafe(mbname_userid(mbname), fctx->req_tgt->userid)) {
            haszzzz = 1;
        }

        len = make_collection_url(&writebuf, fctx->req_tgt->namespace->prefix,
                                  haszzzz, mbname, fctx->req_tgt->userid);

        mbname_free(&mbname);

        /* copy it all back into place... in theory we should check against
         * 'last' and make sure it doesn't change from the original request.
         * yay for micro-optimised memory usage... */
        strlcpy(fctx->req_tgt->path, buf_cstring(&writebuf), MAX_MAILBOX_PATH);
        p = fctx->req_tgt->path + len;
        fctx->req_tgt->collection = p;
        fctx->req_tgt->collen = strlen(p);

        /* If not filtering by calendar resource, and not excluding root,
           add response for collection */
        if (!r && !fctx->filter_crit && !(fctx->prefer & PREFER_NOROOT) &&
            (r = xml_add_response(fctx, 0, 0, NULL, NULL))) goto done;
    }

    if (r) {
        xml_add_response(fctx, HTTP_SERVER_ERROR, 0, error_message(r), NULL);
        goto done;
    }

    if (fctx->depth > 1 && fctx->open_db) { // can't do davdb searches if no dav db
        /* Resource(s) */
        r = propfind_by_resources(fctx);
    }

  done:
    buf_free(&writebuf);
    if (mailbox) mailbox_close(&mailbox);

    return 0;
}
int propfind_by_collection(const mbentry_t *mbentry, void *rock)
{
    struct propfind_ctx *fctx = (struct propfind_ctx *) rock;
    const char *mboxname = mbentry->name;
    struct buf writebuf = BUF_INITIALIZER;
    struct mailbox *mailbox = NULL;
    char *p;
    size_t len;
    int r = 0, rights = 0;

     
    if (mboxname_isdeletedmailbox(mbentry->name, 0) ||
        (mbentry->mbtype & MBTYPE_DELETED)) {
        goto done;
    }

     
    rights = httpd_myrights(httpd_authstate, mbentry);
    if ((rights & fctx->reqd_privs) != fctx->reqd_privs) goto done;

     
    if (!(mbentry->mbtype & fctx->req_tgt->namespace->mboxtype)) goto done;

    p = strrchr(mboxname, '.');
    if (!p) goto done;
    p++;  

    switch (fctx->req_tgt->namespace->id) {
    case URL_NS_DRIVE:
        if (fctx->req_tgt->flags == TGT_DRIVE_USER) {
             
            p = strchr(mboxname+5, '.') + 1;   
            if (strcmp(p, fctx->req_tgt->mboxprefix)) goto done;
        }
        else if (p - mboxname > 1 + (int) strlen(fctx->req_tgt->mbentry->name)) {
             
            goto done;
        }
        break;

    default:
         
        if (httpd_extrafolder && strcasecmp(p, httpd_extrafolder)) goto done;
        break;
    }

     
    if (config_getswitch(IMAPOPT_FASTMAILSHARING) && *p == '#')
        goto done;


     
    if ((r = mailbox_open_irl(mboxname, &mailbox))) {
        syslog(LOG_INFO, "mailbox_open_irl(%s) failed: %s",
               mboxname, error_message(r));
    }

    fctx->mbentry = mbentry;
    fctx->mailbox = mailbox;
    fctx->record = NULL;

    if (!fctx->req_tgt->resource) {
         
        int haszzzz = fctx->req_tgt->flags & TGT_USER_ZZZZ;

        mbname_t *mbname = mbname_from_intname(mboxname);
        if (!mbname_domain(mbname))
            mbname_set_domain(mbname, httpd_extradomain);

         
        if (fctx->req_tgt->userid &&
            strcmpsafe(mbname_userid(mbname), fctx->req_tgt->userid)) {
            haszzzz = 1;
        }

        len = make_collection_url(&writebuf, fctx->req_tgt->namespace->prefix,
                                  haszzzz, mbname, fctx->req_tgt->userid);

        mbname_free(&mbname);

         
        strlcpy(fctx->req_tgt->path, buf_cstring(&writebuf), MAX_MAILBOX_PATH);
        p = fctx->req_tgt->path + len;
        fctx->req_tgt->collection = p;
        fctx->req_tgt->collen = strlen(p);

         
        if (!r && !fctx->filter_crit && !(fctx->prefer & PREFER_NOROOT) &&
            (r = xml_add_response(fctx, 0, 0, NULL, NULL))) goto done;
    }

    if (r) {
        xml_add_response(fctx, HTTP_SERVER_ERROR, 0, error_message(r), NULL);
        goto done;
    }

    if (fctx->depth > 1 && fctx->open_db) {  
         
        r = propfind_by_resources(fctx);
    }

  done:
    buf_free(&writebuf);
    if (mailbox) mailbox_close(&mailbox);

    return 0;
}