/* -*- Mode: C -*- ====================================================================== FILE: icalfileset.c CREATOR: eric 23 December 1999 $Id$ $Locker$ (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org This program is free software; you can redistribute it and/or modify it under the terms of either: The LGPL as published by the Free Software Foundation, version 2.1, available at: http://www.fsf.org/copyleft/lesser.html Or: The Mozilla Public License Version 1.0. You may obtain a copy of the License at http://www.mozilla.org/MPL/ The Original Code is eric. The Initial Developer of the Original Code is Eric Busboom ======================================================================*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include /* For open() flags and mode */ #include /* For open() flags and mode */ #include /* For open() flags and mode */ #include "icalfileset.h" #include "icalfilesetimpl.h" // Eugen C. #include // int snprintf(char *str, size_t n, char const *fmt, ...); //extern int errno; int icalfileset_lock(icalfileset *cluster); int icalfileset_unlock(icalfileset *cluster); icalerrorenum icalfileset_read_file(icalfileset* cluster, mode_t mode); int icalfileset_filesize(icalfileset* cluster); icalerrorenum icalfileset_create_cluster(const char *path); icalfileset* icalfileset_new_impl() { struct icalfileset_impl* impl; if ( ( impl = (struct icalfileset_impl*) malloc(sizeof(struct icalfileset_impl))) == 0) { icalerror_set_errno(ICAL_NEWFAILED_ERROR); errno = ENOMEM; return 0; } memset(impl,0,sizeof(struct icalfileset_impl)); strcpy(impl->id,ICALFILESET_ID); return impl; } icalfileset* icalfileset_new(const char* path) { return icalfileset_new_open(path, O_RDWR|O_CREAT, 0664); } icalfileset* icalfileset_new_open(const char* path, int flags, mode_t mode) { struct icalfileset_impl *impl = icalfileset_new_impl(); struct icaltimetype tt; off_t cluster_file_size; memset(&tt,0,sizeof(struct icaltimetype)); icalerror_clear_errno(); icalerror_check_arg_rz( (path!=0), "path"); if (impl == 0){ return 0; } impl->path = strdup(path); cluster_file_size = icalfileset_filesize(impl); if(cluster_file_size < 0){ icalfileset_free(impl); return 0; } impl->fd = open(impl->path,flags, mode); if (impl->fd < 0){ icalerror_set_errno(ICAL_FILE_ERROR); icalfileset_free(impl); return 0; } icalfileset_lock(impl); if(cluster_file_size > 0 ){ icalerrorenum error; if((error = icalfileset_read_file(impl,mode))!= ICAL_NO_ERROR){ icalfileset_free(impl); return 0; } } if(impl->cluster == 0){ impl->cluster = icalcomponent_new(ICAL_XROOT_COMPONENT); } return impl; } char* icalfileset_read_from_file(char *s, size_t size, void *d) { char* p = s; int fd = (int)d; /* Simulate fgets -- read single characters and stop at '\n' */ for(p=s; pfd); impl->cluster = icalparser_parse(parser,icalfileset_read_from_file); icalparser_free(parser); if (impl->cluster == 0 || icalerrno != ICAL_NO_ERROR){ icalerror_set_errno(ICAL_PARSE_ERROR); return ICAL_PARSE_ERROR; } if (icalcomponent_isa(impl->cluster) != ICAL_XROOT_COMPONENT){ /* The parser got a single component, so it did not put it in an XROOT. */ icalcomponent *cl = impl->cluster; impl->cluster = icalcomponent_new(ICAL_XROOT_COMPONENT); icalcomponent_add_component(impl->cluster,cl); } return ICAL_NO_ERROR; } int icalfileset_filesize(icalfileset* cluster) { struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; int cluster_file_size; struct stat sbuf; if (stat(impl->path,&sbuf) != 0){ /* A file by the given name does not exist, or there was another error */ cluster_file_size = 0; if (errno == ENOENT) { /* It was because the file does not exist */ return 0; } else { /* It was because of another error */ icalerror_set_errno(ICAL_FILE_ERROR); return -1; } } else { /* A file by the given name exists, but is it a regular file? */ #ifndef _QTWIN_ if (!S_ISREG(sbuf.st_mode)){ /* Nope, not a regular file */ icalerror_set_errno(ICAL_FILE_ERROR); return -1; } else { /* Lets assume that it is a file of the right type */ return sbuf.st_size; } #else return sbuf.st_size; #endif } /*return -1; not reached*/ } void icalfileset_free(icalfileset* cluster) { struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; icalerror_check_arg_rv((cluster!=0),"cluster"); if (impl->cluster != 0){ icalfileset_commit(cluster); icalcomponent_free(impl->cluster); impl->cluster=0; } if(impl->fd > 0){ icalfileset_unlock(impl); close(impl->fd); impl->fd = -1; } if(impl->path != 0){ free(impl->path); impl->path = 0; } free(impl); } const char* icalfileset_path(icalfileset* cluster) { struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; icalerror_check_arg_rz((cluster!=0),"cluster"); return impl->path; } int icalfileset_lock(icalfileset *cluster) { #ifndef _WIN32 struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; struct flock lock; int rtrn; icalerror_check_arg_rz((impl->fd>0),"impl->fd"); errno = 0; lock.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */ lock.l_start = 0; /* byte offset relative to l_whence */ lock.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */ lock.l_len = 0; /* #bytes (0 means to EOF) */ rtrn = fcntl(impl->fd, F_SETLKW, &lock); return rtrn; #else return -1; #endif } int icalfileset_unlock(icalfileset *cluster) { #ifndef _WIN32 struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; struct flock lock; icalerror_check_arg_rz((impl->fd>0),"impl->fd"); lock.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */ lock.l_start = 0; /* byte offset relative to l_whence */ lock.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */ lock.l_len = 0; /* #bytes (0 means to EOF) */ return (fcntl(impl->fd, F_UNLCK, &lock)); #else return -1; #endif } #ifdef ICAL_SAFESAVES int icalfileset_safe_saves=1; #else int icalfileset_safe_saves=0; #endif icalerrorenum icalfileset_commit(icalfileset* cluster) { char tmp[ICAL_PATH_MAX]; char *str; icalcomponent *c; off_t write_size=0; struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; icalerror_check_arg_re((impl!=0),"cluster",ICAL_BADARG_ERROR); icalerror_check_arg_re((impl->fd>0),"impl->fd is invalid", ICAL_INTERNAL_ERROR) ; if (impl->changed == 0 ){ return ICAL_NO_ERROR; } if(icalfileset_safe_saves == 1){ snprintf(tmp,ICAL_PATH_MAX,"cp %s %s.bak",impl->path,impl->path); if(system(tmp) < 0){ icalerror_set_errno(ICAL_FILE_ERROR); return ICAL_FILE_ERROR; } } if(lseek(impl->fd,SEEK_SET,0) < 0){ icalerror_set_errno(ICAL_FILE_ERROR); return ICAL_FILE_ERROR; } for(c = icalcomponent_get_first_component(impl->cluster,ICAL_ANY_COMPONENT); c != 0; c = icalcomponent_get_next_component(impl->cluster,ICAL_ANY_COMPONENT)){ int sz; str = icalcomponent_as_ical_string(c); sz=write(impl->fd,str,strlen(str)); if ( sz != strlen(str)){ perror("write"); icalerror_set_errno(ICAL_FILE_ERROR); return ICAL_FILE_ERROR; } write_size += sz; } impl->changed = 0; #ifndef _QTWIN_ if(ftruncate(impl->fd,write_size) < 0){ return ICAL_FILE_ERROR; } #endif return ICAL_NO_ERROR; } void icalfileset_mark(icalfileset* cluster){ struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; icalerror_check_arg_rv((impl!=0),"cluster"); impl->changed = 1; } icalcomponent* icalfileset_get_component(icalfileset* cluster){ struct icalfileset_impl *impl = (struct icalfileset_impl*)cluster; icalerror_check_arg_re((impl!=0),"cluster",ICAL_BADARG_ERROR); return impl->cluster; } /* manipulate the components in the cluster */ icalerrorenum icalfileset_add_component(icalfileset *cluster, icalcomponent* child) { struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; icalerror_check_arg_re((cluster!=0),"cluster", ICAL_BADARG_ERROR); icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR); icalcomponent_add_component(impl->cluster,child); icalfileset_mark(cluster); return ICAL_NO_ERROR; } icalerrorenum icalfileset_remove_component(icalfileset *cluster, icalcomponent* child) { struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; icalerror_check_arg_re((cluster!=0),"cluster",ICAL_BADARG_ERROR); icalerror_check_arg_re((child!=0),"child",ICAL_BADARG_ERROR); icalcomponent_remove_component(impl->cluster,child); icalfileset_mark(cluster); return ICAL_NO_ERROR; } int icalfileset_count_components(icalfileset *cluster, icalcomponent_kind kind) { struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; if(cluster == 0){ icalerror_set_errno(ICAL_BADARG_ERROR); return -1; } return icalcomponent_count_components(impl->cluster,kind); } icalerrorenum icalfileset_select(icalfileset* set, icalgauge* gauge) { struct icalfileset_impl* impl = (struct icalfileset_impl*)set; icalerror_check_arg_re(gauge!=0,"guage",ICAL_BADARG_ERROR); impl->gauge = gauge; return ICAL_NO_ERROR; } void icalfileset_clear(icalfileset* gauge) { struct icalfileset_impl* impl = (struct icalfileset_impl*)gauge; impl->gauge = 0; } icalcomponent* icalfileset_fetch(icalfileset* store,const char* uid) { icalcompiter i; struct icalfileset_impl* impl = (struct icalfileset_impl*)store; for(i = icalcomponent_begin_component(impl->cluster,ICAL_ANY_COMPONENT); icalcompiter_deref(&i)!= 0; icalcompiter_next(&i)){ icalcomponent *this = icalcompiter_deref(&i); icalcomponent *inner = icalcomponent_get_first_real_component(this); icalcomponent *p; const char *this_uid; if(inner != 0){ p = icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY); this_uid = icalproperty_get_uid(p); if(this_uid==0){ icalerror_warn("icalfileset_fetch found a component with no UID"); continue; } if (strcmp(uid,this_uid)==0){ return this; } } } return 0; } int icalfileset_has_uid(icalfileset* store,const char* uid) { assert(0); /* HACK, not implemented */ return 0; } /******* support routines for icalfileset_fetch_match *********/ struct icalfileset_id{ char* uid; char* recurrence_id; int sequence; }; void icalfileset_id_free(struct icalfileset_id *id) { if(id->recurrence_id != 0){ free(id->recurrence_id); } if(id->uid != 0){ free(id->uid); } } struct icalfileset_id icalfileset_get_id(icalcomponent* comp) { icalcomponent *inner; struct icalfileset_id id; icalproperty *p; inner = icalcomponent_get_first_real_component(comp); p = icalcomponent_get_first_property(inner, ICAL_UID_PROPERTY); assert(p!= 0); id.uid = strdup(icalproperty_get_uid(p)); p = icalcomponent_get_first_property(inner, ICAL_SEQUENCE_PROPERTY); if(p == 0) { id.sequence = 0; } else { id.sequence = icalproperty_get_sequence(p); } p = icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY); if (p == 0){ id.recurrence_id = 0; } else { icalvalue *v; v = icalproperty_get_value(p); id.recurrence_id = strdup(icalvalue_as_ical_string(v)); assert(id.recurrence_id != 0); } return id; } /* Find the component that is related to the given component. Currently, it just matches based on UID and RECURRENCE-ID */ icalcomponent* icalfileset_fetch_match(icalfileset* set, icalcomponent *comp) { struct icalfileset_impl* impl = (struct icalfileset_impl*)set; icalcompiter i; struct icalfileset_id comp_id, match_id; comp_id = icalfileset_get_id(comp); for(i = icalcomponent_begin_component(impl->cluster,ICAL_ANY_COMPONENT); icalcompiter_deref(&i)!= 0; icalcompiter_next(&i)){ icalcomponent *match = icalcompiter_deref(&i); match_id = icalfileset_get_id(match); if(strcmp(comp_id.uid, match_id.uid) == 0 && ( comp_id.recurrence_id ==0 || strcmp(comp_id.recurrence_id, match_id.recurrence_id) ==0 )){ /* HACK. What to do with SEQUENCE? */ icalfileset_id_free(&match_id); icalfileset_id_free(&comp_id); return match; } icalfileset_id_free(&match_id); } icalfileset_id_free(&comp_id); return 0; } icalerrorenum icalfileset_modify(icalfileset* store, icalcomponent *old, icalcomponent *new) { assert(0); /* HACK, not implemented */ return ICAL_NO_ERROR; } /* Iterate through components */ icalcomponent* icalfileset_get_current_component (icalfileset* cluster) { struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; icalerror_check_arg_rz((cluster!=0),"cluster"); return icalcomponent_get_current_component(impl->cluster); } icalcomponent* icalfileset_get_first_component(icalfileset* cluster) { struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; icalcomponent *c=0; icalerror_check_arg_rz((cluster!=0),"cluster"); do { if (c == 0){ c = icalcomponent_get_first_component(impl->cluster, ICAL_ANY_COMPONENT); } else { c = icalcomponent_get_next_component(impl->cluster, ICAL_ANY_COMPONENT); } if(c != 0 && (impl->gauge == 0 || icalgauge_compare(impl->gauge,c) == 1)){ return c; } } while(c != 0); return 0; } icalcomponent* icalfileset_get_next_component(icalfileset* cluster) { struct icalfileset_impl* impl = (struct icalfileset_impl*)cluster; icalcomponent *c; icalerror_check_arg_rz((cluster!=0),"cluster"); do { c = icalcomponent_get_next_component(impl->cluster, ICAL_ANY_COMPONENT); if(c != 0 && (impl->gauge == 0 || icalgauge_compare(impl->gauge,c) == 1)){ return c; } } while(c != 0); return 0; }