static int do_proppatch(struct proppatch_ctx *pctx, xmlNodePtr instr)
{
    struct propstat propstat[NUM_PROPSTAT];
    int i;

    memset(propstat, 0, NUM_PROPSTAT * sizeof(struct propstat));

    /* Iterate through propertyupdate children */
    for (; instr; instr = instr->next) {
        if (instr->type == XML_ELEMENT_NODE) {
            xmlNodePtr prop;
            unsigned set = 0;

            if (!xmlStrcmp(instr->name, BAD_CAST "set")) set = 1;
            else if ((pctx->txn->meth == METH_PROPPATCH) &&
                     !xmlStrcmp(instr->name, BAD_CAST "remove")) set = 0;
            else {
                syslog(LOG_INFO, "Unknown PROPPATCH instruction");
                pctx->txn->error.desc = "Unknown PROPPATCH instruction";
                return HTTP_BAD_REQUEST;
            }

            /* Find child element */
            for (prop = instr->children;
                 prop && prop->type != XML_ELEMENT_NODE; prop = prop->next);
            if (!prop || xmlStrcmp(prop->name, BAD_CAST "prop")) {
                pctx->txn->error.desc = "Missing prop element";
                return HTTP_BAD_REQUEST;
            }

            /* Iterate through requested properties */
            for (prop = prop->children; prop; prop = prop->next) {
                if (prop->type == XML_ELEMENT_NODE) {
                    const struct prop_entry *entry;

                    /* Look for a match against our known properties */
                    for (entry = pctx->lprops;
                         entry->name &&
                             (strcmp((const char *) prop->name, entry->name) ||
                              !prop->ns ||
                              strcmp((const char *) prop->ns->href,
                                     known_namespaces[entry->ns].href));
                         entry++);

                    if (entry->name) {
                        int rights = httpd_myrights(httpd_authstate,
                                                    pctx->txn->req_tgt.mbentry);
                        if (!entry->put) {
                            /* Protected property */
                            xml_add_prop(HTTP_FORBIDDEN, pctx->ns[NS_DAV],
                                         &propstat[PROPSTAT_FORBID],
                                         prop->name, prop->ns, NULL,
                                         DAV_PROT_PROP);
                            *pctx->ret = HTTP_FORBIDDEN;
                        }
                        else if ((pctx->txn->meth == METH_PROPPATCH) &&
                                 !(rights & ((entry->flags & PROP_PERUSER) ?
                                             DACL_READ : DACL_PROPCOL))) {
                            /* DAV:need-privileges */
                            xml_add_prop(HTTP_FORBIDDEN, pctx->ns[NS_DAV],
                                         &propstat[PROPSTAT_FORBID],
                                         prop->name, prop->ns, NULL,
                                         DAV_NEED_PRIVS);
                            *pctx->ret = HTTP_FORBIDDEN;
                        }
                        else {
                            /* Write "live" property */
                            entry->put(prop, set, pctx, propstat, entry->rock);
                        }
                    }
                    else if (!prop->ns) {
                        /* Property with no namespace */
                        xmlNodePtr newprop =
                            xml_add_prop(HTTP_FORBIDDEN, pctx->ns[NS_DAV],
                                         &propstat[PROPSTAT_FORBID],
                                         prop->name, NULL, NULL, 0);
                        xmlSetNs(newprop, NULL);
                        *pctx->ret = HTTP_FORBIDDEN;
                    }
                    else if (pctx->txn->req_tgt.namespace->id != URL_NS_PRINCIPAL) {
                        /* Write "dead" property */
                        proppatch_todb(prop, set, pctx, propstat, NULL);
                    }
                }
            }
        }
    }

    /* One or more of the properties failed */
    if (*pctx->ret && propstat[PROPSTAT_OK].root) {
        /* 200 status must become 424 */
        propstat[PROPSTAT_FAILEDDEP].root = propstat[PROPSTAT_OK].root;
        propstat[PROPSTAT_FAILEDDEP].status = HTTP_FAILED_DEP;
        propstat[PROPSTAT_OK].root = NULL;
    }

    /* Add status and optional error to the propstat elements
       and then add them to the response element */
    for (i = 0; i < NUM_PROPSTAT; i++) {
        struct propstat *stat = &propstat[i];

        if (stat->root) {
            xmlNewChild(stat->root, NULL, BAD_CAST "status",
                        BAD_CAST http_statusline(VER_1_1, stat->status));
            if (stat->precond) {
                struct error_t error = { NULL, stat->precond, NULL, NULL, 0 };
                xml_add_error(stat->root, &error, pctx->ns);
            }

            xmlAddChild(pctx->root, stat->root);
        }
    }

    return 0;
}
static int do_proppatch(struct proppatch_ctx *pctx, xmlNodePtr instr)
{
    struct propstat propstat[NUM_PROPSTAT];
    int i;

    memset(propstat, 0, NUM_PROPSTAT * sizeof(struct propstat));

     
    for (; instr; instr = instr->next) {
        if (instr->type == XML_ELEMENT_NODE) {
            xmlNodePtr prop;
            unsigned set = 0;

            if (!xmlStrcmp(instr->name, BAD_CAST "set")) set = 1;
            else if ((pctx->txn->meth == METH_PROPPATCH) &&
                     !xmlStrcmp(instr->name, BAD_CAST "remove")) set = 0;
            else {
                syslog(LOG_INFO, "Unknown PROPPATCH instruction");
                pctx->txn->error.desc = "Unknown PROPPATCH instruction";
                return HTTP_BAD_REQUEST;
            }

             
            for (prop = instr->children;
                 prop && prop->type != XML_ELEMENT_NODE; prop = prop->next);
            if (!prop || xmlStrcmp(prop->name, BAD_CAST "prop")) {
                pctx->txn->error.desc = "Missing prop element";
                return HTTP_BAD_REQUEST;
            }

             
            for (prop = prop->children; prop; prop = prop->next) {
                if (prop->type == XML_ELEMENT_NODE) {
                    const struct prop_entry *entry;

                     
                    for (entry = pctx->lprops;
                         entry->name &&
                             (strcmp((const char *) prop->name, entry->name) ||
                              !prop->ns ||
                              strcmp((const char *) prop->ns->href,
                                     known_namespaces[entry->ns].href));
                         entry++);

                    if (entry->name) {
                        int rights = httpd_myrights(httpd_authstate,
                                                    pctx->txn->req_tgt.mbentry);
                        if (!entry->put) {
                             
                            xml_add_prop(HTTP_FORBIDDEN, pctx->ns[NS_DAV],
                                         &propstat[PROPSTAT_FORBID],
                                         prop->name, prop->ns, NULL,
                                         DAV_PROT_PROP);
                            *pctx->ret = HTTP_FORBIDDEN;
                        }
                        else if ((pctx->txn->meth == METH_PROPPATCH) &&
                                 !(rights & ((entry->flags & PROP_PERUSER) ?
                                             DACL_READ : DACL_PROPCOL))) {
                             
                            xml_add_prop(HTTP_FORBIDDEN, pctx->ns[NS_DAV],
                                         &propstat[PROPSTAT_FORBID],
                                         prop->name, prop->ns, NULL,
                                         DAV_NEED_PRIVS);
                            *pctx->ret = HTTP_FORBIDDEN;
                        }
                        else {
                             
                            entry->put(prop, set, pctx, propstat, entry->rock);
                        }
                    }
                    else if (!prop->ns) {
                         
                        xmlNodePtr newprop =
                            xml_add_prop(HTTP_FORBIDDEN, pctx->ns[NS_DAV],
                                         &propstat[PROPSTAT_FORBID],
                                         prop->name, NULL, NULL, 0);
                        xmlSetNs(newprop, NULL);
                        *pctx->ret = HTTP_FORBIDDEN;
                    }
                    else if (pctx->txn->req_tgt.namespace->id != URL_NS_PRINCIPAL) {
                         
                        proppatch_todb(prop, set, pctx, propstat, NULL);
                    }
                }
            }
        }
    }

     
    if (*pctx->ret && propstat[PROPSTAT_OK].root) {
         
        propstat[PROPSTAT_FAILEDDEP].root = propstat[PROPSTAT_OK].root;
        propstat[PROPSTAT_FAILEDDEP].status = HTTP_FAILED_DEP;
        propstat[PROPSTAT_OK].root = NULL;
    }

     
    for (i = 0; i < NUM_PROPSTAT; i++) {
        struct propstat *stat = &propstat[i];

        if (stat->root) {
            xmlNewChild(stat->root, NULL, BAD_CAST "status",
                        BAD_CAST http_statusline(VER_1_1, stat->status));
            if (stat->precond) {
                struct error_t error = { NULL, stat->precond, NULL, NULL, 0 };
                xml_add_error(stat->root, &error, pctx->ns);
            }

            xmlAddChild(pctx->root, stat->root);
        }
    }

    return 0;
}