/* -*- Mode: C -*- ====================================================================== FILE: icalclassify.c CREATOR: ebusboom 23 aug 2000 $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/ ======================================================================*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "icalerror.h" #include "ical.h" #include "icalclassify.h" #include "icalmemory.h" #include /* For tolower() */ #include /* for index() */ #include /* for malloc and free */ struct icalclassify_parts { icalcomponent *c; icalcomponent_kind inner_kind; icalproperty_method method; char* organizer; icalparameter_partstat reply_partstat; char* reply_attendee; char* uid; int sequence; struct icaltimetype dtstamp; struct icaltimetype recurrence_id; }; char* icalclassify_lowercase(const char* str) { char* p = 0; char* new = icalmemory_strdup(str); if(str ==0){ return 0; } for(p = new; *p!=0; p++){ *p = tolower(*p); } return new; } /* Return a set of components that intersect in time with comp. For component X and Y to intersect: X.DTSTART < Y.DTEND && X.DTEND > Y.DTSTART */ icalcomponent* icalclassify_find_overlaps(icalset* set, icalcomponent* comp) { icalcomponent *return_set; icalcomponent *c; struct icaltime_span span,compspan; icalerror_clear_errno(); compspan = icalcomponent_get_span(comp); if(icalerrno != ICAL_NO_ERROR){ return 0; } return_set = icalcomponent_new(ICAL_XROOT_COMPONENT); for(c = icalset_get_first_component(set); c != 0; c = icalset_get_next_component(set)){ icalerror_clear_errno(); span = icalcomponent_get_span(c); if(icalerrno != ICAL_NO_ERROR){ continue; } if (compspan.start < span.end && compspan.end > span.start){ icalcomponent *clone = icalcomponent_new_clone(c); icalcomponent_add_component(return_set,clone); } } if(icalcomponent_count_components(return_set,ICAL_ANY_COMPONENT) !=0){ return return_set; } else { icalcomponent_free(return_set); return 0; } } icalproperty* icalclassify_find_attendee(icalcomponent *c, const char* attendee) { icalproperty *p; icalcomponent* inner; char* lattendee; char* upn; if(attendee == 0){ return 0; } lattendee = icalclassify_lowercase(attendee); upn = strchr(lattendee,':'); if (upn== 0){ upn = lattendee; } else { upn++; /* skip the ";"*/ } inner = icalcomponent_get_first_real_component(c); for(p = icalcomponent_get_first_property(inner,ICAL_ATTENDEE_PROPERTY); p != 0; p = icalcomponent_get_next_property(inner,ICAL_ATTENDEE_PROPERTY)) { const char* this_attendee = icalclassify_lowercase(icalproperty_get_attendee(p)); char* this_upn = strchr(this_attendee,':'); if(this_upn == 0){ continue; } else { this_upn++; } if(strcmp(this_upn,upn)==0){ return p; } } return 0; } void icalssutil_free_parts(struct icalclassify_parts *parts) { if(parts == 0){ return; } if(parts->organizer != 0){ free(parts->organizer); } if(parts->uid != 0){ free(parts->uid); } if(parts->reply_attendee){ free(parts->reply_attendee); } } void icalssutil_get_parts(icalcomponent* c, struct icalclassify_parts* parts) { icalproperty *p; icalcomponent *inner; memset(parts,0,sizeof(struct icalclassify_parts)); parts->method = ICAL_METHOD_NONE; parts->sequence = 0; parts->reply_partstat = ICAL_PARTSTAT_NONE; if(c == 0){ return; } parts->c = c; p = icalcomponent_get_first_property(c,ICAL_METHOD_PROPERTY); if(p!=0){ parts->method = icalproperty_get_method(p); } inner = icalcomponent_get_first_real_component(c); parts->inner_kind = icalcomponent_isa(inner); p = icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY); if(p!=0){ parts->organizer = strdup(icalproperty_get_organizer(p)); } p = icalcomponent_get_first_property(inner,ICAL_SEQUENCE_PROPERTY); if(p!=0){ parts->sequence = icalproperty_get_sequence(p); } p = icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY); if(p!=0){ parts->uid = strdup(icalproperty_get_uid(p)); } p = icalcomponent_get_first_property(inner,ICAL_RECURRENCEID_PROPERTY); if(p!=0){ parts->recurrence_id = icalproperty_get_recurrenceid(p); } p = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY); if(p!=0){ parts->dtstamp = icalproperty_get_dtstamp(p); } if(parts->method==ICAL_METHOD_REPLY){ icalparameter *param; p = icalcomponent_get_first_property(inner,ICAL_ATTENDEE_PROPERTY); if(p!=0){ param = icalproperty_get_first_parameter(p,ICAL_PARTSTAT_PARAMETER); if(param != 0){ parts->reply_partstat = icalparameter_get_partstat(param); } parts->reply_attendee = strdup(icalproperty_get_attendee(p)); } } } int icalssutil_is_rescheduled(icalcomponent* a,icalcomponent* b) { icalproperty *p1,*p2; icalcomponent *i1,*i2; int i; icalproperty_kind kind_array[] = { ICAL_DTSTART_PROPERTY, ICAL_DTEND_PROPERTY, ICAL_DURATION_PROPERTY, ICAL_DUE_PROPERTY, ICAL_RRULE_PROPERTY, ICAL_RDATE_PROPERTY, ICAL_EXRULE_PROPERTY, ICAL_EXDATE_PROPERTY, ICAL_NO_PROPERTY }; i1 = icalcomponent_get_first_real_component(a); i2 = icalcomponent_get_first_real_component(b); for(i =0; kind_array[i] != ICAL_NO_PROPERTY; i++){ p1 = icalcomponent_get_first_property(i1,kind_array[i]); p2 = icalcomponent_get_first_property(i2,kind_array[i]); if( (p1!=0)^(p1!=0) ){ /* Return true if the property exists in one component and not the other */ return 1; } if(p1 && strcmp(icalproperty_as_ical_string(p1), icalproperty_as_ical_string(p2)) != 0){ return 1; } } return 0; } #define icalclassify_pre \ int rtrn =0; #define icalclassify_post \ return rtrn; int icalclassify_publish_new(struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre; if(comp->method == ICAL_METHOD_PUBLISH && match == 0 && comp->inner_kind != ICAL_VFREEBUSY_COMPONENT){ rtrn = 1; } icalclassify_post; } int icalclassify_publish_update(struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre; if(comp->method == ICAL_METHOD_PUBLISH && match !=0 && comp->inner_kind != ICAL_VFREEBUSY_COMPONENT){ rtrn = 1; } icalclassify_post; } int icalclassify_publish_freebusy(struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre; if(comp->method == ICAL_METHOD_PUBLISH && comp->inner_kind == ICAL_VFREEBUSY_COMPONENT){ rtrn = 1; } icalclassify_post; } int icalclassify_request_new(struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { /* Method is REQUEST, and there is no match */ icalclassify_pre if(match->c==0 && comp->method == ICAL_METHOD_REQUEST){ rtrn = 1; } icalclassify_post } int icalclassify_request_update( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { /* REQUEST method, Higher SEQUENCE than match, and all time-related properties are unchanged */ icalclassify_pre if (match != 0 && comp->sequence >= match->sequence && !icalssutil_is_rescheduled(comp->c,match->c)){ rtrn = 1; } icalclassify_post } int icalclassify_request_reschedule( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { /* REQUEST method, Higher SEQUENCE than match, and one or more time-related properties are changed */ icalclassify_pre if (match->c != 0 && comp->sequence > match->sequence && icalssutil_is_rescheduled(comp->c,match->c)){ rtrn = 1; } icalclassify_post } int icalclassify_request_delegate( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalproperty* attendee; icalparameter* param; icalclassify_pre; attendee = icalclassify_find_attendee(comp->c,user); if(attendee == 0){ return 0; } param = icalproperty_get_first_parameter(attendee,ICAL_DELEGATEDFROM_PARAMETER); if (param != 0){ rtrn = 1; } icalclassify_post } int icalclassify_request_new_organizer( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { /* Organizer has changed between match and component */ icalclassify_pre icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); icalclassify_post } int icalclassify_request_status( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); icalclassify_post } int icalclassify_request_forward( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); icalclassify_post } int icalclassify_request_freebusy( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR); icalclassify_post } int icalclassify_reply_accept( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalproperty* attendee; icalclassify_pre; attendee = icalclassify_find_attendee(match->c,comp->reply_attendee); if(attendee != 0&& comp->reply_partstat == ICAL_PARTSTAT_ACCEPTED){ rtrn = 1; } icalclassify_post } int icalclassify_reply_decline( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalproperty* attendee; icalclassify_pre; attendee = icalclassify_find_attendee(match->c,comp->reply_attendee); if( attendee != 0 && comp->reply_partstat == ICAL_PARTSTAT_DECLINED){ rtrn = 1; } icalclassify_post } int icalclassify_reply_delegate( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalproperty* attendee; icalclassify_pre; attendee = icalclassify_find_attendee(match->c,comp->reply_attendee); if( attendee != 0 && comp->reply_partstat == ICAL_PARTSTAT_DELEGATED){ rtrn = 1; } icalclassify_post } int icalclassify_reply_crasher_accept( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalproperty* attendee; icalclassify_pre; attendee= icalclassify_find_attendee(match->c,comp->reply_attendee); if(attendee == 0 && comp->reply_partstat == ICAL_PARTSTAT_ACCEPTED){ rtrn = 1; } icalclassify_post } int icalclassify_reply_crasher_decline( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalparameter_partstat partstat; icalproperty* attendee; icalclassify_pre; attendee = icalclassify_find_attendee(match->c,comp->reply_attendee); if(attendee == 0 && comp->reply_partstat == ICAL_PARTSTAT_DECLINED){ rtrn = 1; } icalclassify_post } int icalclassify_add_instance( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre if(comp->method == ICAL_METHOD_ADD){ rtrn = 1; } icalclassify_post } int icalclassify_cancel_event( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre if(comp->method == ICAL_METHOD_CANCEL){ rtrn = 1; } icalclassify_post } int icalclassify_cancel_instance( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre if(comp->method == ICAL_METHOD_CANCEL){ rtrn = 1; } icalclassify_post } int icalclassify_cancel_all( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre if(comp->method == ICAL_METHOD_CANCEL){ rtrn = 1; } icalclassify_post } int icalclassify_refesh( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre if(comp->method == ICAL_METHOD_REFRESH){ rtrn = 1; } icalclassify_post } int icalclassify_counter( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre if(comp->method == ICAL_METHOD_COUNTER){ rtrn = 1; } icalclassify_post } int icalclassify_delinecounter( struct icalclassify_parts *comp, struct icalclassify_parts *match, const char* user) { icalclassify_pre if(comp->method == ICAL_METHOD_DECLINECOUNTER){ rtrn = 1; } icalclassify_post } struct icalclassify_map { icalproperty_method method; int (*fn)(struct icalclassify_parts *comp,struct icalclassify_parts *match, const char* user); ical_class class; } icalclassify_map[] = { {ICAL_METHOD_PUBLISH,icalclassify_publish_new,ICAL_PUBLISH_NEW_CLASS}, {ICAL_METHOD_PUBLISH,icalclassify_publish_update,ICAL_PUBLISH_UPDATE_CLASS}, {ICAL_METHOD_PUBLISH,icalclassify_publish_freebusy,ICAL_PUBLISH_FREEBUSY_CLASS}, {ICAL_METHOD_REQUEST,icalclassify_request_delegate,ICAL_REQUEST_DELEGATE_CLASS}, {ICAL_METHOD_REQUEST,icalclassify_request_new,ICAL_REQUEST_NEW_CLASS}, {ICAL_METHOD_REQUEST,icalclassify_request_update,ICAL_REQUEST_UPDATE_CLASS}, {ICAL_METHOD_REQUEST,icalclassify_request_reschedule,ICAL_REQUEST_RESCHEDULE_CLASS}, {ICAL_METHOD_REQUEST,icalclassify_request_new_organizer,ICAL_REQUEST_NEW_ORGANIZER_CLASS}, {ICAL_METHOD_REQUEST,icalclassify_request_forward,ICAL_REQUEST_FORWARD_CLASS}, {ICAL_METHOD_REQUEST,icalclassify_request_status,ICAL_REQUEST_STATUS_CLASS}, {ICAL_METHOD_REQUEST,icalclassify_request_freebusy,ICAL_REQUEST_FREEBUSY_CLASS}, {ICAL_METHOD_REPLY,icalclassify_reply_accept,ICAL_REPLY_ACCEPT_CLASS}, {ICAL_METHOD_REPLY,icalclassify_reply_decline,ICAL_REPLY_DECLINE_CLASS}, {ICAL_METHOD_REPLY,icalclassify_reply_delegate,ICAL_REPLY_DELEGATE_CLASS}, {ICAL_METHOD_REPLY,icalclassify_reply_crasher_accept,ICAL_REPLY_CRASHER_ACCEPT_CLASS}, {ICAL_METHOD_REPLY,icalclassify_reply_crasher_decline,ICAL_REPLY_CRASHER_DECLINE_CLASS}, {ICAL_METHOD_ADD,icalclassify_add_instance,ICAL_ADD_INSTANCE_CLASS}, {ICAL_METHOD_CANCEL,icalclassify_cancel_event,ICAL_CANCEL_EVENT_CLASS}, {ICAL_METHOD_CANCEL,icalclassify_cancel_instance,ICAL_CANCEL_INSTANCE_CLASS}, {ICAL_METHOD_CANCEL,icalclassify_cancel_all,ICAL_CANCEL_ALL_CLASS}, {ICAL_METHOD_REFRESH,icalclassify_refesh,ICAL_REFRESH_CLASS}, {ICAL_METHOD_COUNTER,icalclassify_counter,ICAL_COUNTER_CLASS}, {ICAL_METHOD_DECLINECOUNTER,icalclassify_delinecounter,ICAL_DECLINECOUNTER_CLASS}, {ICAL_METHOD_NONE,0,ICAL_NO_CLASS} }; ical_class icalclassify(icalcomponent* c,icalcomponent* match, const char* user) { icalcomponent *inner; icalproperty *p; icalproperty_method method; ical_class class = ICAL_UNKNOWN_CLASS; int i; struct icalclassify_parts comp_parts; struct icalclassify_parts match_parts; inner = icalcomponent_get_first_real_component(c); if (inner == 0) { return ICAL_NO_CLASS; } icalssutil_get_parts(c,&comp_parts); icalssutil_get_parts(match,&match_parts); /* Determine if the incoming component is obsoleted by the match */ if(match != 0 && ( comp_parts.method == ICAL_METHOD_REQUEST )){ assert ( ! ((comp_parts.dtstamp.is_utc==1)^ (match_parts.dtstamp.is_utc==1))); if( comp_parts.sequence0) { /* comp has a smaller sequence and a later DTSTAMP */ return ICAL_MISSEQUENCED_CLASS; } if( (comp_parts.sequence