char* icaldurationtype_as_ical_string(struct icaldurationtype d) { char *buf, *output_line; size_t buf_size = 256; char* buf_ptr = 0; int seconds; buf = (char*)icalmemory_new_buffer(buf_size); buf_ptr = buf; seconds = icaldurationtype_as_int(d); if(seconds !=0){ if(d.is_neg == 1){ icalmemory_append_char(&buf, &buf_ptr, &buf_size, '-'); } icalmemory_append_char(&buf, &buf_ptr, &buf_size, 'P'); if (d.weeks != 0 ) { append_duration_segment(&buf, &buf_ptr, &buf_size, "W", d.weeks); } if (d.days != 0 ) { append_duration_segment(&buf, &buf_ptr, &buf_size, "D", d.days); } if (d.hours != 0 || d.minutes != 0 || d.seconds != 0) { icalmemory_append_string(&buf, &buf_ptr, &buf_size, "T"); if (d.hours != 0 ) { append_duration_segment(&buf, &buf_ptr, &buf_size, "H", d.hours); } if (d.minutes != 0 ) { append_duration_segment(&buf, &buf_ptr, &buf_size, "M", d.minutes); } if (d.seconds != 0 ) { append_duration_segment(&buf, &buf_ptr, &buf_size, "S", d.seconds); } } } else { icalmemory_append_string(&buf, &buf_ptr, &buf_size, "PT0S"); } output_line = icalmemory_tmp_copy(buf); icalmemory_free_buffer(buf); return output_line; }
/* * Construct a JSON array for an iCalendar component. */ static json_t *icalcomponent_as_json_array(icalcomponent *comp) { icalcomponent *c; icalproperty *p; icalcomponent_kind kind; const char* kind_string; json_t *jcomp, *jprops, *jsubs; if (!comp) return NULL; kind = icalcomponent_isa(comp); switch (kind) { case ICAL_NO_COMPONENT: return NULL; break; case ICAL_X_COMPONENT: kind_string = ""; //comp->x_name; break; default: kind_string = icalcomponent_kind_to_string(kind); } /* Create component array */ jcomp = json_array(); /* Add component name */ json_array_append_new(jcomp, json_string(lcase(icalmemory_tmp_copy(kind_string)))); /* Add properties */ jprops = json_array(); for (p = icalcomponent_get_first_property(comp, ICAL_ANY_PROPERTY); p; p = icalcomponent_get_next_property(comp, ICAL_ANY_PROPERTY)) { json_array_append_new(jprops, icalproperty_as_json_array(p)); } json_array_append_new(jcomp, jprops); /* Add sub-components */ jsubs = json_array(); for (c = icalcomponent_get_first_component(comp, ICAL_ANY_COMPONENT); c; c = icalcomponent_get_next_component(comp, ICAL_ANY_COMPONENT)) { json_array_append_new(jsubs, icalcomponent_as_json_array(c)); } json_array_append_new(jcomp, jsubs); return jcomp; }
/* * Construct a XML element for an iCalendar component. */ static xmlNodePtr icalcomponent_as_xml_element(icalcomponent *comp) { icalcomponent *c; icalproperty *p; icalcomponent_kind kind; const char* kind_string; xmlNodePtr xcomp, xprops = NULL, xsubs = NULL; if (!comp) return NULL; kind = icalcomponent_isa(comp); switch (kind) { case ICAL_NO_COMPONENT: return NULL; break; case ICAL_X_COMPONENT: kind_string = ""; //comp->x_name; break; default: kind_string = icalcomponent_kind_to_string(kind); } /* Create component */ xcomp = xmlNewNode(NULL, BAD_CAST lcase(icalmemory_tmp_copy(kind_string))); /* Add properties */ for (p = icalcomponent_get_first_property(comp, ICAL_ANY_PROPERTY); p; p = icalcomponent_get_next_property(comp, ICAL_ANY_PROPERTY)) { if (!xprops) xprops = xmlNewChild(xcomp, NULL, BAD_CAST "properties", NULL); xmlAddChild(xprops, icalproperty_as_xml_element(p)); } /* Add sub-components */ for (c = icalcomponent_get_first_component(comp, ICAL_ANY_COMPONENT); c; c = icalcomponent_get_next_component(comp, ICAL_ANY_COMPONENT)) { if (!xsubs) xsubs = xmlNewChild(xcomp, NULL, BAD_CAST "components", NULL); xmlAddChild(xsubs, icalcomponent_as_xml_element(c)); } return xcomp; }
/*** @brief Return the code for a request status */ char* icalenum_reqstat_code(icalrequeststatus stat) { int i, major, minor; char tmpbuf[36]; for (i=0; request_status_map[i].kind != ICAL_UNKNOWN_STATUS; i++) { if ( request_status_map[i].kind == stat) { major = request_status_map[i].major; minor = request_status_map[i].minor; sprintf(tmpbuf, "%i.%i", major, minor); return icalmemory_tmp_copy(tmpbuf); } } return NULL; }
/* * Construct an XML element for an iCalendar property. */ static xmlNodePtr icalproperty_as_xml_element(icalproperty *prop) { icalproperty_kind prop_kind; const char *x_name, *property_name = NULL; icalparameter *param; xmlNodePtr xprop, xparams = NULL; 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 */ xprop = xmlNewNode(NULL, BAD_CAST lcase(icalmemory_tmp_copy(property_name))); /* Add parameters */ 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; if (!xparams) xparams = xmlNewChild(xprop, NULL, BAD_CAST "parameters", NULL); xmlAddChild(xparams, icalparameter_as_xml_element(param)); } /* Add value */ icalproperty_add_value_as_xml_element(xprop, prop); return xprop; }
/* * Add an iCalendar parameter to an existing JSON object. */ static void icalparameter_as_json_object_member(icalparameter *param, json_t *jparams) { icalparameter_kind kind; const char *kind_string, *value_string; kind = icalparameter_isa(param); switch (kind) { case ICAL_X_PARAMETER: kind_string = icalparameter_get_xname(param); break; #ifdef HAVE_IANA_PARAMS case ICAL_IANA_PARAMETER: kind_string = icalparameter_get_iana_name(param); break; #endif default: kind_string = icalparameter_kind_to_string(kind); if (kind_string) break; case ICAL_NO_PARAMETER: case ICAL_ANY_PARAMETER: icalerror_set_errno(ICAL_BADARG_ERROR); return; } /* XXX Need to handle multi-valued parameters */ value_string = icalparameter_get_xvalue(param); if (!value_string) { icalparameter_value value = icalparameter_get_value(param); if (value) value_string = icalparameter_enum_to_string(value); } if (!value_string) return; json_object_set_new(jparams, lcase(icalmemory_tmp_copy(kind_string)), json_string(value_string)); }
/* * Construct an iCalendar component from a XML element. */ static icalcomponent *xml_element_to_icalcomponent(xmlNodePtr xcomp) { icalcomponent_kind kind; icalcomponent *comp = NULL; xmlNodePtr node, xprop, xsub; if (!xcomp) return NULL; /* Get component type */ kind = icalenum_string_to_component_kind( ucase(icalmemory_tmp_copy((const char *) xcomp->name))); if (kind == ICAL_NO_COMPONENT) { syslog(LOG_WARNING, "Unknown xCal component type: %s", xcomp->name); return NULL; } /* Create new component */ comp = icalcomponent_new(kind); if (!comp) { syslog(LOG_ERR, "Creation of new %s component failed", xcomp->name); return NULL; } /* Add properties */ node = xmlFirstElementChild(xcomp); if (!node || xmlStrcmp(node->name, BAD_CAST "properties")) { syslog(LOG_WARNING, "Expected <properties> XML element, received %s", node->name); goto error; } for (xprop = xmlFirstElementChild(node); xprop; xprop = xmlNextElementSibling(xprop)) { icalproperty *prop = xml_element_to_icalproperty(xprop); if (!prop) goto error; icalcomponent_add_property(comp, prop); } /* Add sub-components */ if (!(node = xmlNextElementSibling(node))) return comp; if (xmlStrcmp(node->name, BAD_CAST "components")) { syslog(LOG_WARNING, "Expected <components> XML element, received %s", node->name); goto error; } for (xsub = xmlFirstElementChild(node); xsub; xsub = xmlNextElementSibling(xsub)) { icalcomponent *sub = xml_element_to_icalcomponent(xsub); if (!sub) goto error; icalcomponent_add_component(comp, sub); } /* Sanity check */ if ((node = xmlNextElementSibling(node))) { syslog(LOG_WARNING, "Unexpected XML element in component: %s", node->name); goto error; } return comp; error: icalcomponent_free(comp); return NULL; }
/* * Construct an iCalendar property from a XML element. */ static icalproperty *xml_element_to_icalproperty(xmlNodePtr xprop) { const char *propname, *typestr; icalproperty_kind kind; icalproperty *prop = NULL; icalvalue_kind valkind; icalvalue *value; xmlNodePtr node; /* Get the property type */ propname = ucase(icalmemory_tmp_copy((const char *) xprop->name)); kind = icalenum_string_to_property_kind(propname); if (kind == ICAL_NO_PROPERTY) { syslog(LOG_WARNING, "Unknown xCal property type: %s", propname); return NULL; } /* Create new property */ prop = icalproperty_new(kind); if (!prop) { syslog(LOG_ERR, "Creation of new %s property failed", propname); return NULL; } if (kind == ICAL_X_PROPERTY) icalproperty_set_x_name(prop, propname); /* Add parameters */ node = xmlFirstElementChild(xprop); if (node && !xmlStrcmp(node->name, BAD_CAST "parameters")) { xmlNodePtr xparam; for (xparam = xmlFirstElementChild(node); xparam; xparam = xmlNextElementSibling(xparam)) { char *paramname = ucase(icalmemory_tmp_copy((const char *) xparam->name)); xmlChar *paramval = xmlNodeGetContent(xmlFirstElementChild(xparam)); /* XXX Need to handle multi-valued parameters */ icalproperty_set_parameter_from_string(prop, paramname, (const char *) paramval); xmlFree(paramval); } node = xmlNextElementSibling(node); } /* Get the value type */ if (!node) { syslog(LOG_WARNING, "Missing xCal value for %s property", propname); return NULL; } typestr = ucase(icalmemory_tmp_copy((const char *) node->name)); valkind = !strcmp(typestr, "UNKNOWN") ? ICAL_X_VALUE : icalenum_string_to_value_kind(typestr); if (valkind == ICAL_NO_VALUE) { syslog(LOG_WARNING, "Unknown xCal value type for %s property: %s", propname, typestr); return NULL; } else if (valkind == ICAL_TEXT_VALUE) { /* "text" also includes enumerated types - grab type from property */ valkind = icalproperty_kind_to_value_kind(kind); } /* Add value */ switch (kind) { case ICAL_CATEGORIES_PROPERTY: case ICAL_RESOURCES_PROPERTY: case ICAL_POLLPROPERTIES_PROPERTY: if (valkind == ICAL_TEXT_VALUE) { /* Handle multi-valued properties */ struct buf buf = BUF_INITIALIZER; xmlChar *content = NULL; content = xmlNodeGetContent(node); buf_setcstr(&buf, (const char *) content); free(content); while ((node = xmlNextElementSibling(node))) { buf_putc(&buf, ','); content = xmlNodeGetContent(node); buf_appendcstr(&buf, (const char *) content); free(content); } value = icalvalue_new_from_string(valkind, buf_cstring(&buf)); buf_free(&buf); break; } default: value = xml_element_to_icalvalue(node, valkind); if (!value) { syslog(LOG_ERR, "Parsing %s property value failed", propname); goto error; } } icalproperty_set_value(prop, value); /* Sanity check */ if ((node = xmlNextElementSibling(node))) { syslog(LOG_WARNING, "Unexpected XML element in property: %s", node->name); goto error; } return prop; error: icalproperty_free(prop); return NULL; }
/* * 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)); }
/* * Construct an XML element for an iCalendar parameter. */ static xmlNodePtr icalparameter_as_xml_element(icalparameter *param) { icalparameter_kind kind; icalparameter_value value; const char *kind_string, *type_string, *value_string; xmlNodePtr xparam; kind = icalparameter_isa(param); switch (kind) { case ICAL_X_PARAMETER: kind_string = icalparameter_get_xname(param); break; #ifdef HAVE_IANA_PARAMS case ICAL_IANA_PARAMETER: kind_string = icalparameter_get_iana_name(param); break; #endif default: kind_string = icalparameter_kind_to_string(kind); if (kind_string) break; case ICAL_NO_PARAMETER: case ICAL_ANY_PARAMETER: icalerror_set_errno(ICAL_BADARG_ERROR); return NULL; } /* Get value type */ switch (kind) { case ICAL_ALTREP_PARAMETER: case ICAL_DIR_PARAMETER: type_string = "uri"; break; case ICAL_DELEGATEDFROM_PARAMETER: case ICAL_DELEGATEDTO_PARAMETER: case ICAL_MEMBER_PARAMETER: case ICAL_SENTBY_PARAMETER: type_string = "cal-address"; break; case ICAL_RSVP_PARAMETER: type_string = "boolean"; break; default: type_string = "text"; break; } /* XXX Need to handle multi-valued parameters */ value = icalparameter_get_value(param); if (value == ICAL_VALUE_X) value_string = icalparameter_get_xvalue(param); else value_string = icalparameter_enum_to_string(value); if (!value_string) return NULL; xparam = xmlNewNode(NULL, BAD_CAST lcase(icalmemory_tmp_copy(kind_string))); xmlNewTextChild(xparam, NULL, BAD_CAST type_string, BAD_CAST value_string); return xparam; }
/* * 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; }
const char* icallangbind_property_eval_string(icalproperty* prop, char* sep) { char tmp[25]; size_t buf_size = 1024; char* buf = icalmemory_new_buffer(buf_size); char* buf_ptr = buf; icalparameter *param; icalvalue* value; if( prop == 0) { return 0; } 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: { const char* str = icalvalue_as_ical_string(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); break; } } } /* Add Parameters */ for(param = icalproperty_get_first_parameter(prop,ICAL_ANY_PARAMETER); param != 0; param = icalproperty_get_next_parameter(prop,ICAL_ANY_PARAMETER)) { const char* str = icalparameter_as_ical_string(param); char *copy = icalmemory_tmp_copy(str); char *v; if(copy == 0) { icalerror_set_errno(ICAL_NEWFAILED_ERROR); continue; } v = strchr(copy,'='); if(v == 0) { continue; } *v = 0; v++; APPENDS(", "); APPENDC('\''); APPENDS(copy); APPENDC('\''); APPENDS(sep); APPENDC('\''); APPENDS(v); APPENDC('\''); } APPENDC('}'); icalmemory_add_tmp_buffer(buf); return buf; }