diff options
Diffstat (limited to 'src/libical/icalvalue.c')
-rw-r--r-- | src/libical/icalvalue.c | 1513 |
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 */ |