/* * Determine the type (kind) of an iCalendar property value. */ const char *icalproperty_value_kind_as_string(icalproperty *prop) { icalvalue_kind kind = ICAL_NO_VALUE; icalparameter *val_param; val_param = icalproperty_get_first_parameter(prop, ICAL_VALUE_PARAMETER); if (val_param) { /* Use the kind specified in the VALUE param */ kind = icalparameter_value_to_value_kind( icalparameter_get_value(val_param)); } if (kind == ICAL_NO_VALUE) { icalvalue *value = icalproperty_get_value(prop); if (value) { /* Use the kind determined from the property value */ kind = icalvalue_isa(value); } } if (kind == ICAL_NO_VALUE) { /* Use the default kind for the property */ kind = icalproperty_kind_to_value_kind(icalproperty_isa(prop)); } switch (kind) { case ICAL_X_VALUE: return "unknown"; case ICAL_ACTION_VALUE: case ICAL_CARLEVEL_VALUE: case ICAL_CLASS_VALUE: case ICAL_CMD_VALUE: case ICAL_METHOD_VALUE: case ICAL_QUERYLEVEL_VALUE: case ICAL_STATUS_VALUE: case ICAL_TRANSP_VALUE: return "text"; default: return icalvalue_kind_to_string(kind); } }
NS_IMETHODIMP calIcalProperty::GetValue(nsACString &str) { icalvalue *value = icalproperty_get_value(mProperty); icalvalue_kind valuekind = icalvalue_isa(value); const char *icalstr; if (valuekind == ICAL_TEXT_VALUE) { icalstr = icalvalue_get_text(value); } else if (valuekind == ICAL_X_VALUE) { icalstr = icalvalue_get_x(value); } else if (valuekind == ICAL_ATTACH_VALUE) { icalattach *attach = icalvalue_get_attach(value); if (icalattach_get_is_url(attach)) { icalstr = icalattach_get_url(attach); } else { icalstr = (const char *)icalattach_get_data(attach); } } else { icalstr = icalproperty_get_value_as_string(mProperty); } if (!icalstr) { if (icalerrno == ICAL_BADARG_ERROR) { str.Truncate(); // Set string to null, because we don't have a value // (which is something different then an empty value) str.SetIsVoid(true); return NS_OK; } #ifdef DEBUG fprintf(stderr, "Error getting string value: %d (%s)\n", icalerrno, icalerror_strerror(icalerrno)); #endif return NS_ERROR_FAILURE; } str.Assign(icalstr); return NS_OK; }
/* * 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; }
char *icallangbind_property_eval_string_r(icalproperty *prop, char *sep) { char tmp[25]; size_t buf_size = 1024; char *buf; char *buf_ptr; icalparameter *param; icalvalue *value; if (prop == 0) { return 0; } buf = icalmemory_new_buffer(buf_size); buf_ptr = buf; APPENDS("{ "); value = icalproperty_get_value(prop); APPENDS(" 'name' "); APPENDS(sep); APPENDC('\''); APPENDS(icalproperty_kind_to_string(icalproperty_isa(prop))); APPENDC('\''); if (value) { APPENDS(", 'value_type' "); APPENDS(sep); APPENDC('\''); APPENDS(icalvalue_kind_to_string(icalvalue_isa(value))); APPENDC('\''); } APPENDS(", 'pid' "); APPENDS(sep); APPENDC('\''); snprintf(tmp, 25, "%p", prop); APPENDS(tmp); APPENDC('\''); if (value) { switch (icalvalue_isa(value)) { case ICAL_ATTACH_VALUE: case ICAL_BINARY_VALUE: case ICAL_NO_VALUE:{ icalerror_set_errno(ICAL_INTERNAL_ERROR); break; } default: { char *str = icalvalue_as_ical_string_r(value); char *copy = (char *)malloc(strlen(str) + 1); const char *i; char *j; if (copy == 0) { icalerror_set_errno(ICAL_NEWFAILED_ERROR); break; } /* Remove any newlines */ for (j = copy, i = str; *i != 0; j++, i++) { if (*i == '\n') { i++; } *j = *i; } *j = 0; APPENDS(", 'value'"); APPENDS(sep); APPENDC('\''); APPENDS(copy); APPENDC('\''); free(copy); free(str); break; } } } /* Add Parameters */ for (param = icalproperty_get_first_parameter(prop, ICAL_ANY_PARAMETER); param != 0; param = icalproperty_get_next_parameter(prop, ICAL_ANY_PARAMETER)) { char *copy = icalparameter_as_ical_string_r(param); char *v; if (copy == 0) { icalerror_set_errno(ICAL_NEWFAILED_ERROR); continue; } v = strchr(copy, '='); if (v == 0) { free(copy); continue; } *v = 0; v++; APPENDS(", "); APPENDC('\''); APPENDS(copy); APPENDC('\''); APPENDS(sep); APPENDC('\''); APPENDS(v); APPENDC('\''); free(copy); } APPENDC('}'); return buf; }
/* * Construct a JSON array for an iCalendar property. */ static json_t *icalproperty_as_json_array(icalproperty *prop) { icalproperty_kind prop_kind; const char *x_name, *property_name = NULL; icalparameter *param; const char *type = NULL; const icalvalue *value; json_t *jprop, *jparams; if (!prop) return NULL; prop_kind = icalproperty_isa(prop); x_name = icalproperty_get_x_name(prop); if (prop_kind == ICAL_X_PROPERTY && x_name) property_name = x_name; else property_name = icalproperty_kind_to_string(prop_kind); if (!property_name) { icalerror_warn("Got a property of an unknown kind."); return NULL; } /* Create property array */ jprop = json_array(); /* Add property name */ json_array_append_new(jprop, json_string(lcase(icalmemory_tmp_copy(property_name)))); /* Add parameters */ jparams = json_object(); for (param = icalproperty_get_first_parameter(prop, ICAL_ANY_PARAMETER); param != 0; param = icalproperty_get_next_parameter(prop, ICAL_ANY_PARAMETER)) { if (icalparameter_isa(param) == ICAL_VALUE_PARAMETER) continue; icalparameter_as_json_object_member(param, jparams); } json_array_append_new(jprop, jparams); /* Add type */ type = icalproperty_value_kind_as_string(prop); json_array_append_new(jprop, json_string(lcase(icalmemory_tmp_copy(type)))); /* Add value */ value = icalproperty_get_value(prop); if (value) { switch (icalproperty_isa(prop)) { case ICAL_CATEGORIES_PROPERTY: case ICAL_RESOURCES_PROPERTY: case ICAL_POLLPROPERTIES_PROPERTY: if (icalvalue_isa(value) == ICAL_TEXT_VALUE) { /* Handle multi-valued properties */ const char *str = icalvalue_as_ical_string(value); tok_t tok; tok_init(&tok, str, ",", TOK_TRIMLEFT|TOK_TRIMRIGHT|TOK_EMPTY); while ((str = tok_next(&tok))) { if (*str) json_array_append_new(jprop, json_string(str)); } tok_fini(&tok); break; } default: json_array_append_new(jprop, icalvalue_as_json_object(value)); break; } } return jprop; }
/* * 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); }