added new sync tool

Fri, 13 Jun 2014 13:52:59 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 13 Jun 2014 13:52:59 +0200
changeset 46
0542668d0f26
parent 45
e3839719b079
child 47
fbbbeed4ba8f

added new sync tool

dav/Makefile file | annotate | diff | comparison | revisions
dav/db.c file | annotate | diff | comparison | revisions
dav/db.h file | annotate | diff | comparison | revisions
dav/main.c file | annotate | diff | comparison | revisions
dav/scfg.c file | annotate | diff | comparison | revisions
dav/scfg.h file | annotate | diff | comparison | revisions
dav/sopt.c file | annotate | diff | comparison | revisions
dav/sopt.h file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
dav/sync.h file | annotate | diff | comparison | revisions
libidav/webdav.c file | annotate | diff | comparison | revisions
--- a/dav/Makefile	Thu Jun 05 16:53:53 2014 +0200
+++ b/dav/Makefile	Fri Jun 13 13:52:59 2014 +0200
@@ -28,17 +28,29 @@
 
 include ../$(CONF).mk
 
-SRC  = main.c
-SRC += config.c
-SRC += optparser.c
+DAV_SRC  = main.c
+DAV_SRC += config.c
+DAV_SRC += optparser.c
+
+SYNC_SRC = sync.c
+SYNC_SRC += config.c
+SYNC_SRC += scfg.c
+SYNC_SRC += sopt.c
+SYNC_SRC += db.c
 
 
-OBJ = $(SRC:%.c=../build/tool/%.$(OBJ_EXT))
+DAV_OBJ = $(DAV_SRC:%.c=../build/tool/%.$(OBJ_EXT))
+SYNC_OBJ = $(SYNC_SRC:%.c=../build/tool/%.$(OBJ_EXT))
+
+all: ../build/dav ../build/dav-sync
 
-all: ../build/dav
+../build/dav: $(DAV_OBJ) ../build/libidav.$(LIB_EXT)
+	$(LD) -o ../build/dav$(APP_EXT) $(DAV_OBJ) \
+		../build/libidav.$(LIB_EXT) ../build/libucx.$(LIB_EXT)  \
+		$(LDFLAGS) $(DAV_LDFLAGS)
 
-../build/dav: $(OBJ)
-	$(LD) -o ../build/dav$(APP_EXT) $(OBJ) \
+../build/dav-sync: $(SYNC_OBJ) ../build/libidav.$(LIB_EXT)
+	$(LD) -o ../build/dav-sync$(APP_EXT) $(SYNC_OBJ) \
 		../build/libidav.$(LIB_EXT) ../build/libucx.$(LIB_EXT)  \
 		$(LDFLAGS) $(DAV_LDFLAGS)
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/db.c	Fri Jun 13 13:52:59 2014 +0200
@@ -0,0 +1,146 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db.h"
+
+#include <libidav/utils.h>
+
+
+#define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b)
+
+#ifdef _WIN32
+#define ENV_HOME getenv("USERPROFILE")
+#else
+#define ENV_HOME getenv("HOME")
+#endif /* _WIN32 */
+
+UcxMap* load_db(char *name) {
+    char *dav_dir = util_concat_path(ENV_HOME, ".dav");
+    char *db_file = util_concat_path(dav_dir, name);
+    free(dav_dir);
+    
+    xmlTextReaderPtr reader = xmlReaderForFile(db_file, NULL, 0);
+    if(!reader) {
+        fprintf(stderr, "Cannot open database file: %s\n", db_file);
+        free(db_file);
+        return NULL;
+    }
+    free(db_file);
+    
+    UcxMap *map = ucx_map_new(2048);
+    int error = 0;
+    while(xmlTextReaderRead(reader)) {
+        int type = xmlTextReaderNodeType(reader);
+        const xmlChar *name = xmlTextReaderConstName(reader);
+        
+        if(type == XML_READER_TYPE_ELEMENT) {
+            if(xstreq(name, "resource")) {
+                LocalResource *res = process_resource(reader);
+                if(res) {
+                    ucx_map_cstr_put(map, res->path, res);
+                } else {
+                    error = 1;
+                    break;
+                }
+            }
+        }
+    }
+    
+    xmlFreeTextReader(reader);
+    if(error) {
+        // TODO: free resources and map
+        return NULL;
+    } else {
+        return map;
+    }
+}
+
+LocalResource* process_resource(xmlTextReaderPtr reader) {
+    LocalResource *res = calloc(1, sizeof(LocalResource));
+    
+    int field = -1;
+    while(xmlTextReaderRead(reader)) {
+        int type = xmlTextReaderNodeType(reader);
+        const xmlChar *name = xmlTextReaderConstName(reader);
+        
+        if(type == XML_READER_TYPE_ELEMENT) {
+            if(xstreq(name, "path")) {
+                field = 0;
+            } else if(xstreq(name, "etag")) {
+                field = 1;
+            } else if(xstreq(name, "lastmodified")) {
+                field = 2;
+            } else if(xstreq(name, "size")) {
+                field = 3;
+            }
+        } else if(type == XML_READER_TYPE_TEXT) {
+            const xmlChar *value = xmlTextReaderConstValue(reader);
+            int b = 0;
+            switch(field) {
+                case 0: {
+                    res->name = strdup((char*)value);
+                    break;
+                }
+                case 1: {
+                    res->etag = strdup((char*)value);
+                    break;
+                }
+                case 2: {
+                    res->last_modified = util_parse_lastmodified((char*)value);
+                    break;
+                }
+                case 3: {
+                    res->size = atoi((char*)value);
+                    break;
+                }
+            }
+        } else if(XML_READER_TYPE_END_ELEMENT) {
+            if(xstreq(name, "resource")) {
+                break;
+            } else {
+                field = -1;
+            }
+        }
+    }
+    
+    if(!res->name || !res->path || res->last_modified == 0) {
+        // TODO: free res
+        return NULL;
+    } else {
+        return res;
+    }
+}
+
+int store_db(UcxMap *db, char *name) {
+    // TODO:
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/db.h	Fri Jun 13 13:52:59 2014 +0200
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DB_H
+#define	DB_H
+
+#include <libidav/webdav.h>
+#include <ucx/map.h>
+#include <time.h>
+
+#include <libxml/xmlreader.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct LocalResource LocalResource;    
+
+struct LocalResource {
+    char    *name;
+    char    *path;
+    char    *etag;
+    time_t last_modified;
+    off_t  size;
+};
+
+UcxMap* load_db(char *name);
+int store_db(UcxMap *db, char *name);
+
+LocalResource* process_resource(xmlTextReaderPtr reader);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* DB_H */
+
--- a/dav/main.c	Thu Jun 05 16:53:53 2014 +0200
+++ b/dav/main.c	Fri Jun 13 13:52:59 2014 +0200
@@ -45,7 +45,7 @@
 
 static DavContext *ctx;
 
-void xmlerrorfnc(void * c, const char * msg, ... ) {
+static void xmlerrorfnc(void * c, const char * msg, ... ) {
     // nothing
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/scfg.c	Fri Jun 13 13:52:59 2014 +0200
@@ -0,0 +1,151 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libidav/utils.h>
+#include <ucx/map.h>
+
+#include "scfg.h"
+
+#define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b)
+
+#ifdef _WIN32
+#define ENV_HOME getenv("USERPROFILE")
+#else
+#define ENV_HOME getenv("HOME")
+#endif /* _WIN32 */
+
+static UcxMap *directories;
+
+int load_sync_config() {
+    char *file = util_concat_path(ENV_HOME, ".dav/sync.xml");
+    xmlDoc *doc = xmlReadFile(file, NULL, 0);
+    if(!doc) {
+        fprintf(stderr, "Missing configuration file\n");
+        scfg_print_example();
+        return -1;
+    }
+    
+    directories = ucx_map_new(8);
+    
+    int ret = 0;
+    xmlNode *node = xmlDocGetRootElement(doc)->children;
+    while(node) {
+        if(node->type == XML_ELEMENT_NODE) {
+            if(xstreq(node->name, "directory")) {
+                if(scfg_load_directory(node)) {
+                    ret = 1;
+                    ucx_map_free(directories);
+                    break;
+                }
+            }
+        }
+        node = node->next;
+    }
+    
+    xmlFreeDoc(doc);
+    
+    return ret;
+}
+
+int scfg_load_directory(xmlNode *node) {
+    char *name = NULL;
+    char *path = NULL;
+    char *repository = NULL;
+    char *database = NULL;
+    
+    node = node->children;
+    while(node) {
+        if(node->type == XML_ELEMENT_NODE) {
+            char *value = util_xml_get_text(node);
+            if(!value) {
+                // next
+            } else if(xstreq(node->name, "name")) {
+                name = value;
+            } else if(xstreq(node->name, "path")) {
+                path = value;
+            } else if(xstreq(node->name, "repository")) {
+                repository = value;
+            } else if(xstreq(node->name, "database")) {
+                database = value;
+            }
+        }
+        node = node->next;
+    }
+    
+    if(!name) {
+        fprintf(stderr, "Missing name element for directory\n");
+        return -1;
+    }
+    if(!path) {
+        fprintf(stderr, "Missing path element for directory\n");
+        return -1;
+    }
+    if(!repository) {
+        fprintf(stderr, "Missing repository element for directory\n");
+        return -1;
+    }
+    if(!database) {
+        fprintf(stderr, "Missing database element for directory\n");
+        return -1;
+    }
+    
+    SyncDirectory *dir = malloc(sizeof(SyncDirectory));
+    dir->name = strdup(name);
+    dir->path = strdup(path);
+    dir->repository = strdup(repository);
+    dir->database = strdup(database);
+    
+    ucx_map_cstr_put(directories, name, dir);
+    
+    return 0;
+}
+
+void scfg_print_example() {
+    fprintf(stderr, "example sync.xml\n\n");
+    fprintf(stderr, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
+    fprintf(stderr, "<configuration>\n");
+    fprintf(stderr, "  <directory>\n");
+    fprintf(stderr, "    <!-- identifier -->\n");
+    fprintf(stderr, "    <name>documents</name>\n\n");
+    fprintf(stderr, "    <!-- local path to the directory -->\n");
+    fprintf(stderr, "    <path>/home/user/Documents</path>\n\n");
+    fprintf(stderr, "    <!-- repository name specified in config.xml -->\n");
+    fprintf(stderr, "    <repository>server</repository>\n\n");
+    fprintf(stderr, "    <!-- database file name -->\n");
+    fprintf(stderr, "    <database>documents.db</database>\n");
+    fprintf(stderr, "  </directory>\n");
+    fprintf(stderr, "</configuration>\n");
+}
+
+SyncDirectory* scfg_get_dir(char *name) {
+    return ucx_map_cstr_get(directories, name);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/scfg.h	Fri Jun 13 13:52:59 2014 +0200
@@ -0,0 +1,61 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SCFG_H
+#define	SCFG_H
+
+#include <ucx/string.h>
+#include <stdbool.h>
+#include <libidav/webdav.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct SyncDirectory {
+    char *name;
+    char *path;
+    char *repository;
+    char *database;
+} SyncDirectory;
+
+int load_sync_config();
+
+int scfg_load_directory(xmlNode *node);
+
+void scfg_print_example();
+
+SyncDirectory* scfg_get_dir(char *name);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* SCFG_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/sopt.c	Fri Jun 13 13:52:59 2014 +0200
@@ -0,0 +1,140 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "optparser.h"
+
+void cmd_args_free(CmdArgs *args) {
+    ucx_map_free(args->options);
+    free(args->argv);
+}
+
+CmdArgs* cmd_parse_args(int argc, char **argv) {
+    CmdArgs *a = malloc(sizeof(CmdArgs));
+    a->options = ucx_map_new(16);
+    a->argv = calloc(argc, sizeof(char*));
+    a->argc = 0;
+    
+    char *option = NULL;
+    char optchar = 0;
+    for(int i=0;i<argc;i++) {
+        char *arg = argv[i];
+        size_t len = strlen(arg);
+        if(len > 1 && arg[0] == '-') {
+            for(int c=1;c<len;c++) {
+                switch(arg[c]) {
+                    default: {
+                        fprintf(stderr, "Unknown option -%c", arg[c]);
+                        cmd_args_free(a);
+                        return NULL;
+                    }
+                    case 'k': {
+                        if(!option) {
+                            option = "key";
+                            optchar = 'k';
+                        } else {
+                            fprintf(
+                                    stderr,
+                                    "Missing argument for option -%c\n",
+                                    optchar);
+                            cmd_args_free(a);
+                            return NULL;
+                        }
+                        break;
+                    }
+                    case 'p': {
+                        ucx_map_cstr_put(a->options, "plain", "");
+                        break;
+                    }
+                    case 'c': {
+                        ucx_map_cstr_put(a->options, "crypt", "");
+                        break;
+                    }
+                    case 'a': {
+                        ucx_map_cstr_put(a->options, "all", "");
+                        break;
+                    }
+                    case 'l': {
+                        ucx_map_cstr_put(a->options, "list", "");
+                        break;
+                    }
+                    case 't': {
+                        ucx_map_cstr_put(a->options, "type", "");
+                        break;
+                    }
+                    case 'R': {
+                        ucx_map_cstr_put(a->options, "recursive", "");
+                        break;
+                    }
+                    case 'o': {
+                        if(!option) {
+                            option = "output";
+                            optchar = 'o';
+                        } else {
+                            fprintf(
+                                    stderr,
+                                    "Missing argument for option -%c\n",
+                                    optchar);
+                            cmd_args_free(a);
+                            return NULL;
+                        }
+                        break;
+                    }
+                    case 'u': {
+                        if(!option) {
+                            option = "update";
+                            optchar = 'u';
+                        } else {
+                            fprintf(
+                                    stderr,
+                                    "Missing argument for option -%c\n",
+                                    optchar);
+                            cmd_args_free(a);
+                            return NULL;
+                        }
+                        break;
+                    }
+                }
+            }
+        } else if(option) {
+            ucx_map_cstr_put(a->options, option, arg);
+            option = NULL;
+        } else {
+            a->argv[a->argc++] = arg;
+        }
+    }
+    
+    return a;
+}
+
+char* cmd_getoption(CmdArgs *arg, char *name) {
+    return ucx_map_cstr_get(arg->options, name);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/sopt.h	Fri Jun 13 13:52:59 2014 +0200
@@ -0,0 +1,52 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef OPTPARSER_H
+#define	OPTPARSER_H
+
+#include <ucx/map.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+    UcxMap *options;
+    char   **argv;
+    int    argc;
+} CmdArgs;
+
+CmdArgs* cmd_parse_args(int argc, char **argv);
+char* cmd_getoption(CmdArgs *arg, char *name);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* OPTPARSER_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/sync.c	Fri Jun 13 13:52:59 2014 +0200
@@ -0,0 +1,211 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <libxml/xmlerror.h>
+#include <sys/types.h>
+#include <ucx/string.h>
+#include <dirent.h>
+
+#include <libidav/webdav.h>
+#include <libidav/utils.h>
+
+#include "config.h"
+#include "scfg.h"
+#include "sopt.h"
+#include "db.h"
+
+#include "sync.h"
+
+static DavContext *ctx;
+
+static void xmlerrorfnc(void * c, const char * msg, ... ) {
+    // nothing
+}
+
+int main(int argc, char **argv) {
+    if(argc < 2) {
+        fprintf(stderr, "Missing command\n");
+        print_usage(argv[0]);
+        return -1;
+    }
+    
+    char *cmd = argv[1];
+    CmdArgs *args = cmd_parse_args(argc - 2, argv + 2);
+    if(!args) {
+        print_usage(argv[0]);
+        return -1;
+    }
+    
+    xmlGenericErrorFunc fnc = xmlerrorfnc;
+    initGenericErrorDefaultFunc(&fnc);
+    ctx = dav_context_new();
+    load_config(ctx);
+    if(load_sync_config()) {
+        return EXIT_FAILURE;
+    }
+    
+    int ret = EXIT_FAILURE;
+    if(!strcmp(cmd, "pull")) {
+        ret = cmd_pull(args);
+    } else if(!strcmp(cmd, "push")) {
+        ret = cmd_pull(args);
+    } else if(!strcmp(cmd, "sync")) {
+        ret = cmd_sync(args);
+    }
+    
+    return ret;
+}
+
+void print_usage(char *cmd) {
+    
+}
+
+int cmd_pull(CmdArgs *a) {
+    if(a->argc != 1) {
+        fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many");
+        return -1;
+    }
+    
+    SyncDirectory *dir = scfg_get_dir(a->argv[0]);
+    if(!dir) {
+        fprintf(stderr, "Unknown sync dir: %s\n", a->argv[0]);
+        return -1;
+    }
+    
+    Repository *repo = get_repository(sstr(dir->repository));
+    if(!repo) {
+        fprintf(stderr, "Unkown repository %s\n", dir->name);
+        return -1;
+    }
+    
+    UcxMap *db = load_db(dir->database);
+    if(!db) {
+        fprintf(stderr, "Cannot load database file: %s\n", dir->database);
+        return -1;
+    }
+    
+    DavSession *sn = dav_session_new_auth(
+            ctx,
+            repo->url,
+            repo->user,
+            repo->password);
+    dav_session_set_flags(sn, get_repository_flags(repo));
+    sn->key = dav_context_get_key(ctx, repo->default_key);
+    
+    DavResource *ls = dav_query(sn, "get D:getetag from / where lastmodified > 0 with depth -1");
+    if(!ls) {
+        fprintf(stderr, "Error\n");
+        // TODO: free
+        return -1;
+    }
+    
+    if(!ls->children) {
+        // TODO: free
+        return 0; // empty repository
+    }
+    
+    UcxList *stack = ucx_list_prepend(NULL, ls->children);
+    while(stack) {
+        DavResource *res = stack->data;
+        stack = ucx_list_remove(stack, stack);
+        
+        while(res) {
+            if(sync_get_resource(dir, res, db)) {
+                fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path);
+            }
+            
+            if(res->children) {
+                stack = ucx_list_prepend(stack, res->children);
+            }
+            res = res->next;
+        }
+    }
+    
+    // store db
+    
+    
+    return 0;
+}
+
+int sync_get_resource(SyncDirectory *dir, DavResource *res, UcxMap *db) {
+    LocalResource *local = ucx_map_cstr_get(db, res->path);
+    char *etag = dav_get_property(res, "D:getetag");
+    if(local) {
+        if(local->etag && !strcmp(etag, local->etag)) {
+            // resource is already up-to-date on the client
+            return 0;
+        }
+    }
+    
+    char *local_path = util_concat_path(dir->path, res->path);
+    int ret = 0;
+    if(res->iscollection) {
+        mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+        printf("mkdir %s\n", local_path);
+        if(util_mkdir(local_path, mode) && errno != EEXIST) {
+            ret = -1;
+        }
+    } else {
+        FILE *out = fopen(local_path, "w");
+        if(!out) {
+            fprintf(stderr, "cannot open output file: %s\n", local_path);
+            free(local_path);
+            return -1;
+        }
+        printf("get %s\n", res->path);
+        if(dav_get_content(res, out, (dav_write_func)fwrite)) {
+            ret = -1;
+        } else {
+            if(local) {
+                if(local->etag) {
+                    free(local->etag);
+                }
+                local->etag = etag;
+            }
+        }
+        fclose(out);
+    }
+    
+    free(local_path);
+    return ret;
+}
+
+int cmd_push(CmdArgs *a) {
+    return 0;
+}
+
+int cmd_sync(CmdArgs *a) {
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dav/sync.h	Fri Jun 13 13:52:59 2014 +0200
@@ -0,0 +1,55 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2013 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SYNC_H
+#define	SYNC_H
+
+#include <curl/curl.h>
+#include <libidav/webdav.h>
+
+#include "sopt.h"
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+void print_usage(char *cmd);
+
+int cmd_pull(CmdArgs *args);
+int cmd_push(CmdArgs *args);
+int cmd_sync(CmdArgs *args);
+
+int sync_get_resource(SyncDirectory *dir, DavResource *res, UcxMap *db);
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* SYNC_H */
+
--- a/libidav/webdav.c	Thu Jun 05 16:53:53 2014 +0200
+++ b/libidav/webdav.c	Fri Jun 13 13:52:59 2014 +0200
@@ -237,7 +237,7 @@
 
 DavResource* dav_query_get(DavSession *sn, DavGetQuery *query) {
     char *path;
-    int depth = 0;
+    int depth = query->depth;
     /*
     if(parse_path_query(query->from, &path, &depth)) {
         sn->error = DAV_ERROR;
@@ -266,7 +266,6 @@
         dav_resource_free(resource);
         resource = NULL;
     }
-    ucx_buffer_free(rqbuf);
     
     int error = 0;
     if(resource && depth == -1) {
@@ -284,6 +283,8 @@
             stack = propfind_stack_push(stack, sr->children); // add children
         }
     }
+    
+    ucx_buffer_free(rqbuf);
     return resource;
 }
 

mercurial