Sun, 04 Feb 2018 11:14:20 +0100
adds tag conflict detection for dav-sync push
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2018 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 <ucx/string.h> #include <ucx/utils.h> #include "libxattr.h" #include "tags.h" #ifdef __APPLE__ #include <CoreFoundation/CoreFoundation.h> #endif UcxList* parse_text_taglist(const char *buf, size_t length) { UcxList *tags = NULL; int line_start = 0; for(int i=0;i<length;i++) { if(buf[i] == '\n' || i == length-1) { sstr_t line = sstrtrim(sstrn((char*)buf + line_start, i - line_start)); if(line.length > 0) { DavTag *tag = calloc(1, sizeof(DavTag)); tag->name = sstrdup(line).ptr; tag->color = NULL; tags = ucx_list_append(tags, tag); } line_start = i+1; } } return tags; } UcxBuffer* create_text_taglist(UcxList *tags) { if(!tags) { return NULL; } UcxBuffer *buf = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND); UCX_FOREACH(elm, tags) { DavTag *tag = elm->data; ucx_bprintf(buf, "%s\n", tag->name); } return buf; } UcxList* parse_csv_taglist(const char *buf, size_t length) { UcxList *taglist = NULL; sstr_t str = sstrn((char*)buf, length); ssize_t count = 0; sstr_t *tags = sstrsplit(str, S(","), &count); for(int i=0;i<count;i++) { DavTag *tag = malloc(sizeof(DavTag)); tag->name = sstrdup(sstrtrim(tags[i])).ptr; tag->color = NULL; taglist = ucx_list_append(taglist, tag); free(tags[i].ptr); } if(tags) { free(tags); } return taglist; } UcxBuffer* create_csv_taglist(UcxList *tags) { UcxBuffer *buf = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND); int insertsep = 0; UCX_FOREACH(elm, tags) { DavTag *tag = elm->data; if(insertsep) { ucx_buffer_putc(buf, ','); } ucx_buffer_puts(buf, tag->name); insertsep = 1; } return buf; } static DavTag* parse_xml_dav_tag(DavXmlNode *node) { char *name = NULL; DavXmlNode *c = node->children; while(c) { if(c->type == DAV_XML_ELEMENT) { char *value = dav_xml_getstring(c->children); if(value) { if(!strcmp(c->namespace, DAV_NS)) { if(!strcmp(c->name, "name")) { char *value = dav_xml_getstring(c->children); if(value) { name = value; } } // TODO: color, ... } } } c = c->next; } DavTag *tag = NULL; if(name) { tag = malloc(sizeof(DavTag)); tag->name = strdup(name); tag->color = NULL; } return tag; } UcxList* parse_dav_xml_taglist(DavXmlNode *taglistnode) { UcxList *tags = NULL; DavXmlNode *node = taglistnode; while(node) { if(node->type == DAV_XML_ELEMENT) { if(!strcmp(node->namespace, DAV_NS) && !strcmp(node->name, "tag")) { DavTag *tag = parse_xml_dav_tag(node); if(tag) { tags = ucx_list_append(tags, tag); } } } node = node->next; } return tags; } DavXmlNode* create_xml_taglist(UcxList *tags) { DavXmlNode *tag1 = NULL; DavXmlNode *lasttag = NULL; UCX_FOREACH(elm, tags) { DavTag *tag = elm->data; DavXmlNode *tagelm = dav_xml_createnode(DAV_NS, "tag"); DavXmlNode *tagname = dav_xml_createnode_with_text(DAV_NS, "name", tag->name); // TODO: color tagelm->children = tagname; if(lasttag) { lasttag->next = tagelm; tagelm->prev = lasttag; } else { tag1 = tagelm; } lasttag = tagelm; } return tag1; } #ifdef __APPLE__ static DavTag* tagstr2davtag(const char *str) { const char *name = str; const char *color = NULL; size_t len = strlen(str); size_t namelen = len; if(len == 0) { return NULL; } // start with 1 because the first char should not be a linebreak for(int i=1;i<len;i++) { if(str[i] == '\n') { if(!color) { color = str + i + 1; namelen = i; } } } int colorlen = len - namelen - 1; DavTag *tag = malloc(sizeof(DavTag)); tag = malloc(sizeof(DavTag)); tag->name = malloc(namelen + 1); memcpy(tag->name, name, namelen); tag->name[namelen] = 0; if(colorlen > 0) { tag->color = malloc(colorlen + 1); memcpy(tag->color, color, colorlen); tag->color[colorlen] = 0; } else { tag->color = NULL; } return tag; } UcxList* parse_macos_taglist(const char *buf, size_t length) { UcxList *taglist = NULL; CFDataRef data = CFDataCreateWithBytesNoCopy( kCFAllocatorDefault, (const UInt8*)buf, length, kCFAllocatorNull); CFPropertyListRef propertylist = CFPropertyListCreateWithData(kCFAllocatorDefault, data, 0, NULL, NULL); CFArrayRef array = propertylist; int count = CFArrayGetCount(array); for(int i=0;i<count;i++) { CFStringRef str = CFArrayGetValueAtIndex(array, i); int slen = CFStringGetLength(str); size_t cstrbuflen = slen * 4 + 4; char *cstr = malloc(cstrbuflen); if(CFStringGetCString(str, cstr, cstrbuflen, kCFStringEncodingUTF8)) { DavTag *tag = tagstr2davtag(cstr); if(tag) { taglist = ucx_list_append(taglist, tag); } } free(cstr); } CFRelease(propertylist); CFRelease(data); return taglist; } UcxBuffer* create_macos_taglist(UcxList *tags) { size_t count = ucx_list_size(tags); if(count == 0) { return NULL; } CFStringRef *strings = calloc(sizeof(CFStringRef), count); int i = 0; UCX_FOREACH(elm, tags) { DavTag *tag = elm->data; CFStringRef str = NULL; if(tag->color) { sstr_t s = sstrcat(3, sstr(tag->name), S("\n"), sstr(tag->color)); str = CFStringCreateWithCString(kCFAllocatorDefault, s.ptr, kCFStringEncodingUTF8); free(s.ptr); } else { str = CFStringCreateWithCString(kCFAllocatorDefault, tag->name, kCFStringEncodingUTF8); } strings[i] = str; i++; } CFPropertyListRef array = CFArrayCreate(kCFAllocatorDefault, (const void**)strings, count, &kCFTypeArrayCallBacks); CFDataRef data = CFPropertyListCreateData(kCFAllocatorDefault, array, kCFPropertyListBinaryFormat_v1_0, 0, NULL); UcxBuffer *buf = NULL; if(data) { int datalen = CFDataGetLength(data); CFRange range; range.location = 0; range.length = datalen; buf = ucx_buffer_new(NULL, datalen, 0); CFDataGetBytes(data, range, (UInt8*)buf->space); buf->size = datalen; CFRelease(data); } for(int i=0;i<count;i++) { CFRelease(strings[i]); } CFRelease(array); return buf; } #else UcxList* parse_macos_taglist(const char *buf, size_t length) { return NULL; } UcxBuffer* create_macos_taglist(UcxList *tags) { return NULL; } #endif