* Conflict checker loop now stops iterating over existing events when it goes out...
[citadel.git] / citadel / modules / calendar / serv_calendar.c
index 4c9ad42425f172e2845300231a9b7279bb4fa772..05504d3a7bac99eeb4d977039aa160364649708f 100644 (file)
@@ -870,15 +870,16 @@ void ical_conflicts_phase6(struct icaltimetype t1start,
 {
 
        /* 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));
+       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));
+       /* debugging cruft */
 
        /* compare and output */
 
@@ -922,6 +923,7 @@ void ical_conflicts_phase5(struct icaltimetype t1start,
        icalrecur_iterator *ritr = NULL;
        struct icaldurationtype dur;
        int num_recur = 0;
+       int out_of_scope = 0;
 
        /* initialization */
        strcpy(conflict_event_uid, "");
@@ -970,7 +972,12 @@ void ical_conflicts_phase5(struct icaltimetype t1start,
                        ++num_recur;
                }
 
-       } while ( (rrule) && (!icaltime_is_null_time(t2start)) && (num_recur < MAX_RECUR) );
+               if (icaltime_compare(t2start, t1end) < 0) {
+                       CtdlLogPrintf(CTDL_DEBUG, "Went out of scope after %d iterations\n", num_recur);
+                       out_of_scope = 1;
+               }
+
+       } while ((rrule) && (!icaltime_is_null_time(t2start)) && (num_recur < MAX_RECUR) && (!out_of_scope));
        icalrecur_iterator_free(ritr);
        if (num_recur > 0) CtdlLogPrintf(CTDL_DEBUG, "Iterated over existing event %d times.\n", num_recur);
 }
@@ -1497,7 +1504,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);
        }
@@ -1547,11 +1571,26 @@ void ical_getics(void)
        );
 
        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);
+       }
 }
 
 
@@ -1564,13 +1603,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;
@@ -1587,7 +1634,7 @@ void ical_putics(void)
 
        /* 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!)
         */
@@ -1607,7 +1654,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);
+                       }
                }
        }
 
@@ -1776,9 +1871,9 @@ void ical_send_out_invitations(icalcomponent *top_level_cal, icalcomponent *cal)
        size_t reqsize;
        icalproperty *p;
        struct icaltimetype t;
-       const icaltimezone *attached_zones[5] = { NULL, NULL, NULL, NULL, NULL };
+       icaltimezone *attached_zones[5] = { NULL, NULL, NULL, NULL, NULL };
        int i;
-       const icaltimezone *z;
+       icaltimezone *z;
        int num_zones_attached = 0;
        int zone_already_attached;
 
@@ -1889,7 +1984,12 @@ void ical_send_out_invitations(icalcomponent *top_level_cal, icalcomponent *cal)
                        );
 
                        /* First see if there's a timezone attached to the data structure itself */
-                       z = icaltime_get_timezone(t);
+                       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 */