/** * e_cal_util_construct_instance: * @icalcomp: A recurring #icalcomponent * @rid: The RECURRENCE-ID to construct a component for * * This checks that @rid indicates a valid recurrence of @icalcomp, and * if so, generates a copy of @comp containing a RECURRENCE-ID of @rid. * * Returns: the instance, or %NULL. **/ icalcomponent * e_cal_util_construct_instance (icalcomponent *icalcomp, struct icaltimetype rid) { struct instance_data instance; struct icaltimetype start, end; g_return_val_if_fail (icalcomp != NULL, 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); if (!instance.found) return NULL; /* Make the instance */ icalcomp = icalcomponent_new_clone (icalcomp); icalcomponent_set_recurrenceid (icalcomp, rid); return icalcomp; }
/** * 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; }
icalspanlist* icalspanlist_new(icalset *set, struct icaltimetype start, struct icaltimetype end) { struct icaltime_span range; pvl_elem itr; icalcomponent *c,*inner; icalcomponent_kind kind, inner_kind; icalspanlist *sl; struct icaltime_span *freetime; if ( ( sl = (struct icalspanlist_impl*) malloc(sizeof(struct icalspanlist_impl))) == 0) { icalerror_set_errno(ICAL_NEWFAILED_ERROR); return 0; } sl->spans = pvl_newlist(); sl->start = start; sl->end = end; range.start = icaltime_as_timet(start); range.end = icaltime_as_timet(end); /* Get a list of spans of busy time from the events in the set and order the spans based on the start time */ for(c = icalset_get_first_component(set); c != 0; c = icalset_get_next_component(set)){ kind = icalcomponent_isa(c); inner = icalcomponent_get_inner(c); if(!inner){ continue; } inner_kind = icalcomponent_isa(inner); if( kind != ICAL_VEVENT_COMPONENT && inner_kind != ICAL_VEVENT_COMPONENT){ continue; } icalerror_clear_errno(); icalcomponent_foreach_recurrence(c, start, end, icalspanlist_new_callback, (void*)sl); } /* Now Fill in the free time spans. loop through the spans. if the start of the range is not within the span, create a free entry that runs from the start of the range to the start of the span. */ for( itr = pvl_head(sl->spans); itr != 0; itr = pvl_next(itr)) { struct icaltime_span *s = (struct icaltime_span*)pvl_data(itr); if ((freetime=(struct icaltime_span *) malloc(sizeof(struct icaltime_span))) == 0){ icalerror_set_errno(ICAL_NEWFAILED_ERROR); return 0; } if(range.start < s->start){ freetime->start = range.start; freetime->end = s->start; freetime->is_busy = 0; pvl_insert_ordered(sl->spans,compare_span,(void*)freetime); } else { free(freetime); } range.start = s->end; } /* If the end of the range is null, then assume that everything after the last item in the calendar is open and add a span that indicates this */ if( icaltime_is_null_time(end)){ struct icaltime_span* last_span; last_span = (struct icaltime_span*)pvl_data(pvl_tail(sl->spans)); if (last_span != 0){ if ((freetime=(struct icaltime_span *) malloc(sizeof(struct icaltime_span))) == 0){ icalerror_set_errno(ICAL_NEWFAILED_ERROR); return 0; } freetime->is_busy = 0; freetime->start = last_span->end; freetime->end = freetime->start; pvl_insert_ordered(sl->spans,compare_span,(void*)freetime); } } return sl; }
void test_recur_file() { icalset *cin = 0; struct icaltimetype next; icalcomponent *itr; icalproperty *desc, *dtstart, *rrule; struct icalrecurrencetype recur; icalrecur_iterator* ritr; time_t tt; char* file; int num_recurs_found = 0; icalfileset_options options = {O_RDONLY, 0644, 0}; icalerror_set_error_state(ICAL_PARSE_ERROR, ICAL_ERROR_NONFATAL); #ifndef WIN32 signal(SIGALRM,sig_alrm); #endif file = getenv("ICAL_RECUR_FILE"); if (!file) file = TEST_DATADIR "/recur.txt"; #ifndef WIN32 alarm(15); /* to get file lock */ #endif cin = icalset_new(ICAL_FILE_SET, file, &options); #ifndef WIN32 alarm(0); #endif ok("opening file with recurring events", (cin!=NULL)); assert(cin!=NULL); for (itr = icalfileset_get_first_component(cin); itr != 0; itr = icalfileset_get_next_component(cin)){ int badcomp = 0; int expected_events = 0; char msg[128]; struct icaltimetype start = icaltime_null_time(); struct icaltimetype startmin = icaltime_from_timet(1,0); struct icaltimetype endmax = icaltime_null_time(); const char *desc_str = "malformed component"; desc = icalcomponent_get_first_property(itr,ICAL_DESCRIPTION_PROPERTY); dtstart = icalcomponent_get_first_property(itr,ICAL_DTSTART_PROPERTY); rrule = icalcomponent_get_first_property(itr,ICAL_RRULE_PROPERTY); if (desc) { desc_str = icalproperty_get_description(desc); } ok((char*)desc_str, !(desc == 0 || dtstart == 0 || rrule == 0)); if (desc == 0 || dtstart == 0 || rrule == 0) { badcomp = 1; if (VERBOSE) { printf("\n******** Error in input component ********\n"); printf("The following component is malformed:\n %s\n", desc_str); } continue; } if (VERBOSE) { printf("\n\n#### %s\n",desc_str); printf("#### %s\n",icalvalue_as_ical_string(icalproperty_get_value(rrule))); } recur = icalproperty_get_rrule(rrule); start = icalproperty_get_dtstart(dtstart); ritr = icalrecur_iterator_new(recur,start); tt = icaltime_as_timet(start); if (VERBOSE) printf("#### %s\n",ctime(&tt )); icalrecur_iterator_free(ritr); for(ritr = icalrecur_iterator_new(recur,start), next = icalrecur_iterator_next(ritr); !icaltime_is_null_time(next); next = icalrecur_iterator_next(ritr)){ tt = icaltime_as_timet(next); if (VERBOSE) printf(" %s",ctime(&tt )); } icalrecur_iterator_free(ritr); num_recurs_found = 0; expected_events = get_expected_numevents(itr); icalcomponent_foreach_recurrence(itr, startmin, endmax, recur_callback, &num_recurs_found); sprintf(msg," expecting total of %d events", expected_events); int_is(msg, num_recurs_found, expected_events); } icalset_free(cin); }
int main(int argc, char *argv[]) { icalset *cin; struct icaltimetype next; icalcomponent *itr; icalproperty *desc, *dtstart, *rrule; struct icalrecurrencetype recur; icalrecur_iterator* ritr; time_t tt; char* file; icalerror_set_error_state(ICAL_PARSE_ERROR, ICAL_ERROR_NONFATAL); #ifndef WIN32 signal(SIGALRM,sig_alrm); #endif if (argc <= 1) { file = "../../test-data/recur.txt"; } else if (argc == 2) { file = argv[1]; } else { fprintf(stderr,"usage: recur [input file]\n"); exit(1); } #ifndef WIN32 alarm(300); /* to get file lock */ #endif cin = icalfileset_new(file); #ifndef WIN32 alarm(0); #endif if(cin == 0) { fprintf(stderr,"recur: can't open file %s\n",file); exit(1); } for (itr = icalfileset_get_first_component(cin); itr != 0; itr = icalfileset_get_next_component(cin)) { struct icaltimetype start = icaltime_from_timet(1,0); struct icaltimetype end = icaltime_today(); desc = icalcomponent_get_first_property(itr,ICAL_DESCRIPTION_PROPERTY); dtstart = icalcomponent_get_first_property(itr,ICAL_DTSTART_PROPERTY); rrule = icalcomponent_get_first_property(itr,ICAL_RRULE_PROPERTY); if (desc == 0 || dtstart == 0 || rrule == 0) { printf("\n******** Error in input component ********\n"); printf("The following component is malformed:\n %s\n", icalcomponent_as_ical_string(itr)); continue; } printf("\n\n#### %s\n",icalproperty_get_description(desc)); printf("#### %s\n",icalvalue_as_ical_string(icalproperty_get_value(rrule))); recur = icalproperty_get_rrule(rrule); start = icalproperty_get_dtstart(dtstart); ritr = icalrecur_iterator_new(recur,start); tt = icaltime_as_timet(start); printf("#### %s\n",ctime(&tt )); icalrecur_iterator_free(ritr); for(ritr = icalrecur_iterator_new(recur,start), next = icalrecur_iterator_next(ritr); !icaltime_is_null_time(next); next = icalrecur_iterator_next(ritr)) { tt = icaltime_as_timet(next); printf(" %s",ctime(&tt )); } icalrecur_iterator_free(ritr); icalcomponent_foreach_recurrence(itr, start, end, recur_callback, NULL); } icalset_free(cin); icaltimezone_free_builtin_timezones(); icalmemory_free_ring(); free_zone_directory(); return 0; }