X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fcalendar%2Fserv_calendar.c;h=3d63bcdc26cf8fe2a3e7908f51899bb4a9557ca2;hb=85ae093a7401ea30ff071d833c6456ab8880ad15;hp=062e24d055c57cbf316c72e41536dfd6964e343e;hpb=156637d5117372187db974b035237147a4c8e897;p=citadel.git diff --git a/citadel/modules/calendar/serv_calendar.c b/citadel/modules/calendar/serv_calendar.c index 062e24d05..3d63bcdc2 100644 --- a/citadel/modules/calendar/serv_calendar.c +++ b/citadel/modules/calendar/serv_calendar.c @@ -52,8 +52,7 @@ icalcomponent *icalcomponent_new_citadel_vcalendar(void) { encaps = icalcomponent_new_vcalendar(); if (encaps == NULL) { - CtdlLogPrintf(CTDL_CRIT, "Error at %s:%d - could not allocate component!\n", - __FILE__, __LINE__); + CtdlLogPrintf(CTDL_CRIT, "ERROR: could not allocate component!\n"); return NULL; } @@ -87,11 +86,6 @@ icalcomponent *ical_encapsulate_subcomponent(icalcomponent *subcomp) { /* Encapsulate the subcomponent inside */ icalcomponent_add_component(encaps, subcomp); - /* Convert all timestamps to UTC so we don't have to deal with - * stupid VTIMEZONE crap. - */ - ical_dezonify(encaps); - /* Return the object we just created. */ return(encaps); } @@ -124,7 +118,7 @@ void ical_write_to_cal(struct ctdluser *u, icalcomponent *cal) { return; } - ser = icalcomponent_as_ical_string(cal); + ser = icalcomponent_as_ical_string_r(cal); if (ser == NULL) return; /* If the caller supplied a user, write to that user's default calendar room */ @@ -162,39 +156,10 @@ void ical_write_to_cal(struct ctdluser *u, icalcomponent *cal) { } /* In either case, now we can free the serialized calendar object */ -// free(ser); -} - - -/* - * Add a calendar object to the user's calendar - * - * ok because it uses ical_write_to_cal() - */ -void ical_add(icalcomponent *cal, int recursion_level) { - icalcomponent *c; - - /* - * The VEVENT subcomponent is the one we're interested in saving. - */ - if (icalcomponent_isa(cal) == ICAL_VEVENT_COMPONENT) { - - ical_write_to_cal(&CC->user, cal); - - } - - /* If the component has subcomponents, recurse through them. */ - for (c = icalcomponent_get_first_component(cal, ICAL_ANY_COMPONENT); - (c != 0); - c = icalcomponent_get_next_component(cal, ICAL_ANY_COMPONENT)) { - /* Recursively process subcomponent */ - ical_add(c, recursion_level+1); - } - + free(ser); } - /* * Send a reply to a meeting invitation. * @@ -315,7 +280,7 @@ void ical_send_a_reply(icalcomponent *request, char *action) { } /* Now generate the reply message and send it out. */ - serialized_reply = strdup(icalcomponent_as_ical_string(the_reply)); + serialized_reply = icalcomponent_as_ical_string_r(the_reply); icalcomponent_free(the_reply); /* don't need this anymore */ if (serialized_reply == NULL) return; @@ -355,7 +320,7 @@ void ical_send_a_reply(icalcomponent *request, char *action) { */ void ical_locate_part(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, - void *cbuserdata) { + char *cbid, void *cbuserdata) { struct ical_respond_data *ird = NULL; @@ -382,9 +347,6 @@ void ical_locate_part(char *name, char *filename, char *partnum, char *disp, } ird->cal = icalcomponent_new_from_string(content); - if (ird->cal != NULL) { - ical_dezonify(ird->cal); - } } @@ -435,7 +397,7 @@ void ical_respond(long msgnum, char *partnum, char *action) { if (ird.cal != NULL) { /* Save this in the user's calendar if necessary */ if (!strcasecmp(action, "accept")) { - ical_add(ird.cal, 0); + ical_write_to_cal(&CC->user, ird.cal); } /* Send a reply if necessary */ @@ -443,9 +405,9 @@ void ical_respond(long msgnum, char *partnum, char *action) { ical_send_a_reply(ird.cal, action); } - /* Now that we've processed this message, we don't need it - * anymore. So delete it. (NOTE we don't do this anymore.) - CtdlDeleteMessages(CC->room.QRname, &msgnum, 1, ""); + /* We used to delete the invitation after handling it. + * We don't do that anymore, but here is the code that handled it: + * CtdlDeleteMessages(CC->room.QRname, &msgnum, 1, ""); */ /* Free the memory we allocated and return a response. */ @@ -514,7 +476,7 @@ struct original_event_container { */ void ical_locate_original_event(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, - void *cbuserdata) { + char *cbid, void *cbuserdata) { struct original_event_container *oec = NULL; @@ -688,7 +650,7 @@ int ical_update_my_calendar_with_reply(icalcomponent *cal) { ical_merge_attendee_reply(original_event, cal); /* Serialize it */ - serialized_event = strdup(icalcomponent_as_ical_string(original_event)); + serialized_event = icalcomponent_as_ical_string_r(original_event); icalcomponent_free(original_event); /* Don't need this anymore. */ if (serialized_event == NULL) return(2); @@ -896,8 +858,10 @@ int ical_ctdl_is_overlap( * * Now both the proposed and existing events have been boiled down to start and end times. * Check for overlap and output any conflicts. + * + * Returns nonzero if a conflict was reported. This allows the caller to stop iterating. */ -void ical_conflicts_phase6(struct icaltimetype t1start, +int ical_conflicts_phase6(struct icaltimetype t1start, struct icaltimetype t1end, struct icaltimetype t2start, struct icaltimetype t2end, @@ -906,17 +870,19 @@ void ical_conflicts_phase6(struct icaltimetype t1start, char *conflict_event_summary, char *compare_uid) { - - /* debugging cruft */ - // time_t tt; - // tt = icaltime_as_timet(t1start); - // CtdlLogPrintf(CTDL_DEBUG, "PROPOSED START: %s", ctime(&tt)); - // tt = icaltime_as_timet(t1end); - // CtdlLogPrintf(CTDL_DEBUG, " PROPOSED END: %s", ctime(&tt)); - // tt = icaltime_as_timet(t2start); - // CtdlLogPrintf(CTDL_DEBUG, "EXISTING START: %s", ctime(&tt)); - // tt = icaltime_as_timet(t2end); - // CtdlLogPrintf(CTDL_DEBUG, " EXISTING END: %s", ctime(&tt)); + int conflict_reported = 0; + + /* debugging cruft * + time_t tt; + tt = icaltime_as_timet_with_zone(t1start, t1start.zone); + CtdlLogPrintf(CTDL_DEBUG, "PROPOSED START: %s", ctime(&tt)); + tt = icaltime_as_timet_with_zone(t1end, t1end.zone); + CtdlLogPrintf(CTDL_DEBUG, " PROPOSED END: %s", ctime(&tt)); + tt = icaltime_as_timet_with_zone(t2start, t2start.zone); + CtdlLogPrintf(CTDL_DEBUG, "EXISTING START: %s", ctime(&tt)); + tt = icaltime_as_timet_with_zone(t2end, t2end.zone); + CtdlLogPrintf(CTDL_DEBUG, " EXISTING END: %s", ctime(&tt)); + * debugging cruft */ /* compare and output */ @@ -930,8 +896,10 @@ void ical_conflicts_phase6(struct icaltimetype t1start, conflict_event_uid))) ? 1 : 0 ) ); + conflict_reported = 1; } + return(conflict_reported); } @@ -971,10 +939,37 @@ void ical_conflicts_phase5(struct icaltimetype t1start, p = ical_ctdl_get_subprop(existing_event, ICAL_DTSTART_PROPERTY); if (p == NULL) return; if (p != NULL) t2start = icalproperty_get_dtstart(p); + if (icaltime_is_utc(t2start)) { + t2start.zone = icaltimezone_get_utc_timezone(); + } + else { + t2start.zone = icalcomponent_get_timezone(existing_event, + icalparameter_get_tzid( + icalproperty_get_first_parameter(p, ICAL_TZID_PARAMETER) + ) + ); + if (!t2start.zone) { + t2start.zone = get_default_icaltimezone(); + } + } p = ical_ctdl_get_subprop(existing_event, ICAL_DTEND_PROPERTY); if (p != NULL) { t2end = icalproperty_get_dtend(p); + + if (icaltime_is_utc(t2end)) { + t2end.zone = icaltimezone_get_utc_timezone(); + } + else { + t2end.zone = icalcomponent_get_timezone(existing_event, + icalparameter_get_tzid( + icalproperty_get_first_parameter(p, ICAL_TZID_PARAMETER) + ) + ); + if (!t2end.zone) { + t2end.zone = get_default_icaltimezone(); + } + } dur = icaltime_subtract(t2end, t2start); } @@ -982,7 +977,6 @@ void ical_conflicts_phase5(struct icaltimetype t1start, if (rrule) { recur = icalproperty_get_rrule(rrule); ritr = icalrecur_iterator_new(recur, t2start); - CtdlLogPrintf(CTDL_DEBUG, "Recurrence found: %s\n", icalrecurrencetype_as_string(&recur)); } do { @@ -996,20 +990,28 @@ void ical_conflicts_phase5(struct icaltimetype t1start, strcpy(conflict_event_summary, icalproperty_get_comment(p)); } - ical_conflicts_phase6(t1start, t1end, t2start, t2end, - existing_msgnum, conflict_event_uid, conflict_event_summary, compare_uid - ); + if (ical_conflicts_phase6(t1start, t1end, t2start, t2end, + existing_msgnum, conflict_event_uid, conflict_event_summary, compare_uid)) + { + num_recur = MAX_RECUR + 1; /* force it out of scope, no need to continue */ + } if (rrule) { t2start = icalrecur_iterator_next(ritr); if (!icaltime_is_null_time(t2end)) { + const icaltimezone *hold_zone = t2end.zone; t2end = icaltime_add(t2start, dur); + t2end.zone = hold_zone; } ++num_recur; } + if (icaltime_compare(t2start, t1end) < 0) { + num_recur = MAX_RECUR + 1; /* force it out of scope */ + } + } while ( (rrule) && (!icaltime_is_null_time(t2start)) && (num_recur < MAX_RECUR) ); - if (num_recur > 0) CtdlLogPrintf(CTDL_DEBUG, "Iterated over existing event %d times.\n", num_recur); + icalrecur_iterator_free(ritr); } @@ -1047,10 +1049,38 @@ void ical_conflicts_phase4(icalcomponent *proposed_event, p = ical_ctdl_get_subprop(proposed_event, ICAL_DTSTART_PROPERTY); if (p == NULL) return; if (p != NULL) t1start = icalproperty_get_dtstart(p); + if (icaltime_is_utc(t1start)) { + t1start.zone = icaltimezone_get_utc_timezone(); + } + else { + t1start.zone = icalcomponent_get_timezone(proposed_event, + icalparameter_get_tzid( + icalproperty_get_first_parameter(p, ICAL_TZID_PARAMETER) + ) + ); + if (!t1start.zone) { + t1start.zone = get_default_icaltimezone(); + } + } p = ical_ctdl_get_subprop(proposed_event, ICAL_DTEND_PROPERTY); if (p != NULL) { t1end = icalproperty_get_dtend(p); + + if (icaltime_is_utc(t1end)) { + t1end.zone = icaltimezone_get_utc_timezone(); + } + else { + t1end.zone = icalcomponent_get_timezone(proposed_event, + icalparameter_get_tzid( + icalproperty_get_first_parameter(p, ICAL_TZID_PARAMETER) + ) + ); + if (!t1end.zone) { + t1end.zone = get_default_icaltimezone(); + } + } + dur = icaltime_subtract(t1end, t1start); } @@ -1058,7 +1088,6 @@ void ical_conflicts_phase4(icalcomponent *proposed_event, if (rrule) { recur = icalproperty_get_rrule(rrule); ritr = icalrecur_iterator_new(recur, t1start); - CtdlLogPrintf(CTDL_DEBUG, "Recurrence found: %s\n", icalrecurrencetype_as_string(&recur)); } p = ical_ctdl_get_subprop(proposed_event, ICAL_UID_PROPERTY); @@ -1072,13 +1101,15 @@ void ical_conflicts_phase4(icalcomponent *proposed_event, if (rrule) { t1start = icalrecur_iterator_next(ritr); if (!icaltime_is_null_time(t1end)) { + const icaltimezone *hold_zone = t1end.zone; t1end = icaltime_add(t1start, dur); + t1end.zone = hold_zone; } ++num_recur; } } while ( (rrule) && (!icaltime_is_null_time(t1start)) && (num_recur < MAX_RECUR) ); - if (num_recur > 0) CtdlLogPrintf(CTDL_DEBUG, "Iterated over proposed event %d times.\n", num_recur); + icalrecur_iterator_free(ritr); } @@ -1158,7 +1189,7 @@ void ical_conflicts(long msgnum, char *partnum) { msg = CtdlFetchMessage(msgnum, 1); if (msg == NULL) { - cprintf("%d Message %ld not found.\n", + cprintf("%d Message %ld not found\n", ERROR + ILLEGAL_VALUE, (long)msgnum ); @@ -1182,12 +1213,8 @@ void ical_conflicts(long msgnum, char *partnum) { icalcomponent_free(ird.cal); return; } - else { - cprintf("%d No calendar object found\n", ERROR + ROOM_NOT_FOUND); - return; - } - /* should never get here */ + cprintf("%d No calendar object found\n", ERROR + ROOM_NOT_FOUND); } @@ -1212,8 +1239,6 @@ void ical_add_to_freebusy(icalcomponent *fb, icalcomponent *cal) { return; } - ical_dezonify(cal); - /* If this event is not opaque, the user isn't publishing it as * busy time, so don't bother doing anything else. */ @@ -1469,7 +1494,7 @@ void ical_freebusy(char *who) { /* Serialize it */ CtdlLogPrintf(CTDL_DEBUG, "Serializing\n"); - serialized_request = strdup(icalcomponent_as_ical_string(encaps)); + serialized_request = icalcomponent_as_ical_string_r(encaps); icalcomponent_free(encaps); /* Don't need this anymore. */ cprintf("%d Here is the free/busy data:\n", LISTING_FOLLOWS); @@ -1535,7 +1560,24 @@ void ical_getics_backend(long msgnum, void *data) { for (c = icalcomponent_get_first_component(ird.cal, ICAL_ANY_COMPONENT); (c != NULL); c = icalcomponent_get_next_component(ird.cal, ICAL_ANY_COMPONENT)) { - icalcomponent_add_component(encaps, icalcomponent_new_clone(c)); + + /* For VTIMEZONE components, suppress duplicates of the same tzid */ + + if (icalcomponent_isa(c) == ICAL_VTIMEZONE_COMPONENT) { + icalproperty *p = icalcomponent_get_first_property(c, ICAL_TZID_PROPERTY); + if (p) { + const char *tzid = icalproperty_get_tzid(p); + if (!icalcomponent_get_timezone(encaps, tzid)) { + icalcomponent_add_component(encaps, + icalcomponent_new_clone(c)); + } + } + } + + /* All other types of components can go in verbatim */ + else { + icalcomponent_add_component(encaps, icalcomponent_new_clone(c)); + } } icalcomponent_free(ird.cal); } @@ -1560,8 +1602,7 @@ void ical_getics(void) encaps = icalcomponent_new_vcalendar(); if (encaps == NULL) { - CtdlLogPrintf(CTDL_DEBUG, "Error at %s:%d - could not allocate component!\n", - __FILE__, __LINE__); + CtdlLogPrintf(CTDL_DEBUG, "ERROR: could not allocate component!\n"); cprintf("%d Could not allocate memory\n", ERROR+INTERNAL_ERROR); return; } @@ -1585,12 +1626,27 @@ void ical_getics(void) (void *) encaps ); - ser = strdup(icalcomponent_as_ical_string(encaps)); + ser = icalcomponent_as_ical_string_r(encaps); + icalcomponent_free(encaps); /* Don't need this anymore. */ client_write(ser, strlen(ser)); free(ser); cprintf("\n000\n"); - icalcomponent_free(encaps); /* Don't need this anymore. */ +} + +/* + * Helper callback function for ical_putics() to discover which TZID's we need. + * Simply put the tzid name string into a hash table. After the callbacks are + * done we'll go through them and attach the ones that we have. + */ +void ical_putics_grabtzids(icalparameter *param, void *data) +{ + const char *tzid = icalparameter_get_tzid(param); + HashList *keys = (HashList *) data; + + if ( (keys) && (tzid) && (!IsEmptyStr(tzid)) ) { + Put(keys, tzid, strlen(tzid), strdup(tzid), generic_free_handler); + } } @@ -1603,13 +1659,21 @@ void ical_putics(void) char *calstream = NULL; icalcomponent *cal; icalcomponent *c; + icalcomponent *encaps = NULL; + HashList *tzidlist = NULL; + HashPos *HashPos; + void *Value; + const char *Key; + long len; + /* Only allow this operation if we're in a room containing a calendar or tasks view */ if ( (CC->room.QRdefaultview != VIEW_CALENDAR) &&(CC->room.QRdefaultview != VIEW_TASKS) ) { cprintf("%d Not a calendar room\n", ERROR+NOT_HERE); - return; /* Not an iCalendar-centric room */ + return; } + /* Only allow this operation if we have permission to overwrite the existing calendar */ if (!CtdlDoIHavePermissionToDeleteMessagesFromThisRoom()) { cprintf("%d Permission denied.\n", ERROR+HIGHER_ACCESS_REQUIRED); return; @@ -1623,11 +1687,10 @@ void ical_putics(void) cal = icalcomponent_new_from_string(calstream); free(calstream); - ical_dezonify(cal); /* We got our data stream -- now do something with it. */ - /* Delete the existing messages in the room, because we are replacing + /* Delete the existing messages in the room, because we are overwriting * the entire calendar with an entire new (or updated) calendar. * (Careful: this opens an S_ROOMS critical section!) */ @@ -1647,7 +1710,55 @@ void ical_putics(void) for (c = icalcomponent_get_first_component(cal, ICAL_ANY_COMPONENT); (c != NULL); c = icalcomponent_get_next_component(cal, ICAL_ANY_COMPONENT)) { - ical_write_to_cal(NULL, c); + + /* Non-VTIMEZONE components each get written as individual messages. + * But we also need to attach the relevant VTIMEZONE components to them. + */ + if ( (icalcomponent_isa(c) != ICAL_VTIMEZONE_COMPONENT) + && (encaps = icalcomponent_new_vcalendar()) ) { + icalcomponent_add_property(encaps, icalproperty_new_prodid(PRODID)); + icalcomponent_add_property(encaps, icalproperty_new_version("2.0")); + icalcomponent_set_method(encaps, ICAL_METHOD_PUBLISH); + + /* Attach any needed timezones here */ + tzidlist = NewHash(1, NULL); + if (tzidlist) { + icalcomponent_foreach_tzid(c, ical_putics_grabtzids, tzidlist); + } + HashPos = GetNewHashPos(tzidlist, 0); + + while (GetNextHashPos(tzidlist, HashPos, &len, &Key, &Value)) { + CtdlLogPrintf(CTDL_DEBUG, "Attaching timezone '%s'\n", Value); + icaltimezone *t = NULL; + + /* First look for a timezone attached to the original calendar */ + t = icalcomponent_get_timezone(cal, Value); + + /* Try built-in tzdata if the right one wasn't attached */ + if (!t) { + t = icaltimezone_get_builtin_timezone(Value); + } + + /* I've got a valid timezone to attach. */ + if (t) { + icalcomponent_add_component(encaps, + icalcomponent_new_clone( + icaltimezone_get_component(t) + ) + ); + } + + } + DeleteHashPos(&HashPos); + DeleteHash(&tzidlist); + + /* Now attach the component itself (usually a VEVENT or VTODO) */ + icalcomponent_add_component(encaps, icalcomponent_new_clone(c)); + + /* Write it to the message store */ + ical_write_to_cal(NULL, encaps); + icalcomponent_free(encaps); + } } } @@ -1793,10 +1904,14 @@ void ical_create_room(void) /* - * ical_send_out_invitations() is called by ical_saving_vevent() when it - * finds a VEVENT. + * ical_send_out_invitations() is called by ical_saving_vevent() when it finds a VEVENT. + * + * top_level_cal is the highest available level calendar object. + * cal is the subcomponent containing the VEVENT. + * + * Note: if you change the encapsulation code here, change it in WebCit's ical_encapsulate_subcomponent() */ -void ical_send_out_invitations(icalcomponent *cal) { +void ical_send_out_invitations(icalcomponent *top_level_cal, icalcomponent *cal) { icalcomponent *the_request = NULL; char *serialized_request = NULL; icalcomponent *encaps = NULL; @@ -1810,6 +1925,13 @@ void ical_send_out_invitations(icalcomponent *cal) { char summary_string[SIZ]; icalproperty *summary = NULL; size_t reqsize; + icalproperty *p; + struct icaltimetype t; + icaltimezone *attached_zones[5] = { NULL, NULL, NULL, NULL, NULL }; + int i; + icaltimezone *z; + int num_zones_attached = 0; + int zone_already_attached; if (cal == NULL) { CtdlLogPrintf(CTDL_ERR, "ERROR: trying to reply to NULL event?\n"); @@ -1819,7 +1941,7 @@ void ical_send_out_invitations(icalcomponent *cal) { /* If this is a VCALENDAR component, look for a VEVENT subcomponent. */ if (icalcomponent_isa(cal) == ICAL_VCALENDAR_COMPONENT) { - ical_send_out_invitations( + ical_send_out_invitations(top_level_cal, icalcomponent_get_first_component( cal, ICAL_VEVENT_COMPONENT ) @@ -1879,8 +2001,7 @@ void ical_send_out_invitations(icalcomponent *cal) { /* Encapsulate the VEVENT component into a complete VCALENDAR */ encaps = icalcomponent_new_vcalendar(); if (encaps == NULL) { - CtdlLogPrintf(CTDL_DEBUG, "Error at %s:%d - could not allocate component!\n", - __FILE__, __LINE__); + CtdlLogPrintf(CTDL_DEBUG, "ERROR: could not allocate component!\n"); icalcomponent_free(the_request); return; } @@ -1894,20 +2015,101 @@ void ical_send_out_invitations(icalcomponent *cal) { /* Set the method to REQUEST */ icalcomponent_set_method(encaps, ICAL_METHOD_REQUEST); - /* Now make sure all of the DTSTART and DTEND properties are UTC. */ - ical_dezonify(the_request); + /* Look for properties containing timezone parameters, to see if we need to attach VTIMEZONEs */ + for (p = icalcomponent_get_first_property(the_request, ICAL_ANY_PROPERTY); + p != NULL; + p = icalcomponent_get_next_property(the_request, ICAL_ANY_PROPERTY)) + { + if ( (icalproperty_isa(p) == ICAL_COMPLETED_PROPERTY) + || (icalproperty_isa(p) == ICAL_CREATED_PROPERTY) + || (icalproperty_isa(p) == ICAL_DATEMAX_PROPERTY) + || (icalproperty_isa(p) == ICAL_DATEMIN_PROPERTY) + || (icalproperty_isa(p) == ICAL_DTEND_PROPERTY) + || (icalproperty_isa(p) == ICAL_DTSTAMP_PROPERTY) + || (icalproperty_isa(p) == ICAL_DTSTART_PROPERTY) + || (icalproperty_isa(p) == ICAL_DUE_PROPERTY) + || (icalproperty_isa(p) == ICAL_EXDATE_PROPERTY) + || (icalproperty_isa(p) == ICAL_LASTMODIFIED_PROPERTY) + || (icalproperty_isa(p) == ICAL_MAXDATE_PROPERTY) + || (icalproperty_isa(p) == ICAL_MINDATE_PROPERTY) + || (icalproperty_isa(p) == ICAL_RECURRENCEID_PROPERTY) + ) { + t = icalproperty_get_dtstart(p); // it's safe to use dtstart for all of them + CtdlLogPrintf(CTDL_DEBUG, "Found an icaltimetype: %s\n", + icaltime_as_ical_string(t) + ); + + /* First see if there's a timezone attached to the data structure itself */ + if (icaltime_is_utc(t)) { + z = icaltimezone_get_utc_timezone(); + } + else { + z = icaltime_get_timezone(t); + } + if (z) CtdlLogPrintf(CTDL_DEBUG, "Timezone is present in data structure\n"); + + /* If not, try to determine the tzid from the parameter using attached zones */ + if (!z) { + z = icalcomponent_get_timezone(top_level_cal, + icalparameter_get_tzid( + icalproperty_get_first_parameter(p, ICAL_TZID_PARAMETER) + ) + ); + if (z) CtdlLogPrintf(CTDL_DEBUG, "Timezone was found in attached zones\n"); + } + + /* Still no good? Try our internal database */ + if (!z) { + z = icaltimezone_get_builtin_timezone_from_tzid( + icalparameter_get_tzid( + icalproperty_get_first_parameter(p, ICAL_TZID_PARAMETER) + ) + ); + if (z) CtdlLogPrintf(CTDL_DEBUG, "Timezone was found in internal db\n"); + } - /* Here we go: put the VEVENT into the VCALENDAR. We now no longer + if (z) { + CtdlLogPrintf(CTDL_DEBUG, "Have valid timezone, need to attach it.\n"); + + zone_already_attached = 0; + for (i=0; i<5; ++i) { + if (z == attached_zones[i]) { + ++zone_already_attached; + CtdlLogPrintf(CTDL_DEBUG, "zone already attached!!\n"); + } + } + if ((!zone_already_attached) && (num_zones_attached < 5)) { + CtdlLogPrintf(CTDL_DEBUG, "attach zone %d\n", num_zones_attached); + attached_zones[num_zones_attached++] = z; + } + + icalproperty_set_parameter(p, + icalparameter_new_tzid(icaltimezone_get_tzid(z)) + ); + } + } + } + + /* Encapsulate any timezones we need */ + if (num_zones_attached > 0) for (i=0; i