/** * e_cal_util_is_first_instance: * @comp: an #ECalComponent instance * @rid: a recurrence ID * @tz_cb: (closure tz_cb_data) (scope call): The #ECalRecurResolveTimezoneFn to call * @tz_cb_data: (closure): User data to be passed to the @tz_cb callback * * Returns whether the given @rid is the first instance of * the recurrence defined in the @comp. * * Return: Whether the @rid identifies the first instance of @comp. * * Since: 3.16 **/ gboolean e_cal_util_is_first_instance (ECalComponent *comp, struct icaltimetype rid, ECalRecurResolveTimezoneFn tz_cb, gpointer tz_cb_data) { CheckFirstInstanceData ifs; icalcomponent *icalcomp; time_t start, end; g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE); g_return_val_if_fail (!icaltime_is_null_time (rid), FALSE); ifs.rid = rid; ifs.matches = FALSE; icalcomp = e_cal_component_get_icalcomponent (comp); start = icaltime_as_timet (icalcomponent_get_dtstart (icalcomp)) - 24 * 60 * 60; end = icaltime_as_timet (icalcomponent_get_dtend (icalcomp)) + 24 * 60 * 60; e_cal_recur_generate_instances (comp, start, end, check_first_instance_cb, &ifs, tz_cb, tz_cb_data, icaltimezone_get_utc_timezone ()); return ifs.matches; }
static gboolean get_ical_is_all_day (icalcomponent *ical, time_t start_time, icaltimezone *default_zone) { icalproperty *prop; struct tm *start_tm; time_t end_time; struct icaldurationtype duration; struct icaltimetype start_icaltime; start_icaltime = icalcomponent_get_dtstart (ical); if (start_icaltime.is_date) return TRUE; start_tm = gmtime (&start_time); if (start_tm->tm_sec != 0 || start_tm->tm_min != 0 || start_tm->tm_hour != 0) return FALSE; if ((end_time = get_ical_end_time (ical, default_zone))) return (end_time - start_time) % 86400 == 0; prop = icalcomponent_get_first_property (ical, ICAL_DURATION_PROPERTY); if (!prop) return FALSE; duration = icalproperty_get_duration (prop); return icaldurationtype_as_int (duration) % 86400 == 0; }
static gboolean check_first_instance_cb (ECalComponent *comp, time_t instance_start, time_t instance_end, gpointer user_data) { CheckFirstInstanceData *ifs = user_data; icalcomponent *icalcomp; struct icaltimetype rid; g_return_val_if_fail (ifs != NULL, FALSE); icalcomp = e_cal_component_get_icalcomponent (comp); if (icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY) != NULL) { rid = icalcomponent_get_recurrenceid (icalcomp); } else { struct icaltimetype dtstart; dtstart = icalcomponent_get_dtstart (icalcomp); if (dtstart.zone) { rid = icaltime_from_timet_with_zone (instance_start, dtstart.is_date, dtstart.zone); } else { rid = icaltime_from_timet (instance_start, dtstart.is_date); } } ifs->matches = icaltime_compare (ifs->rid, rid) == 0; return FALSE; }
static void adjust_dtstart_day_to_rrule (icalcomponent *comp, struct icalrecurrencetype rule) { time_t now, year_start; struct icaltimetype start, comp_start, iter_start, itime; icalrecur_iterator *iter; now = time (NULL); itime = icaltime_from_timet (now, 0); itime.month = itime.day = 1; itime.hour = itime.minute = itime.second = 0; year_start = icaltime_as_timet(itime); comp_start = icalcomponent_get_dtstart (comp); start = icaltime_from_timet (year_start, 0); iter = icalrecur_iterator_new (rule, start); iter_start = icalrecur_iterator_next (iter); icalrecur_iterator_free (iter); if (iter_start.day != comp_start.day) { comp_start.day = iter_start.day; icalcomponent_set_dtstart (comp, comp_start); } }
/** * e_cal_util_event_dates_match: * @icalcomp1: An #icalcomponent. * @icalcomp2: An #icalcomponent. * * Compare the dates of two #icalcomponent's to check if they match. * * Returns: TRUE if the dates of both components match, FALSE otherwise. */ gboolean e_cal_util_event_dates_match (icalcomponent *icalcomp1, icalcomponent *icalcomp2) { struct icaltimetype c1_dtstart, c1_dtend, c2_dtstart, c2_dtend; g_return_val_if_fail (icalcomp1 != NULL, FALSE); g_return_val_if_fail (icalcomp2 != NULL, FALSE); c1_dtstart = icalcomponent_get_dtstart (icalcomp1); c1_dtend = icalcomponent_get_dtend (icalcomp1); c2_dtstart = icalcomponent_get_dtstart (icalcomp2); c2_dtend = icalcomponent_get_dtend (icalcomp2); /* if either value is NULL, they must both be NULL to match */ if (icaltime_is_valid_time (c1_dtstart) || icaltime_is_valid_time (c2_dtstart)) { if (!(icaltime_is_valid_time (c1_dtstart) && icaltime_is_valid_time (c2_dtstart))) return FALSE; } else { if (icaltime_compare (c1_dtstart, c2_dtstart)) return FALSE; } if (icaltime_is_valid_time (c1_dtend) || icaltime_is_valid_time (c2_dtend)) { if (!(icaltime_is_valid_time (c1_dtend) && icaltime_is_valid_time (c2_dtend))) return FALSE; } else { if (icaltime_compare (c1_dtend, c2_dtend)) return FALSE; } /* now match the timezones */ if (!(!c1_dtstart.zone && !c2_dtstart.zone) || (c1_dtstart.zone && c2_dtstart.zone && !strcmp (icaltimezone_get_tzid ((icaltimezone *) c1_dtstart.zone), icaltimezone_get_tzid ((icaltimezone *) c2_dtstart.zone)))) return FALSE; if (!(!c1_dtend.zone && !c2_dtend.zone) || (c1_dtend.zone && c2_dtend.zone && !strcmp (icaltimezone_get_tzid ((icaltimezone *) c1_dtend.zone), icaltimezone_get_tzid ((icaltimezone *) c2_dtend.zone)))) return FALSE; return TRUE; }
static void event_time (icalcomponent * icalcomp, gchar * str, size_t len, DNTimeFormat format) { struct icaltimetype istart, iend; struct tm tm_start, tm_end; istart = icalcomponent_get_dtstart (icalcomp); iend = icalcomponent_get_dtend (icalcomp); tm_start = icaltimetype_to_tm (&istart); tm_end = icaltimetype_to_tm (&iend); gint offset = 0; if (format == DN_TimeOnly) { offset = e_utf8_strftime (str, len, "%R", &tm_start); str += offset; *str++ = ' '; *str++ = '-'; *str++ = ' '; len -= (offset + 3); g_assert (len > 0); e_utf8_strftime (str, len, "%R", &tm_end); } else { offset = e_utf8_strftime (str, len, "%x", &tm_start); str += offset; *str++ = ' '; *str++ = ' '; len -= (offset + 2); g_assert (len > 0); offset = e_utf8_strftime (str, len, "%R", &tm_start); str += offset; *str++ = '-'; len -= (offset + 1); g_assert (len > 0); e_utf8_strftime (str, len, "%R", &tm_end); } }
/** * e_cal_util_split_at_instance: * @icalcomp: A (recurring) #icalcomponent * @rid: The base RECURRENCE-ID to remove * @master_dtstart: The DTSTART of the master object * * Splits a recurring @icalcomp into two at time @rid. The returned icalcomponent * is modified @icalcomp which contains recurrences beginning at @rid, inclusive. * The instance identified by @rid should exist. The @master_dtstart can be * a null time, then it is read from the @icalcomp. * * Use e_cal_util_remove_instances() with E_CAL_OBJ_MOD_THIS_AND_FUTURE mode * on the @icalcomp to remove the overlapping interval from it, if needed. * * Returns: the split icalcomponent, or %NULL. * * Since: 3.16 **/ icalcomponent * e_cal_util_split_at_instance (icalcomponent *icalcomp, struct icaltimetype rid, struct icaltimetype master_dtstart) { icalproperty *prop; struct instance_data instance; struct icaltimetype start, end; struct icaldurationtype duration; GSList *remove_props = NULL, *link; g_return_val_if_fail (icalcomp != NULL, NULL); g_return_val_if_fail (!icaltime_is_null_time (rid), NULL); /* Make sure this is really recurring */ if (!icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY) && !icalcomponent_get_first_property (icalcomp, ICAL_RDATE_PROPERTY)) return NULL; /* Make sure the specified instance really exists */ start = icaltime_convert_to_zone (rid, icaltimezone_get_utc_timezone ()); end = start; icaltime_adjust (&end, 0, 0, 0, 1); instance.start = icaltime_as_timet (start); instance.found = FALSE; icalcomponent_foreach_recurrence (icalcomp, start, end, check_instance, &instance); /* Make the copy */ icalcomp = icalcomponent_new_clone (icalcomp); e_cal_util_remove_instances_ex (icalcomp, rid, E_CAL_OBJ_MOD_THIS_AND_PRIOR, TRUE, FALSE); start = rid; if (icaltime_is_null_time (master_dtstart)) master_dtstart = icalcomponent_get_dtstart (icalcomp); duration = icalcomponent_get_duration (icalcomp); /* Expect that DTSTART and DTEND are already set when the instance could not be found */ if (instance.found) { icalcomponent_set_dtstart (icalcomp, start); /* Update either DURATION or DTEND */ if (icaltime_is_null_time (icalcomponent_get_dtend (icalcomp))) { icalcomponent_set_duration (icalcomp, duration); } else { end = start; if (duration.is_neg) icaltime_adjust (&end, -duration.days - 7 * duration.weeks, -duration.hours, -duration.minutes, -duration.seconds); else icaltime_adjust (&end, duration.days + 7 * duration.weeks, duration.hours, duration.minutes, duration.seconds); icalcomponent_set_dtend (icalcomp, end); } } /* any RRULE with 'count' should be shortened */ for (prop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY); prop; prop = icalcomponent_get_next_property (icalcomp, ICAL_RRULE_PROPERTY)) { struct icaltimetype recur; struct icalrecurrencetype rule; rule = icalproperty_get_rrule (prop); if (rule.count != 0) { gint occurrences_count = 0; icalrecur_iterator *iter; iter = icalrecur_iterator_new (rule, master_dtstart); while (recur = icalrecur_iterator_next (iter), !icaltime_is_null_time (recur) && occurrences_count < rule.count) { if (icaltime_compare (recur, rid) >= 0) break; occurrences_count++; } icalrecur_iterator_free (iter); if (icaltime_is_null_time (recur)) { remove_props = g_slist_prepend (remove_props, prop); } else { rule.count -= occurrences_count; icalproperty_set_rrule (prop, rule); icalproperty_remove_parameter_by_name (prop, "X-EVOLUTION-ENDDATE"); } } } for (link = remove_props; link; link = g_slist_next (link)) { prop = link->data; icalcomponent_remove_property (icalcomp, prop); } g_slist_free (remove_props); return icalcomp; }
static void e_cal_util_remove_instances_ex (icalcomponent *icalcomp, struct icaltimetype rid, ECalObjModType mod, gboolean keep_rid, gboolean can_add_exrule) { icalproperty *prop; struct icaltimetype itt, recur; struct icalrecurrencetype rule; icalrecur_iterator *iter; GSList *remove_props = NULL, *rrules = NULL, *link; g_return_if_fail (icalcomp != NULL); g_return_if_fail (mod != E_CAL_OBJ_MOD_ALL); /* First remove RDATEs and EXDATEs in the indicated range. */ for (prop = icalcomponent_get_first_property (icalcomp, ICAL_RDATE_PROPERTY); prop; prop = icalcomponent_get_next_property (icalcomp, ICAL_RDATE_PROPERTY)) { struct icaldatetimeperiodtype period; period = icalproperty_get_rdate (prop); if (time_matches_rid (period.time, rid, mod) && (!keep_rid || icaltime_compare (period.time, rid) != 0)) remove_props = g_slist_prepend (remove_props, prop); } for (prop = icalcomponent_get_first_property (icalcomp, ICAL_EXDATE_PROPERTY); prop; prop = icalcomponent_get_next_property (icalcomp, ICAL_EXDATE_PROPERTY)) { itt = icalproperty_get_exdate (prop); if (time_matches_rid (itt, rid, mod) && (!keep_rid || icaltime_compare (itt, rid) != 0)) remove_props = g_slist_prepend (remove_props, prop); } for (link = remove_props; link; link = g_slist_next (link)) { prop = link->data; icalcomponent_remove_property (icalcomp, prop); } g_slist_free (remove_props); remove_props = NULL; /* If we're only removing one instance, just add an EXDATE. */ if (mod == E_CAL_OBJ_MOD_THIS) { prop = icalproperty_new_exdate (rid); icalcomponent_add_property (icalcomp, prop); return; } /* Otherwise, iterate through RRULEs */ /* FIXME: this may generate duplicate EXRULEs */ for (prop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY); prop; prop = icalcomponent_get_next_property (icalcomp, ICAL_RRULE_PROPERTY)) { rrules = g_slist_prepend (rrules, prop); } for (link = rrules; link; link = g_slist_next (link)) { prop = link->data; rule = icalproperty_get_rrule (prop); iter = icalrecur_iterator_new (rule, rid); recur = icalrecur_iterator_next (iter); if (mod & E_CAL_OBJ_MOD_THIS_AND_FUTURE) { /* Truncate the rule at rid. */ if (!icaltime_is_null_time (recur)) { /* Use count if it was used */ if (rule.count > 0) { gint occurrences_count = 0; icalrecur_iterator *count_iter; struct icaltimetype count_recur; count_iter = icalrecur_iterator_new (rule, icalcomponent_get_dtstart (icalcomp)); while (count_recur = icalrecur_iterator_next (count_iter), !icaltime_is_null_time (count_recur) && occurrences_count < rule.count) { if (icaltime_compare (count_recur, rid) >= 0) break; occurrences_count++; } icalrecur_iterator_free (count_iter); if (keep_rid && icaltime_compare (count_recur, rid) == 0) occurrences_count++; /* The caller should make sure that the remove will keep at least one instance */ g_warn_if_fail (occurrences_count > 0); rule.count = occurrences_count; } else { if (keep_rid && icaltime_compare (recur, rid) == 0) rule.until = icaltime_add (rid, icalcomponent_get_duration (icalcomp)); else rule.until = rid; icaltime_adjust (&rule.until, 0, 0, 0, -1); } icalproperty_set_rrule (prop, rule); icalproperty_remove_parameter_by_name (prop, "X-EVOLUTION-ENDDATE"); } } else { /* (If recur == rid, skip to the next occurrence) */ if (!keep_rid && icaltime_compare (recur, rid) == 0) recur = icalrecur_iterator_next (iter); /* If there is a recurrence after rid, add * an EXRULE to block instances up to rid. * Otherwise, just remove the RRULE. */ if (!icaltime_is_null_time (recur)) { if (can_add_exrule) { rule.count = 0; /* iCalendar says we should just use rid * here, but Outlook/Exchange handle * UNTIL incorrectly. */ if (keep_rid && icaltime_compare (recur, rid) == 0) { struct icaldurationtype duration = icalcomponent_get_duration (icalcomp); duration.is_neg = !duration.is_neg; rule.until = icaltime_add (rid, duration); } else rule.until = icaltime_add (rid, icalcomponent_get_duration (icalcomp)); prop = icalproperty_new_exrule (rule); icalcomponent_add_property (icalcomp, prop); } } else { remove_props = g_slist_prepend (remove_props, prop); } } icalrecur_iterator_free (iter); } for (link = remove_props; link; link = g_slist_next (link)) { prop = link->data; icalcomponent_remove_property (icalcomp, prop); } g_slist_free (remove_props); g_slist_free (rrules); }
int main(int argc, char *argv[]) { icalcomponent *c, *next_c = NULL; int i = 0; int dont_remove; icalfileset_options options = { O_RDONLY, 0644, 0, NULL }; icalset *f = icalset_new(ICAL_FILE_SET, TEST_DATADIR "/process-incoming.ics", &options); icalset *trash = icalset_new_file("trash.ics"); icalset *cal = icalset_new(ICAL_FILE_SET, TEST_DATADIR "/process-calendar.ics", &options); icalset *out = icalset_new_file("outgoing.ics"); const char *this_user = "******"; _unused(argc); _unused(argv); assert(f != 0); assert(cal != 0); assert(trash != 0); assert(out != 0); /* Foreach incoming message */ for (c = icalset_get_first_component(f); c != 0; c = next_c) { icalproperty_xlicclass class; icalcomponent *match; icalcomponent *inner; icalcomponent *reply = 0; assert(c != 0); inner = icalcomponent_get_first_real_component(c); i++; reply = 0; dont_remove = 0; if (inner == 0) { printf("Bad component, no inner\n %s\n", icalcomponent_as_ical_string(c)); continue; } /* Find a booked component that is matched to the incoming message, based on the incoming component's UID, SEQUENCE and RECURRENCE-ID */ match = icalset_fetch_match(cal, c); class = icalclassify(c, match, this_user); /* Print out the notes associated with the incoming component and the matched component in the */ { const char *inc_note = 0; const char *match_note = 0; icalproperty *p; for (p = icalcomponent_get_first_property(c, ICAL_X_PROPERTY); p != 0; p = icalcomponent_get_next_property(c, ICAL_X_PROPERTY)) { if (strcmp(icalproperty_get_x_name(p), "X-LIC-NOTE") == 0) { inc_note = icalproperty_get_x(p); } } if (match != 0) { for (p = icalcomponent_get_first_property(match, ICAL_X_PROPERTY); p != 0; p = icalcomponent_get_next_property(match, ICAL_X_PROPERTY)) { if (strcmp(icalproperty_get_x_name(p), "X-LIC-NOTE") == 0) { match_note = icalproperty_get_x(p); } } } if (inc_note != 0) { printf("Incoming: %s\n", inc_note); } if (match_note != 0) { printf("Match : %s\n", match_note); } } /* Main processing structure */ switch (class) { case ICAL_XLICCLASS_NONE:{ char temp[1024]; /* Huh? Return an error to sender */ icalrestriction_check(c); icalcomponent_convert_errors(c); snprintf(temp, 1024, "I can't understand the component you sent.\n" "Here is the component you sent, possibly with error messages:\n" "%s", icalcomponent_as_ical_string(c)); reply = icalmessage_new_error_reply(c, this_user, temp, "", ICAL_UNKNOWN_STATUS); break; } case ICAL_XLICCLASS_PUBLISHNEW:{ /* Don't accept published events from anyone but self. If self, fall through to ICAL_XLICCLASS_REQUESTNEW */ } case ICAL_XLICCLASS_REQUESTNEW:{ /* Book the new component if it does not overlap anything. If the time is busy and the start time is an even modulo 4, delegate to [email protected]. If the time is busy and is 1 modulo 4, counterpropose for the first available free time. Otherwise, deline the meeting */ icalcomponent *overlaps = icalclassify_find_overlaps(cal, c); if (overlaps == 0) { /* No overlaps, book the meeting */ /* icalset_add_component(cal,icalcomponent_new_clone(c));*/ /* Return a reply */ reply = icalmessage_new_accept_reply( c, this_user, "I can make it to this meeting"); (void)icalset_add_component(out, reply); } else { /* There was a conflict, so delegate, counterpropose or decline it */ struct icaltimetype dtstart = icalcomponent_get_dtstart(c); if (dtstart.hour % 4 == 0) { /* Delegate the meeting */ reply = icalmessage_new_delegate_reply( c, this_user, "*****@*****.**", "Unfortunately, I have another commitment that conflicts " "with this meeting. I am delegating my attendance to Bob."); (void)icalset_add_component(out, reply); } else if (dtstart.hour % 4 == 1) { /* Counter propose to next available time */ icalcomponent *newc; struct icalperiodtype next_time; icalspanlist *spanl = icalspanlist_new(cal, dtstart, icaltime_null_time()); next_time = icalspanlist_next_free_time(spanl, icalcomponent_get_dtstart(c)); newc = icalcomponent_new_clone(c); icalcomponent_set_dtstart(newc, next_time.start); /* Hack, the duration of the counterproposed meeting may be longer than the free time available */ icalcomponent_set_duration(newc, icalcomponent_get_duration(c)); reply = icalmessage_new_counterpropose_reply( c, newc, this_user, "Unfortunately, I have another commitment that conflicts with " "this meeting. I am proposing a time that works better for me."); (void)icalset_add_component(out, reply); icalspanlist_free(spanl); icalcomponent_free(newc); } else { /* Decline the meeting */ reply = icalmessage_new_decline_reply( c, this_user, "I can't make it to this meeting"); (void)icalset_add_component(out, reply); } } icalcomponent_free(overlaps); break; } case ICAL_XLICCLASS_PUBLISHFREEBUSY:{ /* Store the busy time information in a file named after the sender */ break; } case ICAL_XLICCLASS_PUBLISHUPDATE:{ /* Only accept publish updates from self. If self, fall through to ICAL_XLICCLASS_REQUESTUPDATE */ } case ICAL_XLICCLASS_REQUESTUPDATE:{ /* always accept the changes */ break; } case ICAL_XLICCLASS_REQUESTRESCHEDULE:{ /* Use same rules as REQUEST_NEW */ (void)icalclassify_find_overlaps(cal, c); break; } case ICAL_XLICCLASS_REQUESTDELEGATE:{ break; } case ICAL_XLICCLASS_REQUESTNEWORGANIZER:{ break; } case ICAL_XLICCLASS_REQUESTFORWARD:{ break; } case ICAL_XLICCLASS_REQUESTSTATUS:{ break; } case ICAL_XLICCLASS_REQUESTFREEBUSY:{ break; } case ICAL_XLICCLASS_REPLYACCEPT:{ /* Change the PARTSTAT of the sender */ break; } case ICAL_XLICCLASS_REPLYDECLINE:{ /* Change the PARTSTAT of the sender */ break; } case ICAL_XLICCLASS_REPLYCRASHERACCEPT:{ /* Add the crasher to the ATTENDEE list with the appropriate PARTSTAT */ break; } case ICAL_XLICCLASS_REPLYCRASHERDECLINE:{ /* Add the crasher to the ATTENDEE list with the appropriate PARTSTAT */ break; } case ICAL_XLICCLASS_ADDINSTANCE:{ break; } case ICAL_XLICCLASS_CANCELEVENT:{ /* Remove the component */ break; } case ICAL_XLICCLASS_CANCELINSTANCE:{ break; } case ICAL_XLICCLASS_CANCELALL:{ /* Remove the component */ break; } case ICAL_XLICCLASS_REFRESH:{ /* Resend the latest copy of the request */ break; } case ICAL_XLICCLASS_COUNTER:{ break; } case ICAL_XLICCLASS_DECLINECOUNTER:{ break; } case ICAL_XLICCLASS_MALFORMED:{ /* Send back an error */ break; } case ICAL_XLICCLASS_OBSOLETE:{ printf(" ** Got an obsolete component:\n%s", icalcomponent_as_ical_string(c)); /* Send back an error */ break; } case ICAL_XLICCLASS_MISSEQUENCED:{ printf(" ** Got a missequenced component:\n%s", icalcomponent_as_ical_string(c)); /* Send back an error */ break; } case ICAL_XLICCLASS_UNKNOWN:{ printf(" ** Don't know what to do with this component:\n%s", icalcomponent_as_ical_string(c)); /* Send back an error */ break; } case ICAL_XLICCLASS_X: case ICAL_XLICCLASS_REPLYDELEGATE: default:{ } } #if 0 if (reply != 0) { /* Don't send the reply if the RSVP parameter indicates not to */ icalcomponent *reply_inner; icalproperty *attendee; icalparameter *rsvp; reply_inner = icalcomponent_get_first_real_component(reply); attendee = icalcomponent_get_first_property(reply_inner, ICAL_ATTENDEE_PROPERTY); rsvp = icalproperty_get_first_parameter(attendee, ICAL_RSVP_PARAMETER); if (rsvp == 0 || icalparameter_get_rsvp(rsvp) == 1) { icalrestriction_check(reply); send_message(reply, this_user); } icalcomponent_free(reply); } #endif if (reply != 0) { printf("%s\n", icalcomponent_as_ical_string(reply)); } next_c = icalset_get_next_component(f); if (dont_remove == 0) { /*icalset_remove_component(f,c); icalset_add_component(trash,c); */ } } #if 0 for (c = icalset_get_first_component(out); c != 0; c = icalset_get_next_component(out)) { printf("%s", icalcomponent_as_ical_string(c)); } #endif icalset_free(f); icalset_free(trash); icalset_free(cal); icalset_free(out); return 0; }
static int gn_ical2calnote_real(icalcomponent *comp, gn_calnote *calnote, int id) { int retval = GN_ERR_FAILED; struct icaltimetype dtstart = {0}, dtend = {0}; icalcomponent *compresult = NULL; if (id < 1) id = 1; /* iterate through the component */ iterate_cal(comp, 0, &id, &compresult, ICAL_VEVENT_COMPONENT); if (!compresult) { dprintf("No component found.\n"); retval = GN_ERR_EMPTYLOCATION; } else { const char *str; icalcomponent *alarm = {0}; icalproperty *rrule; struct icalrecurrencetype recur; retval = GN_ERR_NONE; calnote->phone_number[0] = 0; /* type */ str = comp_get_category(compresult); calnote->type = str2calnote_type(str); switch (calnote->type) { case GN_CALNOTE_CALL: /* description goes into text */ /* TODO: UTF8 --> ascii */ snprintf(calnote->phone_number, GN_CALNOTE_NUMBER_MAX_LENGTH-1, "%s", icalcomponent_get_summary(compresult)); str = icalcomponent_get_description(compresult); break; default: /* summary goes into text */ /* TODO: UTF8 --> ascii */ str = icalcomponent_get_summary(compresult); break; } if (str) { snprintf(calnote->text, GN_CALNOTE_MAX_LENGTH - 1, "%s", str); } /* start time */ dtstart = icalcomponent_get_dtstart(compresult); if (!icaltime_is_null_time(dtstart)) { calnote->time.year = dtstart.year; calnote->time.month = dtstart.month; calnote->time.day = dtstart.day; if (!icaltime_is_date(dtstart)) { calnote->time.hour = dtstart.hour; calnote->time.minute = dtstart.minute; calnote->time.second = dtstart.second; /* TODO: what about time zones? */ } } /* end time */ memset(&calnote->end_time, 0, sizeof(calnote->end_time)); dtend = icalcomponent_get_dtend(compresult); if (!icaltime_is_null_time(dtend)) { calnote->end_time.year = dtend.year; calnote->end_time.month = dtend.month; calnote->end_time.day = dtend.day; if (!icaltime_is_date(dtend)) { calnote->end_time.hour = dtend.hour; calnote->end_time.minute = dtend.minute; calnote->end_time.second = dtend.second; /* TODO: what about time zones? */ } } /* alarm */ alarm = icalcomponent_get_first_component(compresult, ICAL_VALARM_COMPONENT); if (alarm) { icalproperty *trigger = NULL; trigger = icalcomponent_get_first_property(alarm, ICAL_TRIGGER_PROPERTY); if (trigger) { struct icaltriggertype trigger_value; struct icaltimetype alarm_start; icalproperty *property; trigger_value = icalvalue_get_trigger(icalproperty_get_value(trigger)); if (icaltriggertype_is_null_trigger(trigger_value) || icaltriggertype_is_bad_trigger(trigger_value)) { calnote->alarm.enabled = 0; } else { if (icaltime_is_null_time(trigger_value.time)) { memcpy(&alarm_start, &dtstart, sizeof(struct icaltimetype)); } else { memcpy(&alarm_start, &trigger_value.time, sizeof(struct icaltimetype)); } if (!(icaldurationtype_is_bad_duration(trigger_value.duration) || icaldurationtype_is_null_duration(trigger_value.duration))) { alarm_start = icaltime_add(alarm_start, trigger_value.duration); } calnote->alarm.enabled = 1; calnote->alarm.timestamp.year = alarm_start.year; calnote->alarm.timestamp.month = alarm_start.month; calnote->alarm.timestamp.day = alarm_start.day; calnote->alarm.timestamp.hour = alarm_start.hour; calnote->alarm.timestamp.minute = alarm_start.minute; calnote->alarm.timestamp.second = alarm_start.second; /* TODO: time zone? */ property = icalcomponent_get_first_property(alarm, ICAL_ACTION_PROPERTY); calnote->alarm.tone = icalproperty_get_action(property) == ICAL_ACTION_AUDIO ? 1 : 0; } } } /* recurrence */ rrule = icalcomponent_get_first_property(compresult, ICAL_RRULE_PROPERTY); if (rrule) { recur = icalproperty_get_rrule(rrule); calnote->occurrences = recur.count; switch (recur.freq) { case ICAL_SECONDLY_RECURRENCE: dprintf("Not supported recurrence type. Approximating recurrence\n"); calnote->recurrence = recur.interval / 3600; if (!calnote->recurrence) calnote->recurrence = 1; break; case ICAL_MINUTELY_RECURRENCE: dprintf("Not supported recurrence type. Approximating recurrence\n"); calnote->recurrence = recur.interval / 60; if (!calnote->recurrence) calnote->recurrence = 1; break; case ICAL_HOURLY_RECURRENCE: calnote->recurrence = recur.interval; break; case ICAL_DAILY_RECURRENCE: calnote->recurrence = recur.interval * 24; break; case ICAL_WEEKLY_RECURRENCE: calnote->recurrence = recur.interval * 24 * 7; break; case ICAL_MONTHLY_RECURRENCE: calnote->recurrence = GN_CALNOTE_MONTHLY; break; case ICAL_YEARLY_RECURRENCE: calnote->recurrence = GN_CALNOTE_YEARLY; break; case ICAL_NO_RECURRENCE: calnote->recurrence = GN_CALNOTE_NEVER; break; default: dprintf("Not supported recurrence type. Assuming never\n"); calnote->recurrence = GN_CALNOTE_NEVER; break; } } str = icalcomponent_get_location(compresult); if (!str) str = ""; snprintf(calnote->mlocation, sizeof(calnote->mlocation), "%s", str); } if (compresult) { #ifdef DEBUG char *temp; temp = icalcomponent_as_ical_string(compresult); dprintf("Component found\n%s\n", temp); free(temp); #endif icalcomponent_free(compresult); } return retval; }
void parse_iCal(icalcomponent* comp) { icalcomponent * c; icalproperty * rrule; icalproperty * exdate; icalrecur_iterator * data; struct icaldurationtype offset; struct icaltimetype time_start; struct icaltimetype time_end; struct icaltimetype time_next; struct icaltimetype exdatetime; struct icaltimetype now; struct icalrecurrencetype recur; int i = 0; double duration; // Get offset: time_t t = time(NULL); struct tm lt = {0}; localtime_r(&t, <); if (debug_flag) { printf("Offset to GMT is %lds.\n", lt.tm_gmtoff); } offset.days = 0; offset.weeks = 0; offset.hours = 0; offset.minutes = 0; offset.seconds = 0; offset.hours = lt.tm_gmtoff / 3600; if (lt.tm_gmtoff < 0) { offset.is_neg = 1; } else { offset.is_neg = 0; } // Get time now: now = icaltime_today(); // Read each event: for (c = icalcomponent_get_first_component(comp,ICAL_VEVENT_COMPONENT) ; c != 0 ; c = icalcomponent_get_next_component(comp,ICAL_VEVENT_COMPONENT) ) { // Get details about the event: const char * summary = icalcomponent_get_summary(c); const char * description = icalcomponent_get_description(c); // Help: if (debug_flag) { if (summary != NULL) { printf("summary: %s\n", summary); } if (description != NULL) { printf("description: %s\n", description); } } // Ranging time: time_start = icalcomponent_get_dtstart (c); time_end = icalcomponent_get_dtend (c); duration = difftime(icaltime_as_timet(time_end), icaltime_as_timet(time_start)); // Rules: rrule = icalcomponent_get_first_property(c,ICAL_RRULE_PROPERTY); recur = icalproperty_get_rrule(rrule); data = icalrecur_iterator_new (recur, time_start); // Find next event: while (1) { time_next = icalrecur_iterator_next (data); if (icaltime_is_null_time(time_next) == 1) break; if (icaltime_compare(time_next, now) >= 0) break; } // Help: if (debug_flag) { dump_icaltimetype("time start", time_start); dump_icaltimetype("time end", time_end); dump_icaltimetype("until", recur.until); dump_icaltimetype("time next", time_next); } // One shot event: if ( icaltime_is_null_time(time_next) == 1 && icaltime_compare(time_start, now) < 0 ) { if (debug_flag) printf ("event (one shot) is in the past\n"); continue; } // Old event: discard recurent events finished before today... if ( icaltime_is_null_time(recur.until) == 0 && icaltime_compare(recur.until, now) < 0 ) { if (debug_flag) printf ("event is recurent in the past ...\n"); continue; } // Some help: if (debug_flag > 2) { dump_icalrecurrencetype(recur); } // Set time and hours: struct icaltimetype local_time_start = icaltime_add(time_start, offset); printf ("%d %d ", local_time_start.minute, local_time_start.hour); // Set option depending of recurence: switch (recur.freq) { // Weekly: OK but need to remove days not needed... ? case ICAL_WEEKLY_RECURRENCE: printf ("%s", "* * "); for (i = 0; recur.by_day[i] != 32639; i++) { printf ("%02d", icalrecurrencetype_day_day_of_week(recur.by_day[i]) -1); if (recur.by_day[i+1] != 32639) { printf ("%s", ","); } } printf ("%s", " "); break; // Happening each month: case ICAL_MONTHLY_RECURRENCE: // The Xth of the month: if (recur.by_month_day[0] != 32639) { printf ("%02d * * ", recur.by_month_day[0]); } // Day of the week: else { printf ("%d %d * ", time_next.day, time_next.month); } break; // Event happening each year ... OK??? // OK: one shoot. case ICAL_YEARLY_RECURRENCE: case ICAL_NO_RECURRENCE: default: printf ("%02d %02d * ", local_time_start.day, local_time_start.month ); } // How many valid exclude dates: exdate = icalcomponent_get_first_property(c, ICAL_EXDATE_PROPERTY); unsigned int num_ex = 0; if (exdate != NULL) { for (; exdate != NULL; exdate = icalcomponent_get_next_property(c, ICAL_EXDATE_PROPERTY) ) { exdatetime = icalvalue_get_datetime(icalproperty_get_value(exdate)); if (icaltime_compare(exdatetime, now) >= 0) { num_ex++; } } } if (num_ex > 0) { exdate = icalcomponent_get_first_property(c, ICAL_EXDATE_PROPERTY); for (; exdate != NULL; exdate = icalcomponent_get_next_property(c, ICAL_EXDATE_PROPERTY) ) { exdatetime = icalvalue_get_datetime(icalproperty_get_value(exdate)); if (icaltime_compare(exdatetime, now) >= 0) { struct icaltimetype local_exdatetime = icaltime_add(exdatetime, offset); printf ("%s", "[ \"$(date \"+\\\%Y\\\%m\\\%d\")\" = \""); printf ("%04d%02d%02d", local_exdatetime.year, local_exdatetime.month, local_exdatetime.day); printf ("%s", "\" ] || "); } } } // And the action: printf ("%s %.0f\n", summary, duration ); icalrecur_iterator_free (data); } }