/* * Add the proper XML element for an iCalendar value. */ static void icalproperty_add_value_as_xml_element(xmlNodePtr xprop, icalproperty *prop) { const char *type, *str = NULL; xmlNodePtr xtype; const icalvalue *value; char buf[40]; /* Add type */ type = lcase(icalmemory_tmp_copy( icalproperty_value_kind_as_string(prop))); xtype = xmlNewChild(xprop, NULL, BAD_CAST type, NULL); /* Add value */ value = icalproperty_get_value(prop); switch (icalvalue_isa(value)) { case ICAL_DATE_VALUE: str = icaltime_as_iso_string(icalvalue_get_date(value)); break; case ICAL_DATETIME_VALUE: str = icaltime_as_iso_string(icalvalue_get_datetime(value)); break; case ICAL_DATETIMEPERIOD_VALUE: { struct icaldatetimeperiodtype dtp = icalvalue_get_datetimeperiod(value); if (!icaltime_is_null_time(dtp.time)) { str = icaltime_as_iso_string(dtp.time); break; } else { icalperiodtype_add_as_xml_element(xtype, dtp.period); return; } } case ICAL_GEO_VALUE: { struct icalgeotype geo = icalvalue_get_geo(value); snprintf(buf, sizeof(buf), "%f", geo.lat); xmlNewTextChild(xtype, NULL, BAD_CAST "latitude", BAD_CAST buf); snprintf(buf, sizeof(buf), "%f", geo.lon); xmlNewTextChild(xtype, NULL, BAD_CAST "longitude", BAD_CAST buf); return; } case ICAL_PERIOD_VALUE: icalperiodtype_add_as_xml_element(xtype, icalvalue_get_period(value)); return; case ICAL_RECUR_VALUE: { struct icalrecurrencetype recur = icalvalue_get_recur(value); icalrecurrencetype_add_as_xxx(&recur, xtype, NULL, &icalrecur_add_string_as_xml_element); return; } case ICAL_REQUESTSTATUS_VALUE: { struct icalreqstattype stat = icalvalue_get_requeststatus(value); if (!stat.desc) stat.desc = icalenum_reqstat_desc(stat.code); snprintf(buf, sizeof(buf), "%u.%u", icalenum_reqstat_major(stat.code), icalenum_reqstat_minor(stat.code)); xmlNewTextChild(xtype, NULL, BAD_CAST "code", BAD_CAST buf); xmlNewTextChild(xtype, NULL, BAD_CAST "description", BAD_CAST stat.desc); if (stat.debug) xmlNewTextChild(xtype, NULL, BAD_CAST "data", BAD_CAST stat.debug); return; } case ICAL_TRIGGER_VALUE: { struct icaltriggertype trig = icalvalue_get_trigger(value); if (!icaltime_is_null_time(trig.time)) str = icaltime_as_iso_string(trig.time); else str = icaldurationtype_as_ical_string(trig.duration); break; } case ICAL_UTCOFFSET_VALUE: str = icalvalue_utcoffset_as_iso_string(value); break; default: str = icalvalue_as_ical_string(value); switch (icalproperty_isa(prop)) { case ICAL_CATEGORIES_PROPERTY: case ICAL_RESOURCES_PROPERTY: case ICAL_POLLPROPERTIES_PROPERTY: if (strchr(str, ',')) { /* Handle multi-valued properties */ tok_t tok; tok_init(&tok, str, ",", TOK_TRIMLEFT|TOK_TRIMRIGHT|TOK_EMPTY); str = tok_next(&tok); xmlAddChild(xtype, xmlNewText(BAD_CAST str)); while ((str = tok_next(&tok))) { if (*str) { xtype = xmlNewChild(xprop, NULL, BAD_CAST type, NULL); xmlAddChild(xtype, xmlNewText(BAD_CAST str)); } } tok_fini(&tok); return; } default: break; } break; } if (str) xmlAddChild(xtype, xmlNewText(BAD_CAST str)); }
nsresult calIcalProperty::getDatetime_(calIcalComponent * parent, icalproperty * prop, calIDateTime ** dtp) { icalvalue * const val = icalproperty_get_value(prop); icalvalue_kind const valkind = icalvalue_isa(val); if (valkind != ICAL_DATETIME_VALUE && valkind != ICAL_DATE_VALUE) { return NS_ERROR_UNEXPECTED; } icaltimetype itt = icalvalue_get_datetime(val); char const* tzid_ = nullptr; if (!itt.is_utc) { if (itt.zone) { tzid_ = icaltimezone_get_tzid(const_cast<icaltimezone *>(itt.zone)); } else { // Need to get the tzid param. Unfortunatly, libical tends to return raw // ics strings, with quotes and everything. That's not what we want. Need // to work around. icalparameter * const tzparam = icalproperty_get_first_parameter(prop, ICAL_TZID_PARAMETER); if (tzparam) { tzid_ = icalparameter_get_xvalue(tzparam); } } } nsCOMPtr<calITimezone> tz; if (tzid_) { nsDependentCString const tzid(tzid_); calIcalComponent * comp = nullptr; if (parent) { comp = parent->getParentVCalendarOrThis(); } // look up parent if timezone is already referenced: if (comp) { comp->mReferencedTimezones.Get(tzid, getter_AddRefs(tz)); } if (!tz) { if (parent) { // passed tz provider has precedence over timezone service: calITimezoneProvider * const tzProvider = parent->getTzProvider(); if (tzProvider) { tzProvider->GetTimezone(tzid, getter_AddRefs(tz)); NS_ASSERTION(tz, tzid_); } } if (!tz) { // look up tz in tz service. // this hides errors from incorrect ics files, which could state // a TZID that is not present in the ics file. // The other way round, it makes this product more error tolerant. nsresult rv = cal::getTimezoneService()->GetTimezone(tzid, getter_AddRefs(tz)); if (NS_FAILED(rv) || !tz) { icaltimezone const* zone = itt.zone; if (!zone && comp) { // look up parent VCALENDAR for VTIMEZONE: zone = icalcomponent_get_timezone(comp->mComponent, tzid_); NS_ASSERTION(zone, tzid_); } if (zone) { // We need to decouple this (inner) VTIMEZONE from the parent VCALENDAR to avoid // running into circular references (referenced timezones): icaltimezone * const clonedZone = icaltimezone_new(); CAL_ENSURE_MEMORY(clonedZone); icalcomponent * const clonedZoneComp = icalcomponent_new_clone(icaltimezone_get_component(const_cast<icaltimezone *>(zone))); if (!clonedZoneComp) { icaltimezone_free(clonedZone, 1 /* free struct */); CAL_ENSURE_MEMORY(clonedZoneComp); } if (!icaltimezone_set_component(clonedZone, clonedZoneComp)) { icaltimezone_free(clonedZone, 1 /* free struct */); return NS_ERROR_INVALID_ARG; } nsCOMPtr<calIIcalComponent> const tzComp(new calIcalComponent(clonedZone, clonedZoneComp)); CAL_ENSURE_MEMORY(tzComp); tz = new calTimezone(tzid, tzComp); CAL_ENSURE_MEMORY(tz); } else { // install phantom timezone, so the data could be repaired: tz = new calTimezone(tzid, nullptr); CAL_ENSURE_MEMORY(tz); } } } if (comp && tz) { // assure timezone is known: comp->AddTimezoneReference(tz); } } if (tz) { // correct itt which would else appear floating: itt.zone = cal::getIcalTimezone(tz); itt.is_utc = 0; } else { cal::logMissingTimezone(tzid_); } } *dtp = new calDateTime(&itt, tz); CAL_ENSURE_MEMORY(*dtp); NS_ADDREF(*dtp); return NS_OK; }
icalerrorenum icaldirset_add_component(icalset* set, icalcomponent* comp) { char clustername[ICAL_PATH_MAX]; icalproperty *dt = 0; icalvalue *v; struct icaltimetype tm; icalerrorenum error = ICAL_NO_ERROR; icalcomponent *inner; icaldirset *dset = (icaldirset*) set; icalerror_check_arg_rz( (dset!=0), "dset"); icalerror_check_arg_rz( (comp!=0), "comp"); icaldirset_add_uid(comp); /* Determine which cluster this object belongs in. This is a HACK */ for(inner = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT); inner != 0; inner = icalcomponent_get_next_component(comp,ICAL_ANY_COMPONENT)){ dt = icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY); if (dt != 0) break; } if (dt == 0) { for(inner = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT); inner != 0; inner = icalcomponent_get_next_component(comp,ICAL_ANY_COMPONENT)){ dt = icalcomponent_get_first_property(inner,ICAL_DTSTART_PROPERTY); if (dt != 0) break; } } if (dt == 0){ icalerror_warn("The component does not have a DTSTAMP or DTSTART property, so it cannot be added to the store"); icalerror_set_errno(ICAL_BADARG_ERROR); return ICAL_BADARG_ERROR; } v = icalproperty_get_value(dt); tm = icalvalue_get_datetime(v); snprintf(clustername,ICAL_PATH_MAX,"%s/%04d%02d",dset->dir, tm.year, tm.month); /* Load the cluster and insert the object */ if(dset->cluster != 0 && strcmp(clustername,icalcluster_key(dset->cluster)) != 0 ){ icalcluster_free(dset->cluster); dset->cluster = 0; } if (dset->cluster == 0){ dset->cluster = icalfileset_produce_icalcluster(clustername); if (dset->cluster == 0){ error = icalerrno; } } if (error != ICAL_NO_ERROR){ icalerror_set_errno(error); return error; } /* Add the component to the cluster */ icalcluster_add_component(dset->cluster,comp); /* icalcluster_mark(impl->cluster); */ return ICAL_NO_ERROR; }
/* * Construct the proper JSON object for an iCalendar value. */ static json_t *icalvalue_as_json_object(const icalvalue *value) { const char *str = NULL; json_t *obj; switch (icalvalue_isa(value)) { case ICAL_BOOLEAN_VALUE: return json_boolean(icalvalue_get_integer(value)); case ICAL_DATE_VALUE: str = icaltime_as_iso_string(icalvalue_get_date(value)); break; case ICAL_DATETIME_VALUE: str = icaltime_as_iso_string(icalvalue_get_datetime(value)); break; case ICAL_DATETIMEPERIOD_VALUE: { struct icaldatetimeperiodtype dtp = icalvalue_get_datetimeperiod(value); if (!icaltime_is_null_time(dtp.time)) str = icaltime_as_iso_string(dtp.time); else str = icalperiodtype_as_json_string(dtp.period); break; } case ICAL_FLOAT_VALUE: return json_real(icalvalue_get_float(value)); case ICAL_GEO_VALUE: { struct icalgeotype geo = icalvalue_get_geo(value); obj = json_array(); json_array_append_new(obj, json_real(geo.lat)); json_array_append_new(obj, json_real(geo.lon)); return obj; } case ICAL_INTEGER_VALUE: return json_integer(icalvalue_get_integer(value)); case ICAL_PERIOD_VALUE: str = icalperiodtype_as_json_string(icalvalue_get_period(value)); break; case ICAL_RECUR_VALUE: { struct icalrecurrencetype recur = icalvalue_get_recur(value); obj = json_object(); icalrecurrencetype_add_as_xxx(&recur, obj, &icalrecur_add_int_to_json_object, &icalrecur_add_string_to_json_object); return obj; } case ICAL_REQUESTSTATUS_VALUE: return icalreqstattype_as_json_array(icalvalue_get_requeststatus(value)); case ICAL_TRIGGER_VALUE: { struct icaltriggertype trig = icalvalue_get_trigger(value); if (!icaltime_is_null_time(trig.time)) str = icaltime_as_iso_string(trig.time); else str = icaldurationtype_as_ical_string(trig.duration); break; } case ICAL_UTCOFFSET_VALUE: str = icalvalue_utcoffset_as_iso_string(value); break; default: str = icalvalue_as_ical_string(value); break; } return (str ? json_string(str) : NULL); }
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); } }