#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <cx/hash_map.h>
#include <errno.h>
#include <libxml/tree.h>
#include "utils.h"
#define xstreq(a,b) xmlStrEqual(
BAD_CAST a,
BAD_CAST b)
#define xstrEQ(a,b) !xmlStrcasecmp(
BAD_CAST a,
BAD_CAST b)
#define print_error(lineno, ...) \
do {\
fprintf(stderr,
"Error (config.xml line %u): ", lineno); \
fprintf(stderr,
__VA_ARGS__); \
fprintf(stderr,
"Abort.\n"); \
}
while(
0);
#define print_warning(lineno, ...) \
do {\
fprintf(stderr,
"Warning (config.xml line %u): ", lineno); \
fprintf(stderr,
__VA_ARGS__); \
}
while(
0);
#ifdef _WIN32
#define ENV_HOME getenv(
"USERPROFILE")
#else
#define ENV_HOME getenv(
"HOME")
#endif
static int load_repository(
DavConfig *config,
DavCfgRepository **list_begin,
DavCfgRepository **list_end,
xmlNode *reponode);
static int load_key(
DavConfig *config,
DavCfgKey **list_begin,
DavCfgKey **list_end,
xmlNode *keynode);
static int load_proxy(
DavConfig *config, DavCfgProxy *proxy, xmlNode *proxynode,
int type);
static int load_namespace(
DavConfig *config,
DavCfgNamespace **list_begin,
DavCfgNamespace **list_end,
xmlNode *node);
static int load_secretstore(DavConfig *config, xmlNode *node);
int dav_cfg_string_set_node_value(DavConfig *config, CfgString *str, xmlNode *node) {
str->node = node;
char *value = util_xml_get_text(node);
if(value) {
str->value = cx_strdup_a(config->mp->allocator, cx_str(value));
return 0;
}
else {
str->value = (cxmutstr){
NULL,
0};
return 1;
}
}
void dav_cfg_bool_set_node_value(DavConfig *config, CfgBool *cbool, xmlNode *node) {
cbool->node = node;
char *value = util_xml_get_text(node);
cbool->value = util_getboolean(value);
}
static void set_xml_content(xmlNode *node,
const char *content) {
xmlNode *child = node->children;
while(child) {
xmlNode *next = child->next;
xmlUnlinkNode(child);
xmlFreeNode(child);
child = next;
}
if(content) {
xmlChar *encoded = xmlEncodeSpecialChars(node->doc, (
const xmlChar*)content);
if(encoded) {
xmlNodeSetContent(node, encoded);
xmlFree(encoded);
}
}
}
void dav_cfg_string_set_value(DavConfig *config, CfgString *str, xmlNode *parent, cxstring new_value,
const char *nodename) {
if(str->value.ptr) {
cxFree(config->mp->allocator, str->value.ptr);
}
if(new_value.ptr) {
str->value = cx_strdup_a(config->mp->allocator, new_value);
}
else {
str->value = cx_mutstrn(
NULL,
0);
}
if(!str->node) {
str->node = xmlNewNode(
NULL, (
const xmlChar*) nodename);
xmlAddChild(parent, str->node);
}
set_xml_content(str->node, new_value.ptr);
}
void dav_cfg_bool_set_value(DavConfig *config, CfgBool *cbool, xmlNode *parent, DavBool new_value,
const char *nodename) {
const char *content = new_value ?
"true" :
"false";
cbool->value = new_value;
if(!cbool->node) {
cbool->node = xmlNewNode(
NULL, (
const xmlChar*) nodename);
xmlAddChild(parent, cbool->node);
}
set_xml_content(cbool->node, content);
}
void dav_cfg_int_set_value(DavConfig *config, CfgInt *cint, xmlNode *parent,
int64_t new_value,
const char *nodename) {
char content[
32];
snprintf(content,
32,
"%" PRId64, new_value);
cint->value = new_value;
if(!cint->node) {
cint->node = xmlNewNode(
NULL, (
const xmlChar*) nodename);
xmlAddChild(parent, cint->node);
}
set_xml_content(cint->node, content);
}
void dav_cfg_uint_set_value(DavConfig *config, CfgUInt *cint, xmlNode *parent,
uint64_t new_value,
const char *nodename) {
char content[
32];
snprintf(content,
32,
"%" PRIu64, new_value);
cint->value = new_value;
if(!cint->node) {
cint->node = xmlNewNode(
NULL, (
const xmlChar*) nodename);
xmlAddChild(parent, cint->node);
}
set_xml_content(cint->node, content);
}
void dav_cfg_string_remove(CfgString *str) {
if(str->node) {
xmlUnlinkNode(str->node);
xmlFreeNode(str->node);
str->node =
NULL;
}
}
void dav_cfg_bool_remove(CfgBool *cbool) {
if(cbool->node) {
xmlUnlinkNode(cbool->node);
xmlFreeNode(cbool->node);
cbool->node =
NULL;
}
}
void dav_cfg_int_remove(CfgInt *cint) {
if(cint->node) {
xmlUnlinkNode(cint->node);
xmlFreeNode(cint->node);
cint->node =
NULL;
}
}
void dav_cfg_uint_remove(CfgUInt *cint) {
if(cint->node) {
xmlUnlinkNode(cint->node);
xmlFreeNode(cint->node);
cint->node =
NULL;
}
}
DavConfig* dav_config_new(xmlDoc *doc) {
CxMempool *cfg_mp = cxMempoolCreate(
128,
NULL);
DavConfig *config = cxMalloc(cfg_mp->allocator,
sizeof(DavConfig));
memset(config,
0,
sizeof(DavConfig));
config->mp = cfg_mp;
if(!doc) {
doc = xmlNewDoc(
BAD_CAST "1.0");
xmlNode *root = xmlNewNode(
NULL,
BAD_CAST "configuration");
xmlDocSetRootElement(doc, root);
}
config->doc = doc;
return config;
}
DavConfig* dav_config_load(cxmutstr xmlfilecontent,
int *error) {
xmlDoc *doc = xmlReadMemory(xmlfilecontent.ptr, xmlfilecontent.length,
NULL,
NULL,
0);
if(!doc) {
if(error) {
*error =
DAV_CONFIG_ERROR_XML;
}
return NULL;
}
DavConfig *config = dav_config_new(doc);
CxMempool *cfg_mp = config->mp;
cxMempoolRegister(cfg_mp, doc, (cx_destructor_func)xmlFreeDoc);
DavCfgRepository *repos_begin =
NULL;
DavCfgRepository *repos_end =
NULL;
DavCfgKey *keys_begin =
NULL;
DavCfgKey *keys_end =
NULL;
DavCfgNamespace *namespaces_begin =
NULL;
DavCfgNamespace *namespaces_end =
NULL;
xmlNode *xml_root = xmlDocGetRootElement(doc);
xmlNode *node = xml_root->children;
int ret =
0;
while(node && !ret) {
if(node->type ==
XML_ELEMENT_NODE) {
if(xstreq(node->name,
"repository")) {
ret = load_repository(config, &repos_begin, &repos_end, node);
}
else if(xstreq(node->name,
"key")) {
ret = load_key(config, &keys_begin, &keys_end, node);
}
else if (xstreq(node->name,
"http-proxy")) {
config->http_proxy = cxCalloc(config->mp->allocator,
1,
sizeof(DavCfgProxy));
ret = load_proxy(config, config->http_proxy, node,
DAV_HTTP_PROXY);
}
else if (xstreq(node->name,
"https-proxy")) {
config->https_proxy = cxCalloc(config->mp->allocator,
1,
sizeof(DavCfgProxy));
ret = load_proxy(config, config->https_proxy, node,
DAV_HTTPS_PROXY);
}
else if (xstreq(node->name,
"namespace")) {
ret = load_namespace(config, &namespaces_begin, &namespaces_end, node);
}
else if (xstreq(node->name,
"secretstore")) {
ret = load_secretstore(config, node);
}
else {
fprintf(stderr,
"Unknown config element: %s\n", node->name);
ret =
1;
}
}
node = node->next;
}
config->repositories = repos_begin;
config->keys = keys_begin;
config->namespaces = namespaces_begin;
if(ret !=
0 && error) {
*error = ret;
cxMempoolDestroy(cfg_mp);
}
return config;
}
void dav_config_free(DavConfig *config) {
cxMempoolDestroy(config->mp);
}
CxBuffer* dav_config2buf(DavConfig *config) {
xmlChar* xmlText =
NULL;
int textLen =
0;
xmlDocDumpFormatMemory(config->doc, &xmlText, &textLen,
1);
if(!xmlText) {
return NULL;
}
CxBuffer *buf = cxBufferCreate(
NULL, textLen, cxDefaultAllocator,
CX_BUFFER_AUTO_EXTEND|
CX_BUFFER_FREE_CONTENTS);
cxBufferWrite(xmlText,
1, textLen, buf);
xmlFree(xmlText);
return buf;
}
static int repo_add_config(
DavConfig *config,
DavCfgRepository *repo,
xmlNode* node)
{
unsigned short lineno = node->line;
char *key = (
char*)node->name;
char *value = util_xml_get_text(node);
if(!value) {
print_error(lineno,
"missing value for config element: %s\n", key);
return 1;
}
if(xstreq(key,
"name")) {
dav_cfg_string_set_node_value(config, &repo->name, node);
}
else if(xstreq(key,
"url")) {
dav_cfg_string_set_node_value(config, &repo->url, node);
}
else if(xstreq(key,
"user")) {
dav_cfg_string_set_node_value(config, &repo->user, node);
}
else if(xstreq(key,
"password")) {
dav_cfg_string_set_node_value(config, &repo->password, node);
}
else if(xstreq(key,
"stored-user")) {
dav_cfg_string_set_node_value(config, &repo->stored_user, node);
}
else if(xstreq(key,
"default-key")) {
dav_cfg_string_set_node_value(config, &repo->default_key, node);
}
else if(xstreq(key,
"full-encryption")) {
dav_cfg_bool_set_node_value(config, &repo->full_encryption, node);
}
else if(xstreq(key,
"content-encryption")) {
dav_cfg_bool_set_node_value(config, &repo->content_encryption, node);
}
else if(xstreq(key,
"decrypt-content")) {
dav_cfg_bool_set_node_value(config, &repo->decrypt_content, node);
}
else if(xstreq(key,
"decrypt-name")) {
dav_cfg_bool_set_node_value(config, &repo->decrypt_name, node);
}
else if(xstreq(key,
"cert")) {
dav_cfg_string_set_node_value(config, &repo->cert, node);
}
else if(xstreq(key,
"verification")) {
dav_cfg_bool_set_node_value(config, &repo->verification, node);
}
else if(xstreq(key,
"ssl-version")) {
repo->ssl_version.node = node;
int ssl_version = dav_str2ssl_version((
const char*)value);
if(ssl_version == -
1) {
print_warning(lineno,
"unknown ssl version: %s\n", value);
repo->ssl_version.value =
CURL_SSLVERSION_DEFAULT;
}
else {
repo->ssl_version.value = ssl_version;
}
}
else if(xstreq(key,
"authmethods")) {
repo->authmethods.node = node;
repo->authmethods.value =
CURLAUTH_NONE;
const char *delims =
" \t\r\n";
char *meths = strdup(value);
char *meth = strtok(meths, delims);
while (meth) {
if(xstrEQ(meth,
"basic")) {
repo->authmethods.value |=
CURLAUTH_BASIC;
}
else if(xstrEQ(meth,
"digest")) {
repo->authmethods.value |=
CURLAUTH_DIGEST;
}
else if(xstrEQ(meth,
"negotiate")) {
repo->authmethods.value |=
CURLAUTH_GSSNEGOTIATE;
}
else if(xstrEQ(meth,
"ntlm")) {
repo->authmethods.value |=
CURLAUTH_NTLM;
}
else if(xstrEQ(meth,
"any")) {
repo->authmethods.value =
CURLAUTH_ANY;
}
else if(xstrEQ(meth,
"none")) {
}
else {
print_warning(lineno,
"unknown authentication method: %s\n", meth);
}
meth = strtok(
NULL, delims);
}
free(meths);
}
else {
print_error(lineno,
"unkown repository config element: %s\n", key);
return 1;
}
return 0;
}
int dav_str2ssl_version(
const char *value) {
if(xstrEQ(value,
"TLSv1")) {
return CURL_SSLVERSION_TLSv1;
}
else if(xstrEQ(value,
"SSLv2")) {
return CURL_SSLVERSION_SSLv2;
}
else if(xstrEQ(value,
"SSLv3")) {
return CURL_SSLVERSION_SSLv3;
}
#if LIBCURL_VERSION_MAJOR *
1000 +
LIBCURL_VERSION_MINOR >=
7034
else if(xstrEQ(value,
"TLSv1.0")) {
return CURL_SSLVERSION_TLSv1_0;
}
else if(xstrEQ(value,
"TLSv1.1")) {
return CURL_SSLVERSION_TLSv1_1;
}
else if(xstrEQ(value,
"TLSv1.2")) {
return CURL_SSLVERSION_TLSv1_2;
}
#endif
#if LIBCURL_VERSION_MAJOR *
1000 +
LIBCURL_VERSION_MINOR >=
7052
else if(xstrEQ(value,
"TLSv1.3")) {
return CURL_SSLVERSION_TLSv1_3;
}
#endif
return -
1;
}
static int load_repository(
DavConfig *config,
DavCfgRepository **list_begin,
DavCfgRepository **list_end,
xmlNode *reponode)
{
DavCfgRepository *repo = dav_repository_new(config);
repo->node = reponode;
xmlNode *node = reponode->children;
int ret =
0;
while(node && !ret) {
if(node->type ==
XML_ELEMENT_NODE) {
ret = repo_add_config(config, repo, node);
}
node = node->next;
}
if(ret) {
return 1;
}
else {
cx_linked_list_add(
(
void**)list_begin,
(
void**)list_end,
offsetof(DavCfgRepository, prev),
offsetof(DavCfgRepository, next),
repo);
}
return 0;
}
static xmlNode* addXmlNode(xmlNode *node,
const char *name, cxmutstr content) {
xmlNode *text1 = xmlNewDocText(node->doc,
BAD_CAST "\t\t");
xmlAddChild(node, text1);
cxmutstr ctn = cx_strdup(cx_strcast(content));
xmlNode *newNode = xmlNewChild(node,
NULL,
BAD_CAST name,
BAD_CAST ctn.ptr);
free(ctn.ptr);
xmlNode *text2 = xmlNewDocText(node->doc,
BAD_CAST "\n");
xmlAddChild(node, text2);
return newNode;
}
void dav_config_add_repository(DavConfig *config, DavCfgRepository *repo) {
if(repo->node) {
fprintf(stderr,
"Error: dav_config_add_repository: node already exists\n");
return;
}
xmlNode *repoNode = xmlNewNode(
NULL,
BAD_CAST "repository");
xmlNode *rtext1 = xmlNewDocText(config->doc,
BAD_CAST "\n");
xmlAddChild(repoNode, rtext1);
repo->node = repoNode;
if(repo->name.value.ptr) {
repo->name.node = addXmlNode(repoNode,
"name", repo->name.value);
}
if(repo->url.value.ptr) {
repo->url.node = addXmlNode(repoNode,
"url", repo->url.value);
}
if(repo->user.value.ptr) {
repo->user.node = addXmlNode(repoNode,
"user", repo->user.value);
}
if(repo->password.value.ptr) {
repo->password.node = addXmlNode(repoNode,
"password", repo->password.value);
}
if(repo->stored_user.value.ptr) {
repo->stored_user.node = addXmlNode(repoNode,
"stored-user", repo->stored_user.value);
}
if(repo->default_key.value.ptr) {
repo->default_key.node = addXmlNode(repoNode,
"default-key", repo->default_key.value);
}
if(repo->cert.value.ptr) {
repo->cert.node = addXmlNode(repoNode,
"cert", repo->cert.value);
}
xmlNode *rtext2 = xmlNewDocText(config->doc,
BAD_CAST "\t");
xmlAddChild(repoNode, rtext2);
DavCfgRepository **list_begin = &config->repositories;
cx_linked_list_add(
(
void**)list_begin,
NULL,
offsetof(DavCfgRepository, prev),
offsetof(DavCfgRepository, next),
repo);
xmlNode *xml_root = xmlDocGetRootElement(config->doc);
xmlNode *text1 = xmlNewDocText(config->doc,
BAD_CAST "\n\t");
xmlAddChild(xml_root, text1);
xmlAddChild(xml_root, repoNode);
xmlNode *text2 = xmlNewDocText(config->doc,
BAD_CAST "\n");
xmlAddChild(xml_root, text2);
}
DavCfgRepository* dav_repository_new(DavConfig *config) {
DavCfgRepository *repo = cxMalloc(config->mp->allocator,
sizeof(DavCfgRepository));
memset(repo,
0,
sizeof(DavCfgRepository));
repo->decrypt_name.value = false;
repo->decrypt_content.value = true;
repo->decrypt_properties.value = false;
repo->verification.value = true;
repo->ssl_version.value =
CURL_SSLVERSION_DEFAULT;
repo->authmethods.value =
CURLAUTH_BASIC;
return repo;
}
void dav_repository_free(DavConfig *config, DavCfgRepository *repo) {
}
void dav_repository_remove_and_free(DavConfig *config, DavCfgRepository *repo) {
if(repo->prev) {
repo->prev->next = repo->next;
}
if(repo->next) {
repo->next->prev = repo->prev;
}
if(repo->node) {
xmlUnlinkNode(repo->node);
xmlFreeNode(repo->node);
}
}
int dav_repository_get_flags(DavCfgRepository *repo) {
int flags =
0;
DavBool encrypt_content =
FALSE;
DavBool encrypt_name =
FALSE;
DavBool encrypt_properties =
FALSE;
DavBool decrypt_content =
FALSE;
DavBool decrypt_name =
FALSE;
DavBool decrypt_properties =
FALSE;
if(repo->full_encryption.value) {
encrypt_content =
TRUE;
encrypt_name =
TRUE;
encrypt_properties =
TRUE;
decrypt_content =
TRUE;
decrypt_name =
TRUE;
decrypt_properties =
TRUE;
}
else if(repo->content_encryption.value) {
encrypt_content =
TRUE;
decrypt_content =
TRUE;
}
if(decrypt_content) {
flags |=
DAV_SESSION_DECRYPT_CONTENT;
}
if(decrypt_name) {
flags |=
DAV_SESSION_DECRYPT_NAME;
}
if(decrypt_properties) {
flags |=
DAV_SESSION_DECRYPT_PROPERTIES;
}
if(encrypt_content) {
flags |=
DAV_SESSION_ENCRYPT_CONTENT;
}
if(encrypt_name) {
flags |=
DAV_SESSION_ENCRYPT_NAME;
}
if(encrypt_properties) {
flags |=
DAV_SESSION_ENCRYPT_PROPERTIES;
}
return flags;
}
void dav_repository_set_url(DavConfig *config, DavCfgRepository *repo, cxstring newurl) {
if(repo->url.value.ptr) {
cxFree(config->mp->allocator, repo->url.value.ptr);
}
repo->url.value = cx_strdup_a(config->mp->allocator, newurl);
}
void dav_repository_set_auth(DavConfig *config, DavCfgRepository *repo, cxstring user, cxstring password) {
const CxAllocator *a = config->mp->allocator;
if(user.length >
0) {
repo->user.value = cx_strdup_a(a, user);
}
if(password.length >
0) {
char *pwenc = util_base64encode(password.ptr, password.length);
repo->password.value = cx_strdup_a(a, cx_str(pwenc));
free(pwenc);
}
}
cxmutstr dav_repository_get_decodedpassword(DavCfgRepository *repo) {
cxmutstr pw = {
NULL,
0 };
if(repo->password.value.ptr) {
pw = cx_mutstr(util_base64decode(repo->password.value.ptr));
}
return pw;
}
void dav_config_add_key(DavConfig *config, DavCfgKey *key) {
cx_linked_list_add(
(
void**)&config->keys,
NULL,
offsetof(DavCfgKey, prev),
offsetof(DavCfgKey, next),
key);
if(key->node) {
fprintf(stderr,
"Error: dav_config_add_key: node already exists\n");
return;
}
xmlNode *keyNode = xmlNewNode(
NULL,
BAD_CAST "key");
xmlNode *rtext1 = xmlNewDocText(config->doc,
BAD_CAST "\n");
xmlAddChild(keyNode, rtext1);
key->node = keyNode;
if(key->name.value.ptr) {
key->name.node = addXmlNode(keyNode,
"name", key->name.value);
}
const char *type = dav_config_keytype_str(key->type);
if(type) {
key->type_node = addXmlNode(keyNode,
"type", cx_mutstr((
char*)type));
}
if(key->file.value.ptr) {
key->file.node = addXmlNode(keyNode,
"file", key->file.value);
}
xmlNode *rtext2 = xmlNewDocText(config->doc,
BAD_CAST "\t");
xmlAddChild(keyNode, rtext2);
xmlNode *xml_root = xmlDocGetRootElement(config->doc);
xmlNode *text1 = xmlNewDocText(config->doc,
BAD_CAST "\n\t");
xmlAddChild(xml_root, text1);
xmlAddChild(xml_root, keyNode);
xmlNode *text2 = xmlNewDocText(config->doc,
BAD_CAST "\n");
xmlAddChild(xml_root, text2);
}
DavCfgKey* dav_key_new(DavConfig *config) {
DavCfgKey *key = cxMalloc(config->mp->allocator,
sizeof(DavCfgKey));
memset(key,
0,
sizeof(DavCfgKey));
key->type =
DAV_KEY_TYPE_AES256;
return key;
}
void dav_key_remove_and_free(DavConfig *config, DavCfgKey *key) {
cx_linked_list_remove(
(
void**)&config->keys,
NULL,
offsetof(DavCfgKey, prev),
offsetof(DavCfgKey, next),
key);
if(key->node) {
xmlUnlinkNode(key->node);
xmlFreeNode(key->node);
}
}
static int load_key(
DavConfig *config,
DavCfgKey **list_begin,
DavCfgKey **list_end,
xmlNode *keynode)
{
xmlNode *node = keynode->children;
DavCfgKey *key = cxMalloc(config->mp->allocator,
sizeof(DavCfgKey));
memset(key,
0,
sizeof(DavCfgKey));
key->type =
DAV_KEY_TYPE_AES256;
key->node = keynode;
int error =
0;
while(node) {
if(node->type ==
XML_ELEMENT_NODE) {
if(xstreq(node->name,
"name")) {
dav_cfg_string_set_node_value(config, &key->name, node);
}
else if(xstreq(node->name,
"file")) {
dav_cfg_string_set_node_value(config, &key->file, node);
}
else if(xstreq(node->name,
"type")) {
const char *value = util_xml_get_text(node);
key->type_node = node;
if(!strcmp(value,
"aes128")) {
key->type =
DAV_KEY_TYPE_AES128;
}
else if(!strcmp(value,
"aes256")) {
key->type =
DAV_KEY_TYPE_AES256;
}
else {
print_error(node->line,
"unknown key type %s\n", value);
error =
1;
}
}
else {
key->unknown_elements++;
}
}
node = node->next;
}
if(!key->name.value.ptr) {
error =
1;
}
if(!error) {
error =
0;
size_t expected_length =
0;
if(key->type ==
DAV_KEY_TYPE_AES128) {
expected_length =
16;
}
if(key->type ==
DAV_KEY_TYPE_AES256) {
expected_length =
32;
}
}
if(error) {
return 1;
}
else {
cx_linked_list_add(
(
void**)list_begin,
(
void**)list_end,
offsetof(DavCfgKey, prev),
offsetof(DavCfgKey, next),
key);
return 0;
}
}
static int load_proxy(
DavConfig *config, DavCfgProxy *proxy, xmlNode *proxynode,
int type)
{
const char *stype;
if(type ==
DAV_HTTPS_PROXY) {
stype =
"https";
}
else if(type ==
DAV_HTTP_PROXY) {
stype =
"http";
}
else {
fprintf(stderr,
"unknown proxy type\n");
return 1;
}
if(!proxy) {
fprintf(stderr,
"no memory reserved for %s proxy.\n", stype);
return 1;
}
xmlNode *node = proxynode->children;
int ret =
0;
while(node && !ret) {
if(node->type ==
XML_ELEMENT_NODE) {
int reportmissingvalue =
0;
if(xstreq(node->name,
"url")) {
reportmissingvalue = dav_cfg_string_set_node_value(config, &proxy->url, node);
}
else if(xstreq(node->name,
"user")) {
reportmissingvalue = dav_cfg_string_set_node_value(config, &proxy->user, node);
}
else if(xstreq(node->name,
"password")) {
reportmissingvalue = dav_cfg_string_set_node_value(config, &proxy->password, node);
}
else if(xstreq(node->name,
"no")) {
reportmissingvalue = dav_cfg_string_set_node_value(config, &proxy->noproxy, node);
}
else {
proxy->unknown_elements++;
}
if (reportmissingvalue) {
print_error(node->line,
"missing value for proxy configuration element: %s\n",
node->name);
ret =
1;
break;
}
}
node = node->next;
}
if(!ret && !proxy->url.value.ptr) {
print_error(proxynode->line,
"missing url for %s proxy.\n", stype);
return 1;
}
return ret;
}
static char* get_attr_content(xmlNode *node) {
while(node) {
if(node->type ==
XML_TEXT_NODE) {
return (
char*)node->content;
}
node = node->next;
}
return NULL;
}
static int load_namespace(
DavConfig *config,
DavCfgNamespace **list_begin,
DavCfgNamespace **list_end,
xmlNode *node)
{
const char *prefix =
NULL;
const char *uri =
NULL;
xmlAttr *attr = node->properties;
while(attr) {
if(attr->type ==
XML_ATTRIBUTE_NODE) {
char *value = get_attr_content(attr->children);
if(!value) {
print_error(
node->line,
"missing value for attribute %s\n", (
char*)attr->name);
return 1;
}
if(xstreq(attr->name,
"prefix")) {
prefix = value;
}
else if(xstreq(attr->name,
"uri")) {
uri = value;
}
else {
print_error(
node->line,
"unexpected attribute %s\n", (
char*)attr->name);
return 1;
}
}
attr = attr->next;
}
if(!prefix) {
print_error(node->line,
"missing prefix attribute\n");
return 1;
}
if(!uri) {
print_error(node->line,
"missing uri attribute\n");
return 1;
}
DavCfgNamespace *ns = cxMalloc(config->mp->allocator,
sizeof(DavCfgNamespace));
memset(ns,
0,
sizeof(DavCfgNamespace));
ns->node = node;
ns->prefix = cx_strdup_a(config->mp->allocator, cx_str(prefix));
ns->uri = cx_strdup_a(config->mp->allocator, cx_str(uri));
cx_linked_list_add(
(
void**)list_begin,
(
void**)list_end,
offsetof(DavCfgNamespace, prev),
offsetof(DavCfgNamespace, next),
ns);
return 0;
}
static int load_secretstore(DavConfig *config, xmlNode *node) {
if(config->secretstore) {
return 1;
}
config->secretstore = cxCalloc(config->mp->allocator,
1,
sizeof(DavCfgSecretStore));
node = node->children;
int error =
0;
while(node) {
if(node->type ==
XML_ELEMENT_NODE) {
if(xstreq(node->name,
"unlock-command")) {
dav_cfg_string_set_node_value(config, &config->secretstore->unlock_cmd, node);
}
else if(xstreq(node->name,
"lock-command")) {
dav_cfg_string_set_node_value(config, &config->secretstore->lock_cmd, node);
}
}
node = node->next;
}
return error;
}
DavCfgRepository* dav_config_get_repository(DavConfig *config, cxstring name) {
if(!config) {
return NULL;
}
DavCfgRepository *repo = config->repositories;
while(repo) {
if(!cx_strcmp(cx_strcast(repo->name.value), name)) {
return repo;
}
repo = repo->next;
}
return NULL;
}
DavCfgRepository* dav_config_url2repo(DavConfig *config,
const char *url,
char **path) {
cxmutstr p;
DavCfgRepository *repo = dav_config_url2repo_s(config, cx_str(url), &p);
*path = p.ptr;
return repo;
}
DavCfgRepository* dav_config_url2repo_s(DavConfig *config, cxstring url, cxmutstr *path) {
path->ptr =
NULL;
path->length =
0;
int s;
if(cx_strprefix(url,
CX_STR(
"http://"))) {
s =
7;
}
else if(cx_strprefix(url,
CX_STR(
"https://"))) {
s =
8;
}
else {
s =
1;
}
cxstring r = cx_strsubs(url, s);
cxstring p = cx_strchr(r,
'/');
r = cx_strsubsl(url,
0, url.length-p.length);
if(p.length ==
0) {
p = cx_strn(
"/",
1);
}
DavCfgRepository *repo = dav_config_get_repository(config, r);
if(repo) {
*path = cx_strdup(p);
}
else {
repo = dav_repository_new(config);
repo->name.value = cx_strdup_a(config->mp->allocator,
CX_STR(
""));
if(url.ptr[url.length-
1] ==
'/') {
repo->url.value = cx_strdup_a(config->mp->allocator, url);
*path = cx_strdup(
CX_STR(
"/"));
}
else if (cx_strchr(url,
'/').length >
0) {
cxstring repo_url = util_url_base_s(url);
repo->url.value = cx_strdup_a(config->mp->allocator, repo_url);
*path = cx_strdup(util_url_path_s(url));
}
else {
repo->url.value = cx_strdup(url);
*path = cx_strdup(
CX_STR(
"/"));
}
}
return repo;
}
int dav_config_keytype(DavCfgKeyType type) {
switch(type) {
default:
break;
case DAV_KEY_TYPE_AES256:
return DAV_KEY_AES256;
case DAV_KEY_TYPE_AES128:
return DAV_KEY_AES128;
}
return 0;
}
const char* dav_config_keytype_str(DavCfgKeyType type) {
switch(type) {
default:
break;
case DAV_KEY_TYPE_AES256:
return "aes256";
case DAV_KEY_TYPE_AES128:
return "aes128";
}
return NULL;
}
int dav_config_register_keys(DavConfig *config, DavContext *ctx, dav_loadkeyfile_func loadkey) {
for(DavCfgKey *key=config->keys;key;key=key->next) {
char *file = cx_strdup_m(key->file.value).ptr;
cxmutstr keycontent = loadkey(file);
free(file);
if(!keycontent.ptr) {
return 1;
}
DavKey *davkey = calloc(
1,
sizeof(DavKey));
davkey->name = cx_strdup_m(key->name.value).ptr;
davkey->type = dav_config_keytype(key->type);
davkey->data = keycontent.ptr;
davkey->length = keycontent.length;
dav_context_add_key(ctx, davkey);
}
return 0;
}
int dav_config_register_namespaces(DavConfig *config, DavContext *ctx) {
DavCfgNamespace *ns = config->namespaces;
while(ns) {
dav_add_namespace(ctx, ns->prefix.ptr, ns->uri.ptr);
ns = ns->next;
}
return 0;
}