X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fcalendar%2Fserv_calendar.c;h=1dd5935e045f3459d88804e52659b4e08e7685d0;hb=8c47559cb5ae97ec0fa35660ee16fd61a9451c72;hp=8f49b4e85c94fe83f30ea32f94b07bee7efd474b;hpb=5aeb0a36671245d0012dc5de2b661c7915560a9c;p=citadel.git diff --git a/citadel/modules/calendar/serv_calendar.c b/citadel/modules/calendar/serv_calendar.c index 8f49b4e85..1dd5935e0 100644 --- a/citadel/modules/calendar/serv_calendar.c +++ b/citadel/modules/calendar/serv_calendar.c @@ -5,6 +5,22 @@ * room on a Citadel server. It handles iCalendar objects using the * iTIP protocol. See RFCs 2445 and 2446. * + * + * Copyright (c) 1987-2009 by the citadel.org team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define PRODID "-//Citadel//NONSGML Citadel Calendar//EN" @@ -808,51 +824,64 @@ int ical_ctdl_is_overlap( struct icaltimetype t2start, struct icaltimetype t2end ) { - if (icaltime_is_null_time(t1start)) return(0); if (icaltime_is_null_time(t2start)) return(0); - /* First, check for all-day events */ - if (t1start.is_date) { - if (!icaltime_compare_date_only(t1start, t2start)) { - return(1); - } - if (!icaltime_is_null_time(t2end)) { - if (!icaltime_compare_date_only(t1start, t2end)) { - return(1); - } + /* if either event lacks end time, assume end = start */ + if (icaltime_is_null_time(t1end)) + memcpy(&t1end, &t1start, sizeof(struct icaltimetype)); + else { + if (t1end.is_date && icaltime_compare(t1start, t1end)) { + /* + * the end date is non-inclusive so adjust it by one + * day because our test is inclusive, note that a day is + * not too much because we are talking about all day + * events + * if start = end we assume that nevertheless the whole + * day is meant + */ + icaltime_adjust(&t1end, -1, 0, 0, 0); } } - if (t2start.is_date) { - if (!icaltime_compare_date_only(t2start, t1start)) { - return(1); - } - if (!icaltime_is_null_time(t1end)) { - if (!icaltime_compare_date_only(t2start, t1end)) { - return(1); - } + if (icaltime_is_null_time(t2end)) + memcpy(&t2end, &t2start, sizeof(struct icaltimetype)); + else { + if (t2end.is_date && icaltime_compare(t2start, t2end)) { + icaltime_adjust(&t2end, -1, 0, 0, 0); } } - /* Now check for overlaps using date *and* time. */ + /* First, check for all-day events */ + if (t1start.is_date || t2start.is_date) { + /* If event 1 ends before event 2 starts, we're in the clear. */ + if (icaltime_compare_date_only(t1end, t2start) < 0) return(0); + + /* If event 2 ends before event 1 starts, we're also ok. */ + if (icaltime_compare_date_only(t2end, t1start) < 0) return(0); + + return(1); + } + + /* lprintf (9, "Comparing t1start %d:%d t1end %d:%d t2start %d:%d t2end %d:%d \n", + t1start.hour, t1start.minute, t1end.hour, t1end.minute, + t2start.hour, t2start.minute, t2end.hour, t2end.minute); + */ - /* First, bail out if either event 1 or event 2 is missing end time. */ - if (icaltime_is_null_time(t1end)) return(0); - if (icaltime_is_null_time(t2end)) return(0); + /* Now check for overlaps using date *and* time. */ /* If event 1 ends before event 2 starts, we're in the clear. */ if (icaltime_compare(t1end, t2start) <= 0) return(0); + /* lprintf(9, "first passed\n"); */ /* If event 2 ends before event 1 starts, we're also ok. */ if (icaltime_compare(t2end, t1start) <= 0) return(0); + /* lprintf(9, "second passed\n"); */ /* Otherwise, they overlap. */ return(1); } - - /* * Phase 6 of "hunt for conflicts" * called by ical_conflicts_phase5() @@ -1280,7 +1309,6 @@ void ical_add_to_freebusy(icalcomponent *fb, icalcomponent *top_level_cal) { dtstart.zone = get_default_icaltimezone(); } } - // FIXME do more here dtend = icalcomponent_get_dtend(cal); if (!icaltime_is_null_time(dtend)) { @@ -1295,23 +1323,24 @@ void ical_add_to_freebusy(icalcomponent *fb, icalcomponent *top_level_cal) { } do { - - - // FIXME add timezone conversion, we are currently outputting floating times - - CtdlLogPrintf(CTDL_DEBUG, "Start, utc=%d, %s\n", - dtstart.is_utc, - icaltime_as_ical_string(dtstart) - ); - - - /* Convert the DTSTART and DTEND properties to an icalperiod. */ this_event_period.start = dtstart; if (!icaltime_is_null_time(dtend)) { this_event_period.end = dtend; } + + /* Convert the timestamps to UTC. It's ok to do this because we've already expanded + * recurrences and this data is never going to get used again. + */ + this_event_period.start = icaltime_convert_to_zone( + this_event_period.start, + icaltimezone_get_utc_timezone() + ); + this_event_period.end = icaltime_convert_to_zone( + this_event_period.end, + icaltimezone_get_utc_timezone() + ); /* Now add it. */ icalcomponent_add_property(fb, icalproperty_new_freebusy(this_event_period)); @@ -1321,11 +1350,11 @@ void ical_add_to_freebusy(icalcomponent *fb, icalcomponent *top_level_cal) { */ p = icalcomponent_get_first_property(fb, ICAL_DTSTART_PROPERTY); if (p == NULL) { - icalcomponent_set_dtstart(fb, dtstart); + icalcomponent_set_dtstart(fb, this_event_period.start); } else { - if (icaltime_compare(dtstart, icalcomponent_get_dtstart(fb)) < 0) { - icalcomponent_set_dtstart(fb, dtstart); + if (icaltime_compare(this_event_period.start, icalcomponent_get_dtstart(fb)) < 0) { + icalcomponent_set_dtstart(fb, this_event_period.start); } } @@ -1334,11 +1363,11 @@ void ical_add_to_freebusy(icalcomponent *fb, icalcomponent *top_level_cal) { */ p = icalcomponent_get_first_property(fb, ICAL_DTEND_PROPERTY); if (p == NULL) { - icalcomponent_set_dtend(fb, dtend); + icalcomponent_set_dtend(fb, this_event_period.end); } else { - if (icaltime_compare(dtend, icalcomponent_get_dtend(fb)) > 0) { - icalcomponent_set_dtend(fb, dtend); + if (icaltime_compare(this_event_period.end, icalcomponent_get_dtend(fb)) > 0) { + icalcomponent_set_dtend(fb, this_event_period.end); } } @@ -1346,6 +1375,8 @@ void ical_add_to_freebusy(icalcomponent *fb, icalcomponent *top_level_cal) { dtstart = icalrecur_iterator_next(ritr); if (!icaltime_is_null_time(dtend)) { dtend = icaltime_add(dtstart, dur); + dtend.zone = dtstart.zone; + dtend.is_utc = dtstart.is_utc; } ++num_recur; } @@ -1648,7 +1679,7 @@ void ical_getics(void) encaps = icalcomponent_new_vcalendar(); if (encaps == NULL) { - CtdlLogPrintf(CTDL_DEBUG, "ERROR: could not allocate component!\n"); + CtdlLogPrintf(CTDL_ALERT, "ERROR: could not allocate component!\n"); cprintf("%d Could not allocate memory\n", ERROR+INTERNAL_ERROR); return; } @@ -1973,11 +2004,13 @@ void ical_send_out_invitations(icalcomponent *top_level_cal, icalcomponent *cal) size_t reqsize; icalproperty *p; struct icaltimetype t; - icaltimezone *attached_zones[5] = { NULL, NULL, NULL, NULL, NULL }; + const icaltimezone *attached_zones[5] = { NULL, NULL, NULL, NULL, NULL }; int i; - icaltimezone *z; + const icaltimezone *z; int num_zones_attached = 0; int zone_already_attached; + icalparameter *tzidp = NULL; + const char *tzidc = NULL; if (cal == NULL) { CtdlLogPrintf(CTDL_ERR, "ERROR: trying to reply to NULL event?\n"); @@ -2047,7 +2080,7 @@ void ical_send_out_invitations(icalcomponent *top_level_cal, icalcomponent *cal) /* Encapsulate the VEVENT component into a complete VCALENDAR */ encaps = icalcomponent_new_vcalendar(); if (encaps == NULL) { - CtdlLogPrintf(CTDL_DEBUG, "ERROR: could not allocate component!\n"); + CtdlLogPrintf(CTDL_ALERT, "ERROR: could not allocate component!\n"); icalcomponent_free(the_request); return; } @@ -2081,9 +2114,15 @@ void ical_send_out_invitations(icalcomponent *top_level_cal, icalcomponent *cal) || (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) - ); + + /* Determine the tzid in order for some of the conditions below to work */ + tzidp = icalproperty_get_first_parameter(p, ICAL_TZID_PARAMETER); + if (tzidp) { + tzidc = icalparameter_get_tzid(tzidp); + } + else { + tzidc = NULL; + } /* First see if there's a timezone attached to the data structure itself */ if (icaltime_is_utc(t)) { @@ -2092,40 +2131,29 @@ void ical_send_out_invitations(icalcomponent *top_level_cal, icalcomponent *cal) 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"); + if ((!z) && (tzidc)) { + z = icalcomponent_get_timezone(top_level_cal, tzidc); } /* 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"); + if ((!z) && (tzidc)) { + z = icaltimezone_get_builtin_timezone_from_tzid(tzidc); } if (z) { - CtdlLogPrintf(CTDL_DEBUG, "Have valid timezone, need to attach it.\n"); + /* We have a valid timezone. Good. Now we need to attach it. */ zone_already_attached = 0; for (i=0; i<5; ++i) { if (z == attached_zones[i]) { + /* We've already got this one, no need to attach another. */ ++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); + /* This is a new one, so attach it. */ attached_zones[num_zones_attached++] = z; } @@ -2154,8 +2182,6 @@ void ical_send_out_invitations(icalcomponent *top_level_cal, icalcomponent *cal) icalcomponent_free(encaps); /* Don't need this anymore. */ if (serialized_request == NULL) return; - CtdlLogPrintf(CTDL_DEBUG, "SENDING INVITATIONS:\n%s\n", serialized_request); - reqsize = strlen(serialized_request) + SIZ; request_message_text = malloc(reqsize); if (request_message_text != NULL) { @@ -2164,16 +2190,20 @@ void ical_send_out_invitations(icalcomponent *top_level_cal, icalcomponent *cal) serialized_request ); - msg = CtdlMakeMessage(&CC->user, - "", /* No single recipient here */ - "", /* No single recipient here */ - CC->room.QRname, 0, FMT_RFC822, - "", - "", + msg = CtdlMakeMessage( + &CC->user, + NULL, /* No single recipient here */ + NULL, /* No single recipient here */ + CC->room.QRname, + 0, + FMT_RFC822, + NULL, + NULL, summary_string, /* Use summary for subject */ NULL, request_message_text, - NULL); + NULL + ); if (msg != NULL) { valid = validate_recipients(attendees_string, NULL, 0);