summaryrefslogtreecommitdiff
path: root/src/libical/icalvalue.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libical/icalvalue.c')
-rw-r--r--src/libical/icalvalue.c1513
1 files changed, 1513 insertions, 0 deletions
diff --git a/src/libical/icalvalue.c b/src/libical/icalvalue.c
new file mode 100644
index 0000000..bad30e2
--- /dev/null
+++ b/src/libical/icalvalue.c
@@ -0,0 +1,1513 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vi:set ts=4 sts=4 sw=4 expandtab : */
+/*======================================================================
+ FILE: icalvalue.c
+ CREATOR: eric 02 May 1999
+
+ $Id: icalvalue.c,v 1.44 2008-01-15 23:17:43 dothebart Exp $
+
+
+ (C) COPYRIGHT 2000, Eric Busboom <eric@softwarestudio.org>
+ http://www.softwarestudio.org
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ The LGPL as published by the Free Software Foundation, version
+ 2.1, available at: http://www.fsf.org/copyleft/lesser.html
+
+ Or:
+
+ The Mozilla Public License Version 1.0. You may obtain a copy of
+ the License at http://www.mozilla.org/MPL/
+
+ The original code is icalvalue.c
+
+ Contributions from:
+ Graham Davison <g.m.davison@computer.org>
+
+
+======================================================================*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "icalerror.h"
+#include "icalmemory.h"
+#include "icalparser.h"
+#include "icalenums.h"
+#include "icalvalueimpl.h"
+
+#include <stdlib.h> /* for malloc */
+#include <stdio.h> /* for snprintf */
+#include <string.h> /* For memset, others */
+#include <stddef.h> /* For offsetof() macro */
+#include <errno.h>
+#include <time.h> /* for mktime */
+#include <stdlib.h> /* for atoi and atof */
+#include <limits.h> /* for SHRT_MAX */
+#include <locale.h>
+#include <ctype.h> /* for isspace and isdigit */
+
+#ifdef WIN32
+#define snprintf _snprintf
+#define strcasecmp stricmp
+#endif
+
+#if _MAC_OS_
+#include "icalmemory_strdup.h"
+#endif
+
+#define TMP_BUF_SIZE 1024
+
+void print_datetime_to_string(char* str, const struct icaltimetype *data);
+void print_date_to_string(char* str, const struct icaltimetype *data);
+void print_time_to_string(char* str, const struct icaltimetype *data);
+
+
+struct icalvalue_impl* icalvalue_new_impl(icalvalue_kind kind){
+
+ struct icalvalue_impl* v;
+
+ if (!icalvalue_kind_is_valid(kind))
+ return NULL;
+
+ if ( ( v = (struct icalvalue_impl*)
+ malloc(sizeof(struct icalvalue_impl))) == 0) {
+ icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+ return 0;
+ }
+
+ strcpy(v->id,"val");
+
+ v->kind = kind;
+ v->size = 0;
+ v->parent = 0;
+ v->x_value = 0;
+ memset(&(v->data),0,sizeof(v->data));
+
+ return v;
+
+}
+
+
+
+icalvalue*
+icalvalue_new (icalvalue_kind kind)
+{
+ return (icalvalue*)icalvalue_new_impl(kind);
+}
+
+icalvalue* icalvalue_new_clone(const icalvalue* old) {
+ struct icalvalue_impl* new;
+
+ new = icalvalue_new_impl(old->kind);
+
+ if (new == 0){
+ return 0;
+ }
+
+ strcpy(new->id, old->id);
+ new->kind = old->kind;
+ new->size = old->size;
+
+ switch (new->kind){
+ case ICAL_ATTACH_VALUE:
+ case ICAL_BINARY_VALUE:
+ {
+ /* Hmm. We just ref the attach value, which may not be the right
+ * thing to do. We cannot quite copy the data, anyways, since we
+ * don't know how long it is.
+ */
+ new->data.v_attach = old->data.v_attach;
+ if (new->data.v_attach)
+ icalattach_ref (new->data.v_attach);
+
+ break;
+ }
+ case ICAL_QUERY_VALUE:
+ case ICAL_STRING_VALUE:
+ case ICAL_TEXT_VALUE:
+ case ICAL_CALADDRESS_VALUE:
+ case ICAL_URI_VALUE:
+ {
+ if (old->data.v_string != 0) {
+ new->data.v_string=icalmemory_strdup(old->data.v_string);
+
+ if ( new->data.v_string == 0 ) {
+ return 0;
+ }
+
+ }
+ break;
+ }
+ case ICAL_RECUR_VALUE:
+ {
+ if(old->data.v_recur != 0){
+ new->data.v_recur = malloc(sizeof(struct icalrecurrencetype));
+
+ if(new->data.v_recur == 0){
+ return 0;
+ }
+
+ memcpy( new->data.v_recur, old->data.v_recur,
+ sizeof(struct icalrecurrencetype));
+ }
+ break;
+ }
+
+ case ICAL_X_VALUE:
+ {
+ if (old->x_value != 0) {
+ new->x_value=icalmemory_strdup(old->x_value);
+
+ if (new->x_value == 0) {
+ return 0;
+ }
+ }
+
+ break;
+ }
+
+ default:
+ {
+ /* all of the other types are stored as values, not
+ pointers, so we can just copy the whole structure. */
+
+ new->data = old->data;
+ }
+ }
+
+ return new;
+}
+
+static char* icalmemory_strdup_and_dequote(const char* str)
+{
+ const char* p;
+ char* out = (char*)malloc(sizeof(char) * strlen(str) +1);
+ char* pout;
+
+ if (out == 0){
+ return 0;
+ }
+
+ pout = out;
+
+ for (p = str; *p!=0; p++){
+
+ if( *p == '\\')
+ {
+ p++;
+ switch(*p){
+ case 0:
+ {
+ *pout = '\0';
+ break;
+
+ }
+ case 'n':
+ case 'N':
+ {
+ *pout = '\n';
+ break;
+ }
+ case 't':
+ case 'T':
+ {
+ *pout = '\t';
+ break;
+ }
+ case 'r':
+ case 'R':
+ {
+ *pout = '\r';
+ break;
+ }
+ case 'b':
+ case 'B':
+ {
+ *pout = '\b';
+ break;
+ }
+ case 'f':
+ case 'F':
+ {
+ *pout = '\f';
+ break;
+ }
+ case ';':
+ case ',':
+ case '"':
+ case '\\':
+ {
+ *pout = *p;
+ break;
+ }
+ default:
+ {
+ *pout = ' ';
+ }
+ }
+ } else {
+ *pout = *p;
+ }
+
+ pout++;
+
+ }
+
+ *pout = '\0';
+
+ return out;
+}
+
+/*
+ * FIXME
+ *
+ * This is a bad API, as it forces callers to specify their own X type.
+ * This function should take care of this by itself.
+ */
+static
+icalvalue* icalvalue_new_enum(icalvalue_kind kind, int x_type, const char* str)
+{
+ int e = icalproperty_kind_and_string_to_enum(kind, str);
+ struct icalvalue_impl *value;
+
+ if(e != 0 && icalproperty_enum_belongs_to_property(
+ icalproperty_value_kind_to_kind(kind),e)) {
+
+ value = icalvalue_new_impl(kind);
+ value->data.v_enum = e;
+ } else {
+ /* Make it an X value */
+ value = icalvalue_new_impl(kind);
+ value->data.v_enum = x_type;
+ icalvalue_set_x(value,str);
+ }
+
+ return value;
+}
+
+/**
+ * Transforms a simple float number string into a double.
+ * The decimal separator (if any) of the double has to be '.'
+ * The code is locale *independant* and does *not* change the locale.
+ * It should be thread safe.
+ * If you want a code that that does the same job with a decimal separator
+ * dependant on the current locale, then use strtof() from libc.
+ */
+int simple_str_to_float(const char* from,
+ float *result,
+ char** to)
+{
+#define TMP_NUM_SIZE 100
+ char *start=NULL, *end=NULL, *cur=(char*)from ;
+ char tmp_buf[TMP_NUM_SIZE+1] ; /*hack*/
+ struct lconv *loc_data = localeconv () ;
+ int i=0 ;
+
+ /*sanity checks*/
+ if (!from || !result) {
+ return 1 ;
+ }
+
+ /*skip the white spaces at the beginning*/
+ while (cur && isspace (*cur))
+ cur++ ;
+
+ start = cur ;
+ /*
+ * copy the part that looks like a double into tmp_buf
+ * so that we can call strtof() on it.
+ * during the copy, we give ourselves a chance to convert the '.'
+ * into the decimal separator of the current locale.
+ */
+ while (cur && (isdigit (*cur) ||
+ *cur == '.' ||
+ *cur == '+' ||
+ *cur == '-')){
+ ++cur ;
+ }
+ end = cur ;
+ if (end - start + 1> 100) {
+ /*huh hoh, number is too big. getting out*/
+ return 1 ;
+ }
+ memset(tmp_buf, 0, TMP_NUM_SIZE+1) ;
+ i=0 ;
+ /*
+ * copy the float number string into tmp_buf, and take
+ * care to have the (optional) decimal separator be the one
+ * of the current locale.
+ */
+ for (i=0 ; i < end - from ;++i) {
+ if (start[i] == '.'
+ && loc_data
+ && loc_data->decimal_point
+ && loc_data->decimal_point[0]
+ && loc_data->decimal_point[0] != '.') {
+ /*replace '.' by the digit separator of the current locale*/
+ tmp_buf[i] = loc_data->decimal_point[0] ;
+ } else {
+ tmp_buf[i] = start[i] ;
+ }
+ }
+ if (to)
+ *to = end ;
+ *result = atof(tmp_buf) ;
+ return 0 ;
+}
+
+icalvalue* icalvalue_new_from_string_with_error(icalvalue_kind kind,const char* str,icalproperty** error)
+{
+
+ struct icalvalue_impl *value = 0;
+
+ icalerror_check_arg_rz(str!=0,"str");
+
+ if (error != 0){
+ *error = 0;
+ }
+
+ switch (kind){
+
+ case ICAL_ATTACH_VALUE:
+ {
+ icalattach *attach;
+
+ attach = icalattach_new_from_url (str);
+ if (!attach)
+ break;
+
+ value = icalvalue_new_attach (attach);
+ icalattach_unref (attach);
+ break;
+ }
+
+ case ICAL_BINARY_VALUE:
+ {
+ icalattach *attach;
+ attach = icalattach_new_from_data ((unsigned char*)str, 0, 0);
+ if ( !attach )
+ break;
+ value = icalvalue_new_attach (attach);
+ icalattach_unref (attach);
+ break;
+ }
+ case ICAL_BOOLEAN_VALUE:
+ {
+ /* HACK */
+ value = 0;
+
+ if (error != 0){
+ char temp[TMP_BUF_SIZE];
+ snprintf(temp,sizeof(temp),"%s Values are not implemented",
+ icalvalue_kind_to_string(kind));
+ *error = icalproperty_vanew_xlicerror(
+ temp,
+ icalparameter_new_xlicerrortype(
+ ICAL_XLICERRORTYPE_VALUEPARSEERROR),
+ 0);
+ }
+ break;
+ }
+
+
+ case ICAL_TRANSP_VALUE:
+ value = icalvalue_new_enum(kind, (int)ICAL_TRANSP_X,str);
+ break;
+ case ICAL_METHOD_VALUE:
+ value = icalvalue_new_enum(kind, (int)ICAL_METHOD_X,str);
+ break;
+ case ICAL_STATUS_VALUE:
+ value = icalvalue_new_enum(kind, (int)ICAL_STATUS_X,str);
+ break;
+ case ICAL_ACTION_VALUE:
+ value = icalvalue_new_enum(kind, (int)ICAL_ACTION_X,str);
+ break;
+
+ case ICAL_QUERY_VALUE:
+ value = icalvalue_new_query(str);
+ break;
+
+ case ICAL_CLASS_VALUE:
+ value = icalvalue_new_enum(kind, (int)ICAL_CLASS_X,str);
+ break;
+ case ICAL_CMD_VALUE:
+ value = icalvalue_new_enum(kind, ICAL_CMD_X,str);
+ break;
+ case ICAL_QUERYLEVEL_VALUE:
+ value = icalvalue_new_enum(kind, ICAL_QUERYLEVEL_X,str);
+ break;
+ case ICAL_CARLEVEL_VALUE:
+ value = icalvalue_new_enum(kind, ICAL_CARLEVEL_X,str);
+ break;
+
+ case ICAL_INTEGER_VALUE:
+ value = icalvalue_new_integer(atoi(str));
+ break;
+
+ case ICAL_FLOAT_VALUE:
+ value = icalvalue_new_float((float)atof(str));
+ break;
+
+ case ICAL_UTCOFFSET_VALUE:
+ {
+ int t,utcoffset, hours, minutes, seconds;
+ /* treat the UTCOFSET string a a decimal number, disassemble its digits
+ and reconstruct it as sections */
+ t = strtol(str,0,10);
+ /* add phantom seconds field */
+ if(abs(t)<9999){t *= 100; }
+ hours = (t/10000);
+ minutes = (t-hours*10000)/100;
+ seconds = (t-hours*10000-minutes*100);
+ utcoffset = hours*3600+minutes*60+seconds;
+
+ value = icalvalue_new_utcoffset(utcoffset);
+
+ break;
+ }
+
+ case ICAL_TEXT_VALUE:
+ {
+ char* dequoted_str = icalmemory_strdup_and_dequote(str);
+ value = icalvalue_new_text(dequoted_str);
+ free(dequoted_str);
+ break;
+ }
+
+ case ICAL_STRING_VALUE:
+ value = icalvalue_new_string(str);
+ break;
+
+ case ICAL_CALADDRESS_VALUE:
+ value = icalvalue_new_caladdress(str);
+ break;
+
+ case ICAL_URI_VALUE:
+ value = icalvalue_new_uri(str);
+ break;
+
+ case ICAL_GEO_VALUE:
+ {
+ char *cur=NULL ;
+ struct icalgeotype geo = {0.0, 0.0};
+
+ if (simple_str_to_float (str, &geo.lat, &cur)) {
+ goto geo_parsing_error ;
+ }
+
+ /*skip white spaces*/
+ while (cur && isspace (*cur)) {
+ ++cur ;
+ }
+
+ /*there is a ';' between the latitude and longitude parts*/
+ if (!cur || *cur != ';') {
+ goto geo_parsing_error ;
+ }
+
+ ++cur ;
+ if (!cur)
+ goto geo_parsing_error ;
+
+ /*skip white spaces*/
+ while (cur && isspace (*cur)) {
+ ++cur ;
+ }
+
+ if (simple_str_to_float (cur, &geo.lon, &cur)) {
+ goto geo_parsing_error ;
+ }
+ value = icalvalue_new_geo (geo) ;
+ break ;
+
+geo_parsing_error:
+ if (error != 0){
+ char temp[TMP_BUF_SIZE];
+ sprintf(temp, "Could not parse %s as a %s property",
+ str, icalvalue_kind_to_string(kind));
+ *error = icalproperty_vanew_xlicerror(
+ temp,
+ icalparameter_new_xlicerrortype(
+ ICAL_XLICERRORTYPE_VALUEPARSEERROR),
+ 0);
+ }
+ }
+ break;
+
+ case ICAL_RECUR_VALUE:
+ {
+ struct icalrecurrencetype rt;
+ rt = icalrecurrencetype_from_string(str);
+ if(rt.freq != ICAL_NO_RECURRENCE){
+ value = icalvalue_new_recur(rt);
+ }
+ break;
+ }
+
+ case ICAL_DATE_VALUE:
+ case ICAL_DATETIME_VALUE:
+ {
+ struct icaltimetype tt;
+
+ tt = icaltime_from_string(str);
+ if(!icaltime_is_null_time(tt)){
+ value = icalvalue_new_impl(kind);
+ value->data.v_time = tt;
+
+ icalvalue_reset_kind(value);
+ }
+ break;
+ }
+
+ case ICAL_DATETIMEPERIOD_VALUE:
+ {
+ struct icaltimetype tt;
+ struct icalperiodtype p;
+ tt = icaltime_from_string(str);
+
+ if(!icaltime_is_null_time(tt)){
+ value = icalvalue_new_datetime(tt);
+ break;
+ }
+
+ p = icalperiodtype_from_string(str);
+ if (!icalperiodtype_is_null_period(p)){
+ value = icalvalue_new_period(p);
+ }
+
+ break;
+ }
+
+ case ICAL_DURATION_VALUE:
+ {
+ struct icaldurationtype dur = icaldurationtype_from_string(str);
+
+ if (!icaldurationtype_is_bad_duration(dur)) { /* failed to parse */
+ value = icalvalue_new_duration(dur);
+ }
+
+ break;
+ }
+
+ case ICAL_PERIOD_VALUE:
+ {
+ struct icalperiodtype p;
+ p = icalperiodtype_from_string(str);
+
+ if(!icalperiodtype_is_null_period(p)){
+ value = icalvalue_new_period(p);
+ }
+ break;
+ }
+
+ case ICAL_TRIGGER_VALUE:
+ {
+ struct icaltriggertype tr = icaltriggertype_from_string(str);
+ if (!icaltriggertype_is_bad_trigger(tr)) {
+ value = icalvalue_new_trigger(tr);
+ }
+ break;
+ }
+
+ case ICAL_REQUESTSTATUS_VALUE:
+ {
+ struct icalreqstattype rst = icalreqstattype_from_string(str);
+ if(rst.code != ICAL_UNKNOWN_STATUS){
+ value = icalvalue_new_requeststatus(rst);
+ }
+ break;
+
+ }
+
+ case ICAL_X_VALUE:
+ {
+ char* dequoted_str = icalmemory_strdup_and_dequote(str);
+ value = icalvalue_new_x(dequoted_str);
+ free(dequoted_str);
+ }
+ break;
+
+ default:
+ {
+ if (error != 0 ){
+ char temp[TMP_BUF_SIZE];
+
+ snprintf(temp,TMP_BUF_SIZE,"Unknown type for \'%s\'",str);
+
+ *error = icalproperty_vanew_xlicerror(
+ temp,
+ icalparameter_new_xlicerrortype(
+ ICAL_XLICERRORTYPE_VALUEPARSEERROR),
+ 0);
+ }
+
+ icalerror_warn("icalvalue_new_from_string got an unknown value type");
+ value=0;
+ }
+ }
+
+
+ if (error != 0 && *error == 0 && value == 0){
+ char temp[TMP_BUF_SIZE];
+
+ snprintf(temp,TMP_BUF_SIZE,"Failed to parse value: \'%s\'",str);
+
+ *error = icalproperty_vanew_xlicerror(
+ temp,
+ icalparameter_new_xlicerrortype(
+ ICAL_XLICERRORTYPE_VALUEPARSEERROR),
+ 0);
+ }
+
+
+ return value;
+
+}
+
+icalvalue* icalvalue_new_from_string(icalvalue_kind kind,const char* str)
+{
+ return icalvalue_new_from_string_with_error(kind,str,(icalproperty**)0);
+}
+
+
+
+void
+icalvalue_free (icalvalue* v)
+{
+ icalerror_check_arg_rv((v != 0),"value");
+
+#ifdef ICAL_FREE_ON_LIST_IS_ERROR
+ icalerror_assert( (v->parent ==0),"This value is still attached to a property");
+
+#else
+ if(v->parent !=0){
+ return;
+ }
+#endif
+
+ if(v->x_value != 0){
+ free(v->x_value);
+ }
+
+ switch (v->kind){
+ case ICAL_BINARY_VALUE:
+ case ICAL_ATTACH_VALUE: {
+ if (v->data.v_attach) {
+ icalattach_unref (v->data.v_attach);
+ v->data.v_attach = NULL;
+ }
+
+ break;
+ }
+ case ICAL_TEXT_VALUE:
+ case ICAL_CALADDRESS_VALUE:
+ case ICAL_URI_VALUE:
+ case ICAL_QUERY_VALUE:
+ {
+ if (v->data.v_string != 0) {
+ free((void*)v->data.v_string);
+ v->data.v_string = 0;
+ }
+ break;
+ }
+ case ICAL_RECUR_VALUE:
+ {
+ if(v->data.v_recur != 0){
+ free((void*)v->data.v_recur);
+ v->data.v_recur = 0;
+ }
+ break;
+ }
+
+ default:
+ {
+ /* Nothing to do */
+ }
+ }
+
+ v->kind = ICAL_NO_VALUE;
+ v->size = 0;
+ v->parent = 0;
+ memset(&(v->data),0,sizeof(v->data));
+ v->id[0] = 'X';
+ free(v);
+}
+
+int
+icalvalue_is_valid (const icalvalue* value)
+{
+ if(value == 0){
+ return 0;
+ }
+
+ return 1;
+}
+
+static char* icalvalue_binary_as_ical_string_r(const icalvalue* value) {
+
+ const char* data;
+ char* str;
+ icalerror_check_arg_rz( (value!=0),"value");
+
+ data = icalvalue_get_binary(value);
+
+ str = (char*)icalmemory_new_buffer(60);
+ snprintf(str, 60,"icalvalue_binary_as_ical_string is not implemented yet");
+
+ return str;
+}
+
+
+#define MAX_INT_DIGITS 12 /* Enough for 2^32 + sign*/
+
+static char* icalvalue_int_as_ical_string_r(const icalvalue* value) {
+ int data;
+ char* str = (char*)icalmemory_new_buffer(MAX_INT_DIGITS);
+
+ icalerror_check_arg_rz( (value!=0),"value");
+
+ data = icalvalue_get_integer(value);
+
+ snprintf(str,MAX_INT_DIGITS,"%d",data);
+
+ return str;
+}
+
+
+static char* icalvalue_utcoffset_as_ical_string_r(const icalvalue* value)
+{
+ int data,h,m,s;
+ char sign;
+ char* str = (char*)icalmemory_new_buffer(9);
+
+ icalerror_check_arg_rz( (value!=0),"value");
+
+ data = icalvalue_get_utcoffset(value);
+
+ if (abs(data) == data){
+ sign = '+';
+ } else {
+ sign = '-';
+ }
+
+ h = data/3600;
+ m = (data - (h*3600))/ 60;
+ s = (data - (h*3600) - (m*60));
+
+ if (s > 0)
+ snprintf(str,9,"%c%02d%02d%02d",sign,abs(h),abs(m),abs(s));
+ else
+ snprintf(str,9,"%c%02d%02d",sign,abs(h),abs(m));
+
+ return str;
+}
+
+static char* icalvalue_string_as_ical_string_r(const icalvalue* value) {
+
+ const char* data;
+ char* str = 0;
+ icalerror_check_arg_rz( (value!=0),"value");
+ data = value->data.v_string;
+
+ str = (char*)icalmemory_new_buffer(strlen(data)+1);
+
+ strcpy(str,data);
+
+ return str;
+}
+
+
+static char* icalvalue_recur_as_ical_string_r(const icalvalue* value)
+{
+ struct icalrecurrencetype *recur = value->data.v_recur;
+ return icalrecurrencetype_as_string_r(recur);
+}
+
+ /* @todo This is not RFC2445 compliant.
+ * The RFC only allows:
+ * TSAFE-CHAR = %x20-21 / %x23-2B / %x2D-39 / %x3C-5B / %x5D-7E / NON-US-ASCII
+ * As such, \t\r\b\f are not allowed, not even escaped
+ */
+
+static char* icalvalue_text_as_ical_string_r(const icalvalue* value) {
+ char *str;
+ char *str_p;
+ const char *p;
+ size_t buf_sz;
+
+ buf_sz = strlen(value->data.v_string)+1;
+
+ str_p = str = (char*)icalmemory_new_buffer(buf_sz);
+
+ if (str_p == 0){
+ return 0;
+ }
+
+ for(p=value->data.v_string; *p!=0; p++){
+
+ switch(*p){
+ case '\n': {
+ icalmemory_append_string(&str,&str_p,&buf_sz,"\\n");
+ break;
+ }
+
+ case '\t': {
+ icalmemory_append_string(&str,&str_p,&buf_sz,"\\t");
+ break;
+ }
+ case '\r': {
+ icalmemory_append_string(&str,&str_p,&buf_sz,"\\r");
+ break;
+ }
+ case '\b': {
+ icalmemory_append_string(&str,&str_p,&buf_sz,"\\b");
+ break;
+ }
+ case '\f': {
+ icalmemory_append_string(&str,&str_p,&buf_sz,"\\f");
+ break;
+ }
+
+ case ';':
+ case ',':
+ case '"':
+ case '\\':{
+ icalmemory_append_char(&str,&str_p,&buf_sz,'\\');
+ icalmemory_append_char(&str,&str_p,&buf_sz,*p);
+ break;
+ }
+
+ default: {
+ icalmemory_append_char(&str,&str_p,&buf_sz,*p);
+ }
+ }
+ }
+
+ /* Assume the last character is not a '\0' and add one. We could
+ check *str_p != 0, but that would be an uninitialized memory
+ read. */
+
+
+ icalmemory_append_char(&str,&str_p,&buf_sz,'\0');
+ return str;
+}
+
+
+static char* icalvalue_text_as_ical_string(const icalvalue* value) {
+ char *buf;
+ buf = icalvalue_text_as_ical_string_r(value);
+ icalmemory_add_tmp_buffer(buf);
+ return buf;
+}
+
+
+
+static char*
+icalvalue_attach_as_ical_string_r(const icalvalue* value)
+{
+ icalattach *a;
+ char * str;
+
+ icalerror_check_arg_rz( (value!=0),"value");
+
+ a = icalvalue_get_attach(value);
+
+ if (icalattach_get_is_url (a)) {
+ const char *url;
+
+ url = icalattach_get_url (a);
+ str = icalmemory_new_buffer (strlen (url) + 1);
+ strcpy (str, url);
+ return str;
+ } else {
+ const char *data = 0;
+ data = (const char*)icalattach_get_data(a);
+ str = icalmemory_new_buffer (strlen (data) + 1);
+ strcpy (str, data);
+ return str;
+}
+}
+
+
+static char* icalvalue_duration_as_ical_string_r(const icalvalue* value) {
+
+ struct icaldurationtype data;
+
+ icalerror_check_arg_rz( (value!=0),"value");
+ data = icalvalue_get_duration(value);
+
+ return icaldurationtype_as_ical_string_r(data);
+}
+
+
+
+void print_time_to_string(char* str, const struct icaltimetype *data)
+{
+ char temp[20];
+ str[0] = '\0';
+
+ if (data != 0) {
+ if (icaltime_is_utc(*data)){
+ snprintf(temp,sizeof(temp),"%02d%02d%02dZ",data->hour,data->minute,data->second);
+ strncat(str,temp,7);
+ } else {
+ snprintf(temp,sizeof(temp),"%02d%02d%02d",data->hour,data->minute,data->second);
+ strncat(str,temp,6);
+ }
+ }
+}
+
+
+void print_date_to_string(char* str, const struct icaltimetype *data)
+{
+ char temp[20];
+ str[0] = '\0';
+
+ if (data != 0) {
+ snprintf(temp,sizeof(temp),"%04d%02d%02d",data->year,data->month,data->day);
+ strncat(str,temp,8);
+ }
+}
+
+static char* icalvalue_date_as_ical_string_r(const icalvalue* value) {
+
+ struct icaltimetype data;
+ char* str;
+ icalerror_check_arg_rz( (value!=0),"value");
+ data = icalvalue_get_date(value);
+
+ str = (char*)icalmemory_new_buffer(9);
+
+ str[0] = '\0';
+ print_date_to_string(str,&data);
+
+ return str;
+}
+
+void print_datetime_to_string(char* str, const struct icaltimetype *data)
+{
+ char temp[20];
+ str[0] = '\0';
+
+ if (data != 0) {
+ print_date_to_string(str,data);
+ if ( !data->is_date ) {
+ strncat(str,"T",19);
+ temp[0] = '\0';
+ print_time_to_string(temp,data);
+ strncat(str,temp,19);
+ }
+ }
+}
+
+
+static char* icalvalue_datetime_as_ical_string_r(const icalvalue* value) {
+
+ struct icaltimetype data;
+ char* str;
+ icalvalue_kind kind = icalvalue_isa(value);
+
+ icalerror_check_arg_rz( (value!=0),"value");
+
+
+ if( !(kind == ICAL_DATE_VALUE || kind == ICAL_DATETIME_VALUE ))
+ {
+ icalerror_set_errno(ICAL_BADARG_ERROR);
+ return 0;
+ }
+
+ data = icalvalue_get_datetime(value);
+
+ str = (char*)icalmemory_new_buffer(20);
+
+ str[0] = 0;
+ print_datetime_to_string(str,&data);
+
+ return str;
+
+}
+
+static char* icalvalue_float_as_ical_string_r(const icalvalue* value) {
+
+ float data;
+ char* str;
+ icalerror_check_arg_rz( (value!=0),"value");
+ data = icalvalue_get_float(value);
+
+ str = (char*)icalmemory_new_buffer(40);
+
+ snprintf(str,40,"%f",data);
+
+ return str;
+}
+
+
+static char* icalvalue_geo_as_ical_string_r(const icalvalue* value) {
+
+ struct icalgeotype data;
+ char* str;
+ icalerror_check_arg_rz( (value!=0),"value");
+
+ data = icalvalue_get_geo(value);
+
+ str = (char*)icalmemory_new_buffer(80);
+
+ snprintf(str,80,"%f;%f",data.lat,data.lon);
+
+ return str;
+}
+
+
+static char* icalvalue_datetimeperiod_as_ical_string_r(const icalvalue* value) {
+ struct icaldatetimeperiodtype dtp = icalvalue_get_datetimeperiod(value);
+
+ icalerror_check_arg_rz( (value!=0),"value");
+
+ if(!icaltime_is_null_time(dtp.time)){
+ return icaltime_as_ical_string_r(dtp.time);
+ } else {
+ return icalperiodtype_as_ical_string_r(dtp.period);
+ }
+}
+
+
+static char* icalvalue_period_as_ical_string_r(const icalvalue* value) {
+ struct icalperiodtype data;
+ icalerror_check_arg_rz( (value!=0),"value");
+ data = icalvalue_get_period(value);
+
+ return icalperiodtype_as_ical_string_r(data);
+
+}
+
+
+static char* icalvalue_trigger_as_ical_string_r(const icalvalue* value) {
+
+ struct icaltriggertype data;
+
+ icalerror_check_arg_rz( (value!=0),"value");
+ data = icalvalue_get_trigger(value);
+
+ if(!icaltime_is_null_time(data.time)){
+ return icaltime_as_ical_string_r(data.time);
+ } else {
+ return icaldurationtype_as_ical_string_r(data.duration);
+ }
+
+}
+
+const char*
+icalvalue_as_ical_string(const icalvalue* value)
+{
+ char *buf;
+ buf = icalvalue_as_ical_string_r(value);
+ icalmemory_add_tmp_buffer(buf);
+ return buf;
+}
+
+
+char*
+icalvalue_as_ical_string_r(const icalvalue* value)
+{
+ if(value == 0){
+ return 0;
+ }
+
+ switch (value->kind){
+
+ case ICAL_ATTACH_VALUE:
+ return icalvalue_attach_as_ical_string_r(value);
+
+ case ICAL_BINARY_VALUE:
+ return icalvalue_binary_as_ical_string_r(value);
+
+ case ICAL_BOOLEAN_VALUE:
+ case ICAL_INTEGER_VALUE:
+ return icalvalue_int_as_ical_string_r(value);
+
+ case ICAL_UTCOFFSET_VALUE:
+ return icalvalue_utcoffset_as_ical_string_r(value);
+
+ case ICAL_TEXT_VALUE:
+ return icalvalue_text_as_ical_string_r(value);
+
+ case ICAL_QUERY_VALUE:
+ return icalvalue_string_as_ical_string_r(value);
+
+ case ICAL_STRING_VALUE:
+ case ICAL_URI_VALUE:
+ case ICAL_CALADDRESS_VALUE:
+ return icalvalue_string_as_ical_string_r(value);
+
+ case ICAL_DATE_VALUE:
+ return icalvalue_date_as_ical_string_r(value);
+ case ICAL_DATETIME_VALUE:
+ return icalvalue_datetime_as_ical_string_r(value);
+ case ICAL_DURATION_VALUE:
+ return icalvalue_duration_as_ical_string_r(value);
+
+ case ICAL_PERIOD_VALUE:
+ return icalvalue_period_as_ical_string_r(value);
+ case ICAL_DATETIMEPERIOD_VALUE:
+ return icalvalue_datetimeperiod_as_ical_string_r(value);
+
+ case ICAL_FLOAT_VALUE:
+ return icalvalue_float_as_ical_string_r(value);
+
+ case ICAL_GEO_VALUE:
+ return icalvalue_geo_as_ical_string_r(value);
+
+ case ICAL_RECUR_VALUE:
+ return icalvalue_recur_as_ical_string_r(value);
+
+ case ICAL_TRIGGER_VALUE:
+ return icalvalue_trigger_as_ical_string_r(value);
+
+ case ICAL_REQUESTSTATUS_VALUE:
+ return icalreqstattype_as_string_r(value->data.v_requeststatus);
+
+ case ICAL_ACTION_VALUE:
+ case ICAL_CMD_VALUE:
+ case ICAL_QUERYLEVEL_VALUE:
+ case ICAL_CARLEVEL_VALUE:
+ case ICAL_METHOD_VALUE:
+ case ICAL_STATUS_VALUE:
+ case ICAL_TRANSP_VALUE:
+ case ICAL_CLASS_VALUE:
+ if(value->x_value !=0){
+ return icalmemory_strdup(value->x_value);
+ }
+
+ return icalproperty_enum_to_string_r(value->data.v_enum);
+
+ case ICAL_X_VALUE:
+ if (value->x_value != 0)
+ return icalmemory_strdup(value->x_value);
+
+ /* FALLTHRU */
+
+ case ICAL_NO_VALUE:
+ default:
+ {
+ return 0;
+ }
+ }
+}
+
+
+icalvalue_kind
+icalvalue_isa (const icalvalue* value)
+{
+ if(value == 0){
+ return ICAL_NO_VALUE;
+ }
+
+ return value->kind;
+}
+
+
+int
+icalvalue_isa_value (void* value)
+{
+ struct icalvalue_impl *impl = (struct icalvalue_impl *)value;
+
+ icalerror_check_arg_rz( (value!=0), "value");
+
+ if (strcmp(impl->id,"val") == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+static int icalvalue_is_time(const icalvalue* a) {
+ icalvalue_kind kind = icalvalue_isa(a);
+
+ if(kind == ICAL_DATETIME_VALUE ||
+ kind == ICAL_DATE_VALUE ){
+ return 1;
+ }
+
+ return 0;
+
+}
+
+/*
+ * In case of error, this function returns 0. This is partly bogus, as 0 is
+ * not part of the returned enum.
+ * FIXME We should probably add an error value to the enum.
+ */
+icalparameter_xliccomparetype
+icalvalue_compare(const icalvalue* a, const icalvalue *b)
+{
+
+ icalerror_check_arg_rz( (a!=0), "a");
+ icalerror_check_arg_rz( (b!=0), "b");
+
+ /* Not the same type; they can only be unequal */
+ if( ! (icalvalue_is_time(a) && icalvalue_is_time(b)) &&
+ icalvalue_isa(a) != icalvalue_isa(b)){
+ return ICAL_XLICCOMPARETYPE_NOTEQUAL;
+ }
+
+ switch (icalvalue_isa(a)){
+
+ case ICAL_ATTACH_VALUE:
+ {
+ if (icalattach_get_is_url(a->data.v_attach) &&
+ icalattach_get_is_url(b->data.v_attach)) {
+ if (strcasecmp(icalattach_get_url(a->data.v_attach),
+ icalattach_get_url(b->data.v_attach)) == 0)
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ else
+ return ICAL_XLICCOMPARETYPE_NOTEQUAL;
+ }
+ else {
+ if (a->data.v_attach == b->data.v_attach)
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ else
+ return ICAL_XLICCOMPARETYPE_NOTEQUAL;
+ }
+ }
+ case ICAL_BINARY_VALUE:
+ {
+ if (a->data.v_attach == b->data.v_attach)
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ else
+ return ICAL_XLICCOMPARETYPE_NOTEQUAL;
+ }
+
+ case ICAL_BOOLEAN_VALUE:
+ {
+ if (icalvalue_get_boolean(a) == icalvalue_get_boolean(b)){
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ } else {
+ return ICAL_XLICCOMPARETYPE_NOTEQUAL;
+ }
+ }
+
+ case ICAL_FLOAT_VALUE:
+ {
+ if (a->data.v_float > b->data.v_float){
+ return ICAL_XLICCOMPARETYPE_GREATER;
+ } else if (a->data.v_float < b->data.v_float){
+ return ICAL_XLICCOMPARETYPE_LESS;
+ } else {
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ }
+ }
+
+ case ICAL_INTEGER_VALUE:
+ case ICAL_UTCOFFSET_VALUE:
+ {
+ if (a->data.v_int > b->data.v_int){
+ return ICAL_XLICCOMPARETYPE_GREATER;
+ } else if (a->data.v_int < b->data.v_int){
+ return ICAL_XLICCOMPARETYPE_LESS;
+ } else {
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ }
+ }
+
+ case ICAL_DURATION_VALUE:
+ {
+ int dur_a = icaldurationtype_as_int(a->data.v_duration);
+ int dur_b = icaldurationtype_as_int(b->data.v_duration);
+
+ if (dur_a > dur_b){
+ return ICAL_XLICCOMPARETYPE_GREATER;
+ } else if (dur_a < dur_b){
+ return ICAL_XLICCOMPARETYPE_LESS;
+ } else {
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ }
+ }
+
+
+ case ICAL_TEXT_VALUE:
+ case ICAL_URI_VALUE:
+ case ICAL_CALADDRESS_VALUE:
+ case ICAL_TRIGGER_VALUE:
+ case ICAL_DATE_VALUE:
+ case ICAL_DATETIME_VALUE:
+ case ICAL_DATETIMEPERIOD_VALUE:
+ case ICAL_QUERY_VALUE:
+ case ICAL_RECUR_VALUE:
+ {
+ int r;
+ char *temp1, *temp2;
+ temp1 = icalvalue_as_ical_string_r(a);
+ temp2 = icalvalue_as_ical_string_r(b);
+ r = strcmp(temp1, temp2);
+ free(temp1);
+ free(temp2);
+
+ if (r > 0) {
+ return ICAL_XLICCOMPARETYPE_GREATER;
+ } else if (r < 0){
+ return ICAL_XLICCOMPARETYPE_LESS;
+ } else {
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ }
+
+
+ }
+
+ case ICAL_METHOD_VALUE:
+ {
+ if (icalvalue_get_method(a) == icalvalue_get_method(b)){
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ } else {
+ return ICAL_XLICCOMPARETYPE_NOTEQUAL;
+ }
+
+ }
+
+ case ICAL_STATUS_VALUE:
+ {
+ if (icalvalue_get_status(a) == icalvalue_get_status(b)){
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ } else {
+ return ICAL_XLICCOMPARETYPE_NOTEQUAL;
+ }
+
+ }
+
+ case ICAL_TRANSP_VALUE:
+ {
+ if (icalvalue_get_transp(a) == icalvalue_get_transp(b)){
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ } else {
+ return ICAL_XLICCOMPARETYPE_NOTEQUAL;
+ }
+ }
+
+ case ICAL_ACTION_VALUE:
+ {
+ if (icalvalue_get_action(a) == icalvalue_get_action(b)){
+ return ICAL_XLICCOMPARETYPE_EQUAL;
+ } else {
+ return ICAL_XLICCOMPARETYPE_NOTEQUAL;
+ }
+ }
+
+ case ICAL_PERIOD_VALUE:
+ case ICAL_GEO_VALUE:
+ case ICAL_NO_VALUE:
+ default:
+ {
+ icalerror_warn("Comparison not implemented for value type");
+ return 0;
+ }
+ }
+
+}
+
+/** Examine the value and possibly change the kind to agree with the
+ * value
+ */
+
+void icalvalue_reset_kind(icalvalue* value)
+{
+ if( (value->kind==ICAL_DATETIME_VALUE || value->kind==ICAL_DATE_VALUE )&&
+ !icaltime_is_null_time(value->data.v_time) ) {
+
+ if(icaltime_is_date(value->data.v_time)){
+ value->kind = ICAL_DATE_VALUE;
+ } else {
+ value->kind = ICAL_DATETIME_VALUE;
+ }
+ }
+
+}
+
+void icalvalue_set_parent(icalvalue* value,
+ icalproperty* property)
+{
+ value->parent = property;
+}
+
+icalproperty* icalvalue_get_parent(icalvalue* value)
+{
+ return value->parent;
+}
+
+
+int icalvalue_encode_ical_string(const char *szText, char *szEncText, int nMaxBufferLen)
+{
+ char *ptr;
+ icalvalue *value = 0;
+
+ if ((szText == 0) || (szEncText == 0))
+ return 0;
+
+ value = icalvalue_new_from_string(ICAL_STRING_VALUE, szText);
+
+ if (value == 0)
+ return 0;
+
+ ptr = icalvalue_text_as_ical_string_r(value);
+ if (ptr == 0)
+ return 0;
+
+ if ((int)strlen(ptr) >= nMaxBufferLen)
+ {
+ icalvalue_free (value);
+ free(ptr);
+ return 0;
+ }
+
+ strcpy(szEncText, ptr);
+ free(ptr);
+
+ icalvalue_free ((icalvalue*)value);
+
+ return 1;
+}
+
+int icalvalue_decode_ical_string(const char *szText, char *szDecText, int nMaxBufferLen)
+{
+ char *str, *str_p;
+ const char *p;
+ size_t buf_sz;
+
+ if ((szText == 0) || (szDecText == 0))
+ return 0;
+
+ buf_sz = strlen(szText);
+ str_p = str = (char*)icalmemory_new_buffer(buf_sz + 1);
+
+ if (str_p == 0){
+ return 0;
+ }
+
+ for (p=szText; *p!=0; p++) {
+ if (*p == '\\') {
+ icalmemory_append_char (&str,&str_p,&buf_sz,*(p+1));
+ p++;
+ }
+ else
+ icalmemory_append_char (&str,&str_p,&buf_sz,*p);
+ }
+
+ icalmemory_append_char(&str,&str_p,&buf_sz,'\0');
+
+ if ((int)strlen(str) > nMaxBufferLen) {
+ icalmemory_free_buffer(str);
+ return 0;
+ }
+
+ strcpy(szDecText, str);
+
+ icalmemory_free_buffer(str);
+ return 1;
+}
+
+
+/* The remaining interfaces are 'new', 'set' and 'get' for each of the value
+ types */