Back to index

lightning-sunbird  0.9+nobinonly
icalvalue.c
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* vi:set ts=4 sts=4 sw=4 expandtab : */
00003 /*======================================================================
00004   FILE: icalvalue.c
00005   CREATOR: eric 02 May 1999
00006   
00007   $Id: icalvalue.c,v 1.40 2005/01/24 13:11:31 acampi Exp $
00008 
00009 
00010  (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
00011 
00012  This program is free software; you can redistribute it and/or modify
00013  it under the terms of either: 
00014 
00015     The LGPL as published by the Free Software Foundation, version
00016     2.1, available at: http://www.fsf.org/copyleft/lesser.html
00017 
00018   Or:
00019 
00020     The Mozilla Public License Version 1.0. You may obtain a copy of
00021     the License at http://www.mozilla.org/MPL/
00022 
00023   The original code is icalvalue.c
00024 
00025   Contributions from:
00026      Graham Davison (g.m.davison@computer.org)
00027 
00028 
00029 ======================================================================*/
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif
00034 
00035 #include "icalerror.h"
00036 #include "icalmemory.h"
00037 #include "icalparser.h"
00038 #include "icalenums.h"
00039 #include "icalvalueimpl.h"
00040 
00041 #include <stdlib.h> /* for malloc */
00042 #include <stdio.h> /* for snprintf */
00043 #include <string.h> /* For memset, others */
00044 #include <stddef.h> /* For offsetof() macro */
00045 #include <errno.h>
00046 #include <time.h> /* for mktime */
00047 #include <stdlib.h> /* for atoi and atof */
00048 #include <limits.h> /* for SHRT_MAX */         
00049 
00050 #ifdef WIN32
00051 #define snprintf      _snprintf
00052 #define strcasecmp    stricmp
00053 #endif
00054 
00055 #if _MAC_OS_
00056 #include "icalmemory_strdup.h"
00057 #endif
00058 
00059 #define TMP_BUF_SIZE 1024
00060 
00061 void print_datetime_to_string(char* str,  const struct icaltimetype *data);
00062 void print_date_to_string(char* str,  const struct icaltimetype *data);
00063 void print_time_to_string(char* str,  const struct icaltimetype *data);
00064 
00065 
00066 struct icalvalue_impl*  icalvalue_new_impl(icalvalue_kind kind){
00067 
00068     struct icalvalue_impl* v;
00069 
00070     if (!icalvalue_kind_is_valid(kind))
00071       return NULL;
00072 
00073     if ( ( v = (struct icalvalue_impl*)
00074           malloc(sizeof(struct icalvalue_impl))) == 0) {
00075        icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00076        return 0;
00077     }
00078     
00079     strcpy(v->id,"val");
00080     
00081     v->kind = kind;
00082     v->size = 0;
00083     v->parent = 0;
00084     v->x_value = 0;
00085     memset(&(v->data),0,sizeof(v->data));
00086     
00087     return v;
00088 
00089 }
00090 
00091 
00092 
00093 icalvalue*
00094 icalvalue_new (icalvalue_kind kind)
00095 {
00096     return (icalvalue*)icalvalue_new_impl(kind);
00097 }
00098 
00099 icalvalue* icalvalue_new_clone(const icalvalue* old) {
00100     struct icalvalue_impl* new;
00101 
00102     new = icalvalue_new_impl(old->kind);
00103 
00104     if (new == 0){
00105        return 0;
00106     }
00107 
00108     strcpy(new->id, old->id);
00109     new->kind = old->kind;
00110     new->size = old->size;
00111 
00112     switch (new->kind){
00113        case ICAL_ATTACH_VALUE: 
00114        case ICAL_BINARY_VALUE: 
00115        {
00116            /* Hmm.  We just ref the attach value, which may not be the right
00117             * thing to do.  We cannot quite copy the data, anyways, since we
00118             * don't know how long it is.
00119             */
00120            new->data.v_attach = old->data.v_attach;
00121            if (new->data.v_attach)
00122               icalattach_ref (new->data.v_attach);
00123 
00124            break;
00125        }
00126        case ICAL_QUERY_VALUE:
00127        case ICAL_STRING_VALUE:
00128        case ICAL_TEXT_VALUE:
00129        case ICAL_CALADDRESS_VALUE:
00130        case ICAL_URI_VALUE:
00131        {
00132            if (old->data.v_string != 0) { 
00133               new->data.v_string=icalmemory_strdup(old->data.v_string);
00134 
00135               if ( new->data.v_string == 0 ) {
00136                   return 0;
00137               }                 
00138 
00139            }
00140            break;
00141        }
00142        case ICAL_RECUR_VALUE:
00143        {
00144            if(old->data.v_recur != 0){
00145               new->data.v_recur = malloc(sizeof(struct icalrecurrencetype));
00146 
00147               if(new->data.v_recur == 0){
00148                   return 0;
00149               }
00150 
00151               memcpy(       new->data.v_recur, old->data.v_recur,
00152                      sizeof(struct icalrecurrencetype));       
00153            }
00154            break;
00155        }
00156 
00157        case ICAL_X_VALUE: 
00158        {
00159            if (old->x_value != 0) {
00160               new->x_value=icalmemory_strdup(old->x_value);
00161 
00162               if (new->x_value == 0) {
00163                   return 0;
00164               }
00165            }
00166 
00167            break;
00168        }
00169 
00170        default:
00171        {
00172            /* all of the other types are stored as values, not
00173                pointers, so we can just copy the whole structure. */
00174 
00175            new->data = old->data;
00176        }
00177     }
00178 
00179     return new;
00180 }
00181 
00182 static char* icalmemory_strdup_and_dequote(const char* str)
00183 {
00184     const char* p;
00185     char* out = (char*)malloc(sizeof(char) * strlen(str) +1);
00186     char* pout;
00187 
00188     if (out == 0){
00189        return 0;
00190     }
00191 
00192     pout = out;
00193 
00194     for (p = str; *p!=0; p++){
00195        
00196        if( *p == '\\')
00197        {
00198            p++;
00199            switch(*p){
00200               case 0:
00201               {
00202                   *pout = '\0';
00203                   break;
00204 
00205               }
00206               case 'n':
00207               case 'N':
00208               {
00209                   *pout = '\n';
00210                   break;
00211               }
00212               case 't':
00213               case 'T':
00214               {
00215                   *pout = '\t';
00216                   break;
00217               }
00218               case 'r':
00219               case 'R':
00220               {
00221                   *pout = '\r';
00222                   break;
00223               }
00224               case 'b':
00225               case 'B':
00226               {
00227                   *pout = '\b';
00228                   break;
00229               }
00230               case 'f':
00231               case 'F':
00232               {
00233                   *pout = '\f';
00234                   break;
00235               }
00236               case ';':
00237               case ',':
00238               case '"':
00239               case '\\':
00240               {
00241                   *pout = *p;
00242                   break;
00243               }
00244               default:
00245               {
00246                   *pout = ' ';
00247               }             
00248            }
00249        } else {
00250            *pout = *p;
00251        }
00252 
00253        pout++;
00254        
00255     }
00256 
00257     *pout = '\0';
00258 
00259     return out;
00260 }
00261 
00262 /*
00263  * FIXME
00264  *
00265  * This is a bad API, as it forces callers to specify their own X type.
00266  * This function should take care of this by itself.
00267  */
00268 static
00269 icalvalue* icalvalue_new_enum(icalvalue_kind kind, int x_type, const char* str)
00270 {
00271     int e = icalproperty_kind_and_string_to_enum(kind, str);
00272     struct icalvalue_impl *value; 
00273 
00274     if(e != 0 && icalproperty_enum_belongs_to_property(
00275                    icalproperty_value_kind_to_kind(kind),e)) {
00276         
00277         value = icalvalue_new_impl(kind);
00278         value->data.v_enum = e;
00279     } else {
00280         /* Make it an X value */
00281         value = icalvalue_new_impl(kind);
00282         value->data.v_enum = x_type;
00283         icalvalue_set_x(value,str);
00284     }
00285 
00286     return value;
00287 }
00288 
00289 
00290 icalvalue* icalvalue_new_from_string_with_error(icalvalue_kind kind,const char* str,icalproperty** error)
00291 {
00292 
00293     struct icalvalue_impl *value = 0;
00294     
00295     icalerror_check_arg_rz(str!=0,"str");
00296 
00297     if (error != 0){
00298        *error = 0;
00299     }
00300 
00301     switch (kind){
00302        
00303     case ICAL_ATTACH_VALUE:
00304        {
00305            icalattach *attach;
00306 
00307            attach = icalattach_new_from_url (str);
00308            if (!attach)
00309               break;
00310 
00311            value = icalvalue_new_attach (attach);
00312            icalattach_unref (attach);
00313            break;
00314        }
00315 
00316     case ICAL_BINARY_VALUE:
00317     case ICAL_BOOLEAN_VALUE:
00318         {
00319             /* HACK */
00320             value = 0;
00321             
00322            if (error != 0){
00323               char temp[TMP_BUF_SIZE];
00324               snprintf(temp,sizeof(temp),"%s Values are not implemented",
00325                         icalvalue_kind_to_string(kind)); 
00326               *error = icalproperty_vanew_xlicerror( 
00327                                    temp, 
00328                                    icalparameter_new_xlicerrortype( 
00329                                         ICAL_XLICERRORTYPE_VALUEPARSEERROR), 
00330                                    0); 
00331            }
00332            break;
00333        }
00334         
00335 
00336     case ICAL_TRANSP_VALUE:
00337         value = icalvalue_new_enum(kind, (int)ICAL_TRANSP_X,str);
00338         break;
00339     case ICAL_METHOD_VALUE:
00340         value = icalvalue_new_enum(kind, (int)ICAL_METHOD_X,str);
00341         break;
00342     case ICAL_STATUS_VALUE:
00343         value = icalvalue_new_enum(kind, (int)ICAL_STATUS_X,str);
00344         break;
00345     case ICAL_ACTION_VALUE:
00346         value = icalvalue_new_enum(kind, (int)ICAL_ACTION_X,str);
00347         break;
00348 
00349     case ICAL_QUERY_VALUE:
00350            value = icalvalue_new_query(str);
00351            break;
00352 
00353     case ICAL_CLASS_VALUE:
00354         value = icalvalue_new_enum(kind, (int)ICAL_CLASS_X,str);
00355         break;
00356 
00357     case ICAL_CMD_VALUE:
00358         value = icalvalue_new_enum(kind, ICAL_CMD_X,str);
00359         break;
00360     case ICAL_QUERYLEVEL_VALUE:
00361         value = icalvalue_new_enum(kind, ICAL_QUERYLEVEL_X,str);
00362         break;
00363     case ICAL_CARLEVEL_VALUE:
00364         value = icalvalue_new_enum(kind, ICAL_CARLEVEL_X,str);
00365         break;
00366 
00367 
00368     case ICAL_INTEGER_VALUE:
00369            value = icalvalue_new_integer(atoi(str));
00370            break;
00371 
00372     case ICAL_FLOAT_VALUE:
00373            value = icalvalue_new_float((float)atof(str));
00374            break;
00375 
00376     case ICAL_UTCOFFSET_VALUE:
00377        {
00378             int t,utcoffset, hours, minutes, seconds;
00379             /* treat the UTCOFSET string a a decimal number, disassemble its digits
00380                and reconstruct it as sections */
00381             t = strtol(str,0,10);
00382             /* add phantom seconds field */
00383             if(abs(t)<9999){t *= 100; }
00384             hours = (t/10000);
00385             minutes = (t-hours*10000)/100;
00386             seconds = (t-hours*10000-minutes*100);
00387             utcoffset = hours*3600+minutes*60+seconds;
00388 
00389            value = icalvalue_new_utcoffset(utcoffset);
00390 
00391            break;
00392        }
00393         
00394     case ICAL_TEXT_VALUE:
00395        {
00396            char* dequoted_str = icalmemory_strdup_and_dequote(str);
00397            value = icalvalue_new_text(dequoted_str);
00398            free(dequoted_str);
00399            break;
00400        }
00401         
00402     case ICAL_STRING_VALUE:
00403            value = icalvalue_new_string(str);
00404            break;
00405         
00406     case ICAL_CALADDRESS_VALUE:
00407            value = icalvalue_new_caladdress(str);
00408            break;
00409         
00410     case ICAL_URI_VALUE:
00411            value = icalvalue_new_uri(str);
00412            break;
00413         
00414     case ICAL_GEO_VALUE:
00415            value = 0;
00416            /* HACK */
00417             
00418            if (error != 0){
00419               *error = icalproperty_vanew_xlicerror( 
00420                   "GEO Values are not implemented",
00421                   icalparameter_new_xlicerrortype( 
00422                      ICAL_XLICERRORTYPE_VALUEPARSEERROR), 
00423                   0); 
00424            }
00425 
00426            /*icalerror_warn("Parsing GEO properties is unimplmeneted");*/
00427 
00428            break;
00429         
00430     case ICAL_RECUR_VALUE:
00431        {
00432            struct icalrecurrencetype rt;
00433            rt = icalrecurrencetype_from_string(str);
00434             if(rt.freq != ICAL_NO_RECURRENCE){
00435                 value = icalvalue_new_recur(rt);
00436             }
00437            break;
00438        }
00439         
00440     case ICAL_DATE_VALUE:
00441     case ICAL_DATETIME_VALUE:
00442        {
00443            struct icaltimetype tt;
00444       
00445            tt = icaltime_from_string(str);
00446             if(!icaltime_is_null_time(tt)){
00447                 value = icalvalue_new_impl(kind);
00448                 value->data.v_time = tt;
00449 
00450                 icalvalue_reset_kind(value);
00451             }
00452            break;
00453        }
00454         
00455     case ICAL_DATETIMEPERIOD_VALUE:
00456        {
00457            struct icaltimetype tt;
00458             struct icalperiodtype p;
00459             tt = icaltime_from_string(str);
00460 
00461             if(!icaltime_is_null_time(tt)){
00462                 value = icalvalue_new_datetime(tt);            
00463               break;
00464             }  
00465            
00466             p = icalperiodtype_from_string(str);     
00467            if (!icalperiodtype_is_null_period(p)){
00468                 value = icalvalue_new_period(p);
00469             }            
00470 
00471             break;
00472        }
00473         
00474     case ICAL_DURATION_VALUE:
00475        {
00476             struct icaldurationtype dur = icaldurationtype_from_string(str);
00477             
00478             if (!icaldurationtype_is_bad_duration(dur)) {    /* failed to parse */
00479                 value = icalvalue_new_duration(dur);
00480             }
00481             
00482            break;
00483        }
00484         
00485     case ICAL_PERIOD_VALUE:
00486        {
00487             struct icalperiodtype p;
00488             p = icalperiodtype_from_string(str);  
00489             
00490             if(!icalperiodtype_is_null_period(p)){
00491                 value = icalvalue_new_period(p);
00492             }
00493             break; 
00494        }
00495        
00496     case ICAL_TRIGGER_VALUE:
00497        {
00498            struct icaltriggertype tr = icaltriggertype_from_string(str);
00499             if (!icaltriggertype_is_bad_trigger(tr)) {
00500                 value = icalvalue_new_trigger(tr);
00501             }
00502            break;
00503        }
00504         
00505     case ICAL_REQUESTSTATUS_VALUE:
00506         {
00507             struct icalreqstattype rst = icalreqstattype_from_string(str);
00508             if(rst.code != ICAL_UNKNOWN_STATUS){
00509                 value = icalvalue_new_requeststatus(rst);
00510             }
00511             break;
00512 
00513         }
00514 
00515     case ICAL_X_VALUE:
00516         {
00517             char* dequoted_str = icalmemory_strdup_and_dequote(str);
00518             value = icalvalue_new_x(dequoted_str);
00519             free(dequoted_str);
00520         }
00521         break;
00522 
00523     default:
00524         {
00525             if (error != 0 ){
00526               char temp[TMP_BUF_SIZE];
00527                 
00528                 snprintf(temp,TMP_BUF_SIZE,"Unknown type for \'%s\'",str);
00529                          
00530               *error = icalproperty_vanew_xlicerror( 
00531                   temp, 
00532                   icalparameter_new_xlicerrortype( 
00533                      ICAL_XLICERRORTYPE_VALUEPARSEERROR), 
00534                   0); 
00535            }
00536 
00537            icalerror_warn("icalvalue_new_from_string got an unknown value type");
00538             value=0;
00539        }
00540     }
00541 
00542 
00543     if (error != 0 && *error == 0 && value == 0){
00544        char temp[TMP_BUF_SIZE];
00545        
00546         snprintf(temp,TMP_BUF_SIZE,"Failed to parse value: \'%s\'",str);
00547        
00548        *error = icalproperty_vanew_xlicerror( 
00549            temp, 
00550            icalparameter_new_xlicerrortype( 
00551               ICAL_XLICERRORTYPE_VALUEPARSEERROR), 
00552            0); 
00553     }
00554 
00555 
00556     return value;
00557 
00558 }
00559 
00560 icalvalue* icalvalue_new_from_string(icalvalue_kind kind,const char* str)
00561 {
00562     return icalvalue_new_from_string_with_error(kind,str,(icalproperty**)0);
00563 }
00564 
00565 
00566 
00567 void
00568 icalvalue_free (icalvalue* v)
00569 {
00570     icalerror_check_arg_rv((v != 0),"value");
00571 
00572 #ifdef ICAL_FREE_ON_LIST_IS_ERROR
00573     icalerror_assert( (v->parent ==0),"This value is still attached to a property");
00574     
00575 #else
00576     if(v->parent !=0){
00577        return;
00578     }
00579 #endif
00580 
00581     if(v->x_value != 0){
00582         free(v->x_value);
00583     }
00584 
00585     switch (v->kind){
00586        case ICAL_BINARY_VALUE: 
00587        case ICAL_ATTACH_VALUE: {
00588            if (v->data.v_attach) {
00589               icalattach_unref (v->data.v_attach);
00590               v->data.v_attach = NULL;
00591            }
00592 
00593            break;
00594        }
00595        case ICAL_TEXT_VALUE:
00596        case ICAL_CALADDRESS_VALUE:
00597        case ICAL_URI_VALUE:
00598        case ICAL_QUERY_VALUE:
00599        {
00600            if (v->data.v_string != 0) { 
00601               free((void*)v->data.v_string);
00602               v->data.v_string = 0;
00603            }
00604            break;
00605        }
00606        case ICAL_RECUR_VALUE:
00607        {
00608            if(v->data.v_recur != 0){
00609               free((void*)v->data.v_recur);
00610               v->data.v_recur = 0;
00611            }
00612            break;
00613        }
00614 
00615        default:
00616        {
00617            /* Nothing to do */
00618        }
00619     }
00620 
00621     v->kind = ICAL_NO_VALUE;
00622     v->size = 0;
00623     v->parent = 0;
00624     memset(&(v->data),0,sizeof(v->data));
00625     v->id[0] = 'X';
00626     free(v);
00627 }
00628 
00629 int
00630 icalvalue_is_valid (const icalvalue* value)
00631 {
00632     if(value == 0){
00633        return 0;
00634     }
00635     
00636     return 1;
00637 }
00638 
00639 static char* icalvalue_binary_as_ical_string(const icalvalue* value) {
00640 
00641     const char* data;
00642     char* str;
00643     icalerror_check_arg_rz( (value!=0),"value");
00644 
00645     data = icalvalue_get_binary(value);
00646 
00647     str = icalmemory_tmp_copy(
00648             "icalvalue_binary_as_ical_string is not implemented yet");
00649 
00650     return str;
00651 }
00652 
00653 
00654 #define MAX_INT_DIGITS 12 /* Enough for 2^32 + sign*/ 
00655     
00656 static char* icalvalue_int_as_ical_string(const icalvalue* value) {
00657     int data;
00658     char* str = (char*)icalmemory_tmp_buffer(MAX_INT_DIGITS); 
00659 
00660     icalerror_check_arg_rz( (value!=0),"value");
00661 
00662     data = icalvalue_get_integer(value);
00663        
00664     snprintf(str,MAX_INT_DIGITS,"%d",data);
00665 
00666     return str;
00667 }
00668 
00669 static char* icalvalue_utcoffset_as_ical_string(const icalvalue* value)
00670 {    
00671     int data,h,m,s;
00672     char sign;
00673     char* str = (char*)icalmemory_tmp_buffer(9);
00674 
00675     icalerror_check_arg_rz( (value!=0),"value");
00676 
00677     data = icalvalue_get_utcoffset(value);
00678 
00679     if (abs(data) == data){
00680        sign = '+';
00681     } else {
00682        sign = '-';
00683     }
00684 
00685     h = data/3600;
00686     m = (data - (h*3600))/ 60;
00687     s = (data - (h*3600) - (m*60));
00688 
00689     if (s > 0)
00690        snprintf(str,9,"%c%02d%02d%02d",sign,abs(h),abs(m),abs(s));
00691     else
00692        snprintf(str,9,"%c%02d%02d",sign,abs(h),abs(m));
00693 
00694     return str;
00695 }
00696 
00697 static char* icalvalue_string_as_ical_string(const icalvalue* value) {
00698 
00699     const char* data;
00700     char* str = 0;
00701     icalerror_check_arg_rz( (value!=0),"value");
00702     data = value->data.v_string;
00703 
00704     str = (char*)icalmemory_tmp_buffer(strlen(data)+1);   
00705 
00706     strcpy(str,data);
00707 
00708     return str;
00709 }
00710 
00711 
00712 static char* icalvalue_recur_as_ical_string(const icalvalue* value) 
00713 {
00714     struct icalrecurrencetype *recur = value->data.v_recur;
00715 
00716     return icalrecurrencetype_as_string(recur);
00717 }
00718 
00719  /* @todo This is not RFC2445 compliant.
00720  * The RFC only allows:
00721  * TSAFE-CHAR = %x20-21 / %x23-2B / %x2D-39 / %x3C-5B / %x5D-7E / NON-US-ASCII
00722  * As such, \t\r\b\f are not allowed, not even escaped
00723  */
00724 
00725 static char* icalvalue_text_as_ical_string(const icalvalue* value) {
00726     char *str;
00727     char *str_p;
00728     char *rtrn;
00729     const char *p;
00730     size_t buf_sz;
00731 
00732     buf_sz = strlen(value->data.v_string)+1;
00733 
00734     str_p = str = (char*)icalmemory_new_buffer(buf_sz);
00735 
00736     if (str_p == 0){
00737       return 0;
00738     }
00739 
00740     for(p=value->data.v_string; *p!=0; p++){
00741 
00742        switch(*p){
00743            case '\n': {
00744               icalmemory_append_string(&str,&str_p,&buf_sz,"\\n");
00745               break;
00746            }
00747 
00748            case '\t': {
00749               icalmemory_append_string(&str,&str_p,&buf_sz,"\\t");
00750               break;
00751            }
00752            case '\r': {
00753               icalmemory_append_string(&str,&str_p,&buf_sz,"\\r");
00754               break;
00755            }
00756            case '\b': {
00757               icalmemory_append_string(&str,&str_p,&buf_sz,"\\b");
00758               break;
00759            }
00760            case '\f': {
00761               icalmemory_append_string(&str,&str_p,&buf_sz,"\\f");
00762               break;
00763            }
00764 
00765            case ';':
00766            case ',':
00767            case '"':
00768            case '\\':{
00769               icalmemory_append_char(&str,&str_p,&buf_sz,'\\');
00770               icalmemory_append_char(&str,&str_p,&buf_sz,*p);
00771               break;
00772            }
00773 
00774            default: {
00775               icalmemory_append_char(&str,&str_p,&buf_sz,*p);
00776            }
00777        }
00778     }
00779 
00780     /* Assume the last character is not a '\0' and add one. We could
00781        check *str_p != 0, but that would be an uninitialized memory
00782        read. */
00783 
00784 
00785     icalmemory_append_char(&str,&str_p,&buf_sz,'\0');
00786 
00787     rtrn = icalmemory_tmp_copy(str);
00788 
00789     icalmemory_free_buffer(str);
00790 
00791     return rtrn;
00792 }
00793 
00794 
00795 static char* 
00796 icalvalue_attach_as_ical_string(const icalvalue* value) 
00797 {
00798     icalattach *a;
00799     char * str;
00800 
00801     icalerror_check_arg_rz( (value!=0),"value");
00802 
00803     a = icalvalue_get_attach(value);
00804 
00805     if (icalattach_get_is_url (a)) {
00806        const char *url;
00807 
00808        url = icalattach_get_url (a);
00809        str = icalmemory_tmp_buffer (strlen (url) + 1);
00810        strcpy (str, url);
00811        return str;
00812     } else
00813        return icalvalue_binary_as_ical_string (value);
00814 }
00815 
00816 
00817 static char* icalvalue_duration_as_ical_string(const icalvalue* value) {
00818 
00819     struct icaldurationtype data;
00820 
00821     icalerror_check_arg_rz( (value!=0),"value");
00822     data = icalvalue_get_duration(value);
00823 
00824     return icaldurationtype_as_ical_string(data);
00825 }
00826 
00827 void print_time_to_string(char* str, const struct icaltimetype *data)
00828 {
00829     char temp[20];
00830 
00831     if (icaltime_is_utc(*data)){
00832        snprintf(temp,sizeof(temp),"%02d%02d%02dZ",data->hour,data->minute,data->second);
00833     } else {
00834        snprintf(temp,sizeof(temp),"%02d%02d%02d",data->hour,data->minute,data->second);
00835     }   
00836 
00837     strcat(str,temp);
00838 }
00839 
00840  
00841 void print_date_to_string(char* str,  const struct icaltimetype *data)
00842 {
00843     char temp[20];
00844 
00845     snprintf(temp,sizeof(temp),"%04d%02d%02d",data->year,data->month,data->day);
00846 
00847     strcat(str,temp);
00848 }
00849 
00850 static char* icalvalue_date_as_ical_string(const icalvalue* value) {
00851 
00852     struct icaltimetype data;
00853     char* str;
00854     icalerror_check_arg_rz( (value!=0),"value");
00855     data = icalvalue_get_date(value);
00856 
00857     str = (char*)icalmemory_tmp_buffer(9);
00858  
00859     str[0] = 0;
00860     print_date_to_string(str,&data);
00861    
00862     return str;
00863 }
00864 
00865 void print_datetime_to_string(char* str,  const struct icaltimetype *data)
00866 {
00867     print_date_to_string(str,data);
00868     strcat(str,"T");
00869     print_time_to_string(str,data);
00870 }
00871 
00872 static const char* icalvalue_datetime_as_ical_string(const icalvalue* value) {
00873     
00874     struct icaltimetype data;
00875     char* str;
00876     icalvalue_kind kind = icalvalue_isa(value);    
00877 
00878     icalerror_check_arg_rz( (value!=0),"value");
00879 
00880 
00881     if( !(kind == ICAL_DATE_VALUE || kind == ICAL_DATETIME_VALUE ))
00882        {
00883            icalerror_set_errno(ICAL_BADARG_ERROR);
00884            return 0;
00885        }
00886 
00887     data = icalvalue_get_datetime(value);
00888 
00889     str = (char*)icalmemory_tmp_buffer(20);
00890  
00891     str[0] = 0;
00892 
00893     print_datetime_to_string(str,&data);
00894    
00895     return str;
00896 
00897 }
00898 
00899 #define MAX_FLOAT_DIGITS 40
00900     
00901 static char* icalvalue_float_as_ical_string(const icalvalue* value) {
00902 
00903     float data;
00904     char* str;
00905     icalerror_check_arg_rz( (value!=0),"value");
00906     data = icalvalue_get_float(value);
00907 
00908     str = (char*)icalmemory_tmp_buffer(MAX_FLOAT_DIGITS);
00909 
00910     snprintf(str,MAX_FLOAT_DIGITS,"%f",data);
00911 
00912     return str;
00913 }
00914 
00915 #define MAX_GEO_DIGITS 40
00916     
00917 static char* icalvalue_geo_as_ical_string(const icalvalue* value) {
00918 
00919     struct icalgeotype data;
00920     char* str;
00921     icalerror_check_arg_rz( (value!=0),"value");
00922 
00923     data = icalvalue_get_geo(value);
00924 
00925     str = (char*)icalmemory_tmp_buffer(MAX_GEO_DIGITS);
00926 
00927     snprintf(str,MAX_GEO_DIGITS,"%f;%f",data.lat,data.lon);
00928 
00929     return str;
00930 }
00931 
00932 static const char* icalvalue_datetimeperiod_as_ical_string(const icalvalue* value) {
00933     struct icaldatetimeperiodtype dtp = icalvalue_get_datetimeperiod(value);
00934 
00935     icalerror_check_arg_rz( (value!=0),"value");
00936 
00937     if(!icaltime_is_null_time(dtp.time)){
00938        return icaltime_as_ical_string(dtp.time);
00939     } else {
00940        return icalperiodtype_as_ical_string(dtp.period);
00941     }
00942 }
00943 
00944 static const char* icalvalue_period_as_ical_string(const icalvalue* value) {
00945     struct icalperiodtype data;
00946     icalerror_check_arg_rz( (value!=0),"value");
00947     data = icalvalue_get_period(value);
00948 
00949     return icalperiodtype_as_ical_string(data);
00950 
00951 }
00952 
00953 static const char* icalvalue_trigger_as_ical_string(const icalvalue* value) {
00954 
00955     struct icaltriggertype data;
00956 
00957     icalerror_check_arg_rz( (value!=0),"value");
00958     data = icalvalue_get_trigger(value);
00959 
00960     if(!icaltime_is_null_time(data.time)){
00961        return icaltime_as_ical_string(data.time);
00962     } else {
00963        return icaldurationtype_as_ical_string(data.duration);
00964     }   
00965 
00966 }
00967 
00968 const char*
00969 icalvalue_as_ical_string(const icalvalue* value)
00970 {
00971     if(value == 0){
00972        return 0;
00973     }
00974 
00975     switch (value->kind){
00976 
00977     case ICAL_ATTACH_VALUE:
00978         return icalvalue_attach_as_ical_string(value);
00979         
00980     case ICAL_BINARY_VALUE:
00981         return icalvalue_binary_as_ical_string(value);
00982         
00983     case ICAL_BOOLEAN_VALUE:
00984     case ICAL_INTEGER_VALUE:
00985         return icalvalue_int_as_ical_string(value);                  
00986         
00987     case ICAL_UTCOFFSET_VALUE:
00988         return icalvalue_utcoffset_as_ical_string(value);                  
00989         
00990     case ICAL_TEXT_VALUE:
00991         return icalvalue_text_as_ical_string(value);
00992         
00993     case ICAL_QUERY_VALUE:
00994         return icalvalue_string_as_ical_string(value);
00995         
00996     case ICAL_STRING_VALUE:
00997     case ICAL_URI_VALUE:
00998     case ICAL_CALADDRESS_VALUE:
00999         return icalvalue_string_as_ical_string(value);
01000         
01001     case ICAL_DATE_VALUE:
01002         return icalvalue_date_as_ical_string(value);
01003     case ICAL_DATETIME_VALUE:
01004         return icalvalue_datetime_as_ical_string(value);
01005     case ICAL_DURATION_VALUE:
01006         return icalvalue_duration_as_ical_string(value);
01007         
01008     case ICAL_PERIOD_VALUE:
01009         return icalvalue_period_as_ical_string(value);
01010     case ICAL_DATETIMEPERIOD_VALUE:
01011         return icalvalue_datetimeperiod_as_ical_string(value);
01012         
01013     case ICAL_FLOAT_VALUE:
01014         return icalvalue_float_as_ical_string(value);
01015         
01016     case ICAL_GEO_VALUE:
01017         return icalvalue_geo_as_ical_string(value);
01018         
01019     case ICAL_RECUR_VALUE:
01020         return icalvalue_recur_as_ical_string(value);
01021         
01022     case ICAL_TRIGGER_VALUE:
01023         return icalvalue_trigger_as_ical_string(value);
01024 
01025     case ICAL_REQUESTSTATUS_VALUE:
01026         return icalreqstattype_as_string(value->data.v_requeststatus);
01027         
01028     case ICAL_ACTION_VALUE:
01029     case ICAL_CMD_VALUE:
01030     case ICAL_QUERYLEVEL_VALUE:
01031     case ICAL_CARLEVEL_VALUE:
01032     case ICAL_METHOD_VALUE:
01033     case ICAL_STATUS_VALUE:
01034     case ICAL_TRANSP_VALUE:
01035     case ICAL_CLASS_VALUE:
01036         if(value->x_value !=0){
01037             return icalmemory_tmp_copy(value->x_value);
01038         }
01039 
01040         return icalproperty_enum_to_string(value->data.v_enum);
01041         
01042     case ICAL_X_VALUE: 
01043        if (value->x_value != 0)
01044             return icalmemory_tmp_copy(value->x_value);
01045 
01046     /* FALLTHRU */
01047 
01048     case ICAL_NO_VALUE:
01049     default:
01050        {
01051            return 0;
01052        }
01053     }
01054 }
01055 
01056 
01057 icalvalue_kind
01058 icalvalue_isa (const icalvalue* value)
01059 {
01060     if(value == 0){
01061        return ICAL_NO_VALUE;
01062     }
01063 
01064     return value->kind;
01065 }
01066 
01067 
01068 int
01069 icalvalue_isa_value (void* value)
01070 {
01071     struct icalvalue_impl *impl = (struct icalvalue_impl *)value;
01072 
01073     icalerror_check_arg_rz( (value!=0), "value");
01074 
01075     if (strcmp(impl->id,"val") == 0) {
01076        return 1;
01077     } else {
01078        return 0;
01079     }
01080 }
01081 
01082 
01083 static int icalvalue_is_time(const icalvalue* a) {
01084     icalvalue_kind kind = icalvalue_isa(a);
01085 
01086     if(kind == ICAL_DATETIME_VALUE ||
01087        kind == ICAL_DATE_VALUE ){
01088        return 1;
01089     }
01090 
01091     return 0;
01092 
01093 }
01094 
01095 /*
01096  * In case of error, this function returns 0. This is partly bogus, as 0 is
01097  * not part of the returned enum.
01098  * FIXME We should probably add an error value to the enum.
01099  */
01100 icalparameter_xliccomparetype
01101 icalvalue_compare(const icalvalue* a, const icalvalue *b)
01102 {
01103 
01104     icalerror_check_arg_rz( (a!=0), "a");
01105     icalerror_check_arg_rz( (b!=0), "b");
01106 
01107     /* Not the same type; they can only be unequal */
01108     if( ! (icalvalue_is_time(a) && icalvalue_is_time(b)) &&
01109        icalvalue_isa(a) != icalvalue_isa(b)){
01110        return ICAL_XLICCOMPARETYPE_NOTEQUAL;
01111     }
01112 
01113     switch (icalvalue_isa(a)){
01114 
01115        case ICAL_ATTACH_VALUE:
01116        {
01117            if (icalattach_get_is_url(a->data.v_attach) &&
01118                icalattach_get_is_url(b->data.v_attach)) {
01119               if (strcasecmp(icalattach_get_url(a->data.v_attach),
01120                             icalattach_get_url(b->data.v_attach)) == 0)
01121                   return ICAL_XLICCOMPARETYPE_EQUAL;
01122               else
01123                   return ICAL_XLICCOMPARETYPE_NOTEQUAL;
01124            }
01125            else {
01126                if (a->data.v_attach == b->data.v_attach)
01127                   return ICAL_XLICCOMPARETYPE_EQUAL;
01128                else
01129                   return ICAL_XLICCOMPARETYPE_NOTEQUAL;
01130            }
01131        }
01132         case ICAL_BINARY_VALUE:
01133        {
01134            if (a->data.v_attach == b->data.v_attach)
01135               return ICAL_XLICCOMPARETYPE_EQUAL;
01136            else
01137               return ICAL_XLICCOMPARETYPE_NOTEQUAL;
01138        }
01139 
01140        case ICAL_BOOLEAN_VALUE:
01141        {
01142            if (icalvalue_get_boolean(a) == icalvalue_get_boolean(b)){
01143               return ICAL_XLICCOMPARETYPE_EQUAL;
01144            } else {
01145               return ICAL_XLICCOMPARETYPE_NOTEQUAL;
01146            }
01147        }
01148 
01149        case ICAL_FLOAT_VALUE:
01150        {
01151            if (a->data.v_float > b->data.v_float){
01152               return ICAL_XLICCOMPARETYPE_GREATER;
01153            } else if (a->data.v_float < b->data.v_float){
01154               return ICAL_XLICCOMPARETYPE_LESS;
01155            } else {
01156               return ICAL_XLICCOMPARETYPE_EQUAL;
01157            }
01158        }
01159 
01160        case ICAL_INTEGER_VALUE:
01161        case ICAL_UTCOFFSET_VALUE:
01162        {
01163            if (a->data.v_int > b->data.v_int){
01164               return ICAL_XLICCOMPARETYPE_GREATER;
01165            } else if (a->data.v_int < b->data.v_int){
01166               return ICAL_XLICCOMPARETYPE_LESS;
01167            } else {
01168               return ICAL_XLICCOMPARETYPE_EQUAL;
01169            }
01170        }
01171 
01172        case ICAL_DURATION_VALUE: 
01173        {
01174            int dur_a = icaldurationtype_as_int(a->data.v_duration);
01175            int dur_b = icaldurationtype_as_int(b->data.v_duration);
01176 
01177            if (dur_a > dur_b){
01178               return ICAL_XLICCOMPARETYPE_GREATER;
01179            } else if (dur_a < dur_b){
01180               return ICAL_XLICCOMPARETYPE_LESS;
01181            } else {
01182               return ICAL_XLICCOMPARETYPE_EQUAL;
01183            }
01184        }          
01185 
01186 
01187        case ICAL_TEXT_VALUE:
01188        case ICAL_URI_VALUE:
01189        case ICAL_CALADDRESS_VALUE:
01190        case ICAL_TRIGGER_VALUE:
01191        case ICAL_DATE_VALUE:
01192        case ICAL_DATETIME_VALUE:
01193        case ICAL_DATETIMEPERIOD_VALUE:
01194        case ICAL_QUERY_VALUE:
01195        case ICAL_RECUR_VALUE:
01196        {
01197            int r;
01198 
01199            r =  strcmp(icalvalue_as_ical_string(a),
01200                        icalvalue_as_ical_string(b));
01201 
01202            if (r > 0) {     
01203               return ICAL_XLICCOMPARETYPE_GREATER;
01204            } else if (r < 0){
01205               return ICAL_XLICCOMPARETYPE_LESS;
01206            } else {
01207               return ICAL_XLICCOMPARETYPE_EQUAL;
01208            }
01209 
01210               
01211        }
01212 
01213        case ICAL_METHOD_VALUE:
01214        {
01215            if (icalvalue_get_method(a) == icalvalue_get_method(b)){
01216               return ICAL_XLICCOMPARETYPE_EQUAL;
01217            } else {
01218               return ICAL_XLICCOMPARETYPE_NOTEQUAL;
01219            }
01220 
01221        }
01222 
01223        case ICAL_STATUS_VALUE:
01224        {
01225            if (icalvalue_get_status(a) == icalvalue_get_status(b)){
01226               return ICAL_XLICCOMPARETYPE_EQUAL;
01227            } else {
01228               return ICAL_XLICCOMPARETYPE_NOTEQUAL;
01229            }
01230 
01231        }
01232 
01233        case ICAL_TRANSP_VALUE:
01234        {
01235            if (icalvalue_get_transp(a) == icalvalue_get_transp(b)){
01236               return ICAL_XLICCOMPARETYPE_EQUAL;
01237            } else {
01238               return ICAL_XLICCOMPARETYPE_NOTEQUAL;
01239            }
01240        }
01241 
01242        case ICAL_ACTION_VALUE:
01243         {
01244            if (icalvalue_get_action(a) == icalvalue_get_action(b)){
01245               return ICAL_XLICCOMPARETYPE_EQUAL;
01246            } else {
01247               return ICAL_XLICCOMPARETYPE_NOTEQUAL;
01248            }
01249         }
01250 
01251        case ICAL_PERIOD_VALUE:
01252        case ICAL_GEO_VALUE:
01253        case ICAL_NO_VALUE:
01254        default:
01255        {
01256            icalerror_warn("Comparison not implemented for value type");
01257            return 0;
01258        }
01259     }   
01260 
01261 }
01262 
01267 void icalvalue_reset_kind(icalvalue* value)
01268 {
01269     if( (value->kind==ICAL_DATETIME_VALUE || value->kind==ICAL_DATE_VALUE )&&
01270         !icaltime_is_null_time(value->data.v_time) ) {
01271         
01272         if(icaltime_is_date(value->data.v_time)){
01273             value->kind = ICAL_DATE_VALUE;
01274         } else {
01275             value->kind = ICAL_DATETIME_VALUE;
01276         }
01277     }
01278        
01279 }
01280 
01281 void icalvalue_set_parent(icalvalue* value,
01282                           icalproperty* property)
01283 {
01284     value->parent = property;
01285 }
01286 
01287 icalproperty* icalvalue_get_parent(icalvalue* value)
01288 {
01289     return value->parent;
01290 }
01291 
01292 
01293 int icalvalue_encode_ical_string(const char *szText, char *szEncText, int nMaxBufferLen)
01294 {
01295     char   *ptr;
01296     icalvalue *value = 0;
01297 
01298     if ((szText == 0) || (szEncText == 0))
01299         return 0;
01300    
01301     value = icalvalue_new_from_string(ICAL_STRING_VALUE, szText);
01302     
01303     if (value == 0)
01304         return 0;
01305     
01306     ptr = icalvalue_text_as_ical_string(value);
01307     if (ptr == 0)
01308         return 0;
01309     
01310     if ((int)strlen(ptr) >= nMaxBufferLen)
01311         {
01312             icalvalue_free (value);
01313             return 0;
01314         }
01315 
01316     strcpy(szEncText, ptr);
01317 
01318     icalvalue_free ((icalvalue*)value);
01319 
01320     return 1;
01321 }
01322 
01323 /* The remaining interfaces are 'new', 'set' and 'get' for each of the value
01324    types */