Back to index

lightning-sunbird  0.9+nobinonly
icalproperty.c
Go to the documentation of this file.
00001 /* -*- Mode: C -*- */
00002 
00003 /*======================================================================
00004   FILE: icalproperty.c
00005   CREATOR: eric 28 April 1999
00006   
00007   $Id: icalproperty.c,v 1.39 2004/10/27 11:57:26 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 icalproperty.c
00024 
00025 ======================================================================*/
00026 
00027 #ifdef HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030 
00031 #include "icalproperty.h"
00032 #include "icalparameter.h"
00033 #include "icalcomponent.h"
00034 #include "pvl.h"
00035 #include "icalenums.h"
00036 #include "icalerror.h"
00037 #include "icalmemory.h"
00038 #include "icalparser.h"
00039 
00040 #include <string.h> /* For icalmemory_strdup, rindex */
00041 #include <assert.h>
00042 #include <stdlib.h>
00043 #include <errno.h>
00044 #include <stdio.h> /* for printf */
00045 #include <stdarg.h> /* for va_list, va_start, etc. */
00046                                                
00047 #ifdef WIN32
00048 #define snprintf      _snprintf
00049 #define strcasecmp    stricmp
00050 #endif
00051 
00052 /* Private routines for icalproperty */
00053 void icalvalue_set_parent(icalvalue* value,
00054                           icalproperty* property);
00055 icalproperty* icalvalue_get_parent(icalvalue* value);
00056 
00057 void icalparameter_set_parent(icalparameter* param,
00058                           icalproperty* property);
00059 icalproperty* icalparameter_get_parent(icalparameter* value);
00060 
00061 
00062 void icalproperty_set_x_name(icalproperty* prop, const char* name);
00063 
00064 struct icalproperty_impl 
00065 {
00066        char id[5];
00067        icalproperty_kind kind;
00068        char* x_name;
00069        pvl_list parameters;
00070        pvl_elem parameter_iterator;
00071        icalvalue* value;
00072        icalcomponent *parent;
00073 };
00074 
00075 void icalproperty_add_parameters(icalproperty* prop, va_list args)
00076 {
00077     void* vp;
00078 
00079     while((vp = va_arg(args, void*)) != 0) {
00080 
00081        if (icalvalue_isa_value(vp) != 0 ){
00082        } else if (icalparameter_isa_parameter(vp) != 0 ){
00083 
00084            icalproperty_add_parameter((icalproperty*)prop,
00085                                    (icalparameter*)vp);
00086        } else {
00087            icalerror_set_errno(ICAL_BADARG_ERROR);
00088        }
00089 
00090     }
00091 }
00092 
00093 
00094 icalproperty*
00095 icalproperty_new_impl(icalproperty_kind kind)
00096 {
00097     icalproperty* prop;
00098 
00099     if (!icalproperty_kind_is_valid(kind))
00100       return NULL;
00101 
00102     if ( ( prop = (icalproperty*) malloc(sizeof(icalproperty))) == 0) {
00103        icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00104        return 0;
00105     }
00106     
00107     strcpy(prop->id,"prop");
00108 
00109     prop->kind = kind;
00110     prop->parameters = pvl_newlist();
00111     prop->parameter_iterator = 0;
00112     prop->value = 0;
00113     prop->x_name = 0;
00114     prop->parent = 0;
00115 
00116     return prop;
00117 }
00118 
00119 
00120 icalproperty*
00121 icalproperty_new (icalproperty_kind kind)
00122 {
00123     if (kind == ICAL_NO_PROPERTY){
00124         return 0;
00125     }
00126 
00127     return (icalproperty*)icalproperty_new_impl(kind);
00128 }
00129 
00130 
00131 icalproperty *
00132 icalproperty_new_x_name(const char *name, const char *value) {
00133 
00134        icalproperty   *ret;
00135 
00136        if (name == NULL || value == NULL)
00137               return NULL;
00138 
00139        ret = icalproperty_new_x(value);
00140        if (ret == NULL)
00141               return NULL;
00142 
00143        icalproperty_set_x_name(ret, name);
00144 
00145        return ret;   
00146 }
00147 
00148 icalproperty*
00149 icalproperty_new_clone(icalproperty* old)
00150 {
00151     icalproperty *new = icalproperty_new_impl(old->kind);
00152     pvl_elem p;
00153 
00154     icalerror_check_arg_rz((old!=0),"old");
00155     icalerror_check_arg_rz((new!=0),"new");
00156 
00157     if (old->value !=0) {
00158        new->value = icalvalue_new_clone(old->value);
00159     }
00160 
00161     if (old->x_name != 0) {
00162 
00163        new->x_name = icalmemory_strdup(old->x_name);
00164        
00165        if (new->x_name == 0) {
00166            icalproperty_free(new);
00167            icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00168            return 0;
00169        }
00170     }
00171 
00172     for(p=pvl_head(old->parameters);p != 0; p = pvl_next(p)){
00173        icalparameter *param = icalparameter_new_clone(pvl_data(p));
00174        
00175        if (param == 0){
00176            icalproperty_free(new);
00177            icalerror_set_errno(ICAL_NEWFAILED_ERROR);
00178            return 0;
00179        }
00180 
00181        pvl_push(new->parameters,param);
00182     
00183     } 
00184 
00185     return new;
00186 
00187 }
00188 
00189 icalproperty* icalproperty_new_from_string(const char* str)
00190 {
00191 
00192     size_t buf_size = 1024;
00193     char* buf = icalmemory_new_buffer(buf_size);
00194     char* buf_ptr = buf;  
00195     icalproperty *prop;
00196     icalcomponent *comp;
00197     int errors  = 0;
00198 
00199 #ifdef ICAL_UNIX_NEWLINE
00200     char newline[] = "\n";
00201 #else
00202     char newline[] = "\r\n";
00203 #endif
00204 
00205     icalerror_check_arg_rz( (str!=0),"str");
00206 
00207     /* Is this a HACK or a crafty reuse of code? */
00208 
00209     icalmemory_append_string(&buf, &buf_ptr, &buf_size, "BEGIN:VCALENDAR");
00210     icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
00211     icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
00212     icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
00213     icalmemory_append_string(&buf, &buf_ptr, &buf_size, "END:VCALENDAR");
00214     icalmemory_append_string(&buf, &buf_ptr, &buf_size, newline);
00215 
00216     comp = icalparser_parse_string(buf);
00217 
00218     if(comp == 0){
00219         icalerror_set_errno(ICAL_PARSE_ERROR);
00220         return 0;
00221     }
00222 
00223     errors = icalcomponent_count_errors(comp);
00224 
00225     prop = icalcomponent_get_first_property(comp,ICAL_ANY_PROPERTY);
00226 
00227     icalcomponent_remove_property(comp,prop);
00228 
00229     icalcomponent_free(comp);
00230     free(buf);
00231 
00232     if(errors > 0){
00233         icalproperty_free(prop);
00234         return 0;
00235     } else {
00236         return prop;
00237     }
00238     
00239 }
00240 
00241 void
00242 icalproperty_free (icalproperty* p)
00243 {
00244     icalparameter* param;
00245     
00246     icalerror_check_arg_rv((p!=0),"prop");
00247 
00248 #ifdef ICAL_FREE_ON_LIST_IS_ERROR
00249     icalerror_assert( (p->parent ==0),"Tried to free a property that is still attached to a component. ");
00250     
00251 #else
00252     if(p->parent !=0){
00253        return;
00254     }
00255 #endif
00256 
00257     if (p->value != 0){
00258         icalvalue_set_parent(p->value,0);
00259        icalvalue_free(p->value);
00260     }
00261     
00262     while( (param = pvl_pop(p->parameters)) != 0){
00263        icalparameter_free(param);
00264     }
00265     
00266     pvl_free(p->parameters);
00267     
00268     if (p->x_name != 0) {
00269        free(p->x_name);
00270     }
00271     
00272     p->kind = ICAL_NO_PROPERTY;
00273     p->parameters = 0;
00274     p->parameter_iterator = 0;
00275     p->value = 0;
00276     p->x_name = 0;
00277     p->id[0] = 'X';
00278     
00279     free(p);
00280 
00281 }
00282 
00283 
00284 /* This returns where the start of the next line should be. chars_left does
00285    not include the trailing '\0'. */
00286 #define MAX_LINE_LEN 75
00287 /*#define MAX_LINE_LEN 120*/
00288 
00289 static char*
00290 get_next_line_start (char *line_start, int chars_left)
00291 {
00292     char *pos;
00293 
00294     /* If we have 74 chars or less left, we can output all of them. 
00295        we return a pointer to the '\0' at the end of the string. */
00296     if (chars_left < MAX_LINE_LEN) {
00297         return line_start + chars_left;
00298     } 
00299 
00300     /* Now we jump to the last possible character of the line, and step back
00301        trying to find a ';' ':' or ' '. If we find one, we return the character
00302        after it. */
00303     pos = line_start + MAX_LINE_LEN - 2;
00304     while (pos > line_start) {
00305         if (*pos == ';' || *pos == ':' || *pos == ' ') {
00306            return pos + 1;
00307        }
00308        pos--;
00309     }
00310     /* Now try to split on a UTF-8 boundary defined as a 7-bit
00311        value or as a byte with the two high-most bits set:
00312        11xxxxxx.  See http://czyborra.com/utf/ */
00313 
00314     pos = line_start + MAX_LINE_LEN - 1;
00315     while (pos > line_start) {
00316         /* plain ascii */
00317         if ((*pos & 128) == 0)
00318             return pos;
00319 
00320         /* utf8 escape byte */
00321         if ((*pos & 192) == 192)
00322             return pos;
00323 
00324         pos--;
00325     }
00326 
00327     /* Give up, just break at 74 chars (the 75th char is the space at
00328        the start of the line).  */
00329 
00330     return line_start + MAX_LINE_LEN - 1;
00331 }
00332 
00333 
00341 static char*
00342 fold_property_line (char *text)
00343 {
00344     size_t buf_size;
00345     char *buf, *buf_ptr, *line_start, *next_line_start, *out_buf;
00346     int len, chars_left, first_line;
00347     char ch;
00348 
00349 #ifdef ICAL_UNIX_NEWLINE
00350     char newline[] = "\n";
00351 #else
00352     char newline[] = "\r\n";
00353 #endif
00354 
00355     /* Start with a buffer twice the size of our property line, so we almost
00356        certainly won't overflow it. */
00357     len = strlen (text);
00358     buf_size = len * 2;
00359     buf = icalmemory_new_buffer (buf_size);
00360     buf_ptr = buf;
00361 
00362     /* Step through the text, finding each line to add to the output. */
00363     line_start = text;
00364     chars_left = len;
00365     first_line = 1;
00366     for (;;) {
00367         if (chars_left <= 0)
00368            break;
00369 
00370         /* This returns the first character for the next line. */
00371         next_line_start = get_next_line_start (line_start, chars_left);
00372 
00373        /* If this isn't the first line, we need to output a newline and space
00374           first. */
00375        if (!first_line) {
00376            icalmemory_append_string (&buf, &buf_ptr, &buf_size, newline);
00377            icalmemory_append_string (&buf, &buf_ptr, &buf_size, " ");
00378        }
00379        first_line = 0;
00380 
00381        /* This adds the line to our tmp buffer. We temporarily place a '\0'
00382           in text, so we can copy the line in one go. */
00383        ch = *next_line_start;
00384        *next_line_start = '\0';
00385        icalmemory_append_string (&buf, &buf_ptr, &buf_size, line_start);
00386        *next_line_start = ch;
00387 
00388        /* Now we move on to the next line. */
00389        chars_left -= (next_line_start - line_start);
00390        line_start = next_line_start;
00391     }
00392 
00393     icalmemory_append_string (&buf, &buf_ptr, &buf_size, newline);
00394 
00395     /* Copy it to a temporary buffer, and then free it. */
00396     out_buf = icalmemory_tmp_buffer (strlen (buf) + 1);
00397     strcpy (out_buf, buf);
00398     icalmemory_free_buffer (buf);
00399 
00400     return out_buf;
00401 }
00402 
00403 
00404 /* Determine what VALUE parameter to include. The VALUE parameters
00405    are ignored in the normal parameter printing ( the block after
00406    this one, so we need to do it here */
00407 static const char *
00408 icalproperty_get_value_kind(icalproperty *prop)
00409 {
00410        const char* kind_string = 0;
00411 
00412        icalparameter *orig_val_param
00413            = icalproperty_get_first_parameter(prop,ICAL_VALUE_PARAMETER);
00414 
00415        icalvalue *value = icalproperty_get_value(prop);
00416 
00417        icalvalue_kind orig_kind = ICAL_NO_VALUE;
00418 
00419        icalvalue_kind this_kind = ICAL_NO_VALUE;
00420 
00421        icalvalue_kind default_kind 
00422            =  icalproperty_kind_to_value_kind(prop->kind);
00423 
00424        if(orig_val_param){
00425            orig_kind = (icalvalue_kind)icalparameter_get_value(orig_val_param);
00426        }
00427 
00428        if(value != 0){
00429            this_kind = icalvalue_isa(value);
00430        }
00431        
00432        
00433        if(this_kind == default_kind &&
00434           orig_kind != ICAL_NO_VALUE){
00435            /* The kind is the default, so it does not need to be
00436                included, but do it anyway, since it was explicit in
00437                the property. But, use the default, not the one
00438                specified in the property */
00439            
00440            kind_string = icalvalue_kind_to_string(default_kind);
00441 
00442        } else if (this_kind != default_kind && this_kind !=  ICAL_NO_VALUE){
00443            /* Not the default, so it must be specified */
00444            kind_string = icalvalue_kind_to_string(this_kind);
00445        } else {
00446            /* Don'tinclude the VALUE parameter at all */
00447        }
00448 
00449        return kind_string;
00450 }
00451 
00452 const char*
00453 icalproperty_as_ical_string (icalproperty* prop)
00454 {   
00455     icalparameter *param;
00456 
00457     /* Create new buffer that we can append names, parameters and a
00458        value to, and reallocate as needed. Later, this buffer will be
00459        copied to a icalmemory_tmp_buffer, which is managed internally
00460        by libical, so it can be given to the caller without fear of
00461        the caller forgetting to free it */
00462 
00463     const char* property_name = 0; 
00464     size_t buf_size = 1024;
00465     char* buf = icalmemory_new_buffer(buf_size);
00466     char* buf_ptr = buf;
00467     icalvalue* value;
00468     char *out_buf;
00469     const char* kind_string = 0;
00470 
00471 #ifdef ICAL_UNIX_NEWLINE
00472     char newline[] = "\n";
00473 #else
00474     char newline[] = "\r\n";
00475 #endif
00476 
00477 
00478     
00479     icalerror_check_arg_rz( (prop!=0),"prop");
00480 
00481 
00482     /* Append property name */
00483 
00484     if (prop->kind == ICAL_X_PROPERTY && prop->x_name != 0){
00485        property_name = prop->x_name;
00486     } else {
00487        property_name = icalproperty_kind_to_string(prop->kind);
00488     }
00489 
00490     if (property_name == 0 ) {
00491        icalerror_warn("Got a property of an unknown kind.");
00492        icalmemory_free_buffer(buf);
00493        return 0;
00494        
00495     }
00496 
00497     icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
00498 
00499     kind_string = icalproperty_get_value_kind(prop);
00500     if(kind_string!=0){
00501        icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";VALUE=");
00502        icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
00503     }
00504 
00505     /* Append parameters */
00506     for(param = icalproperty_get_first_parameter(prop,ICAL_ANY_PARAMETER);
00507        param != 0; 
00508        param = icalproperty_get_next_parameter(prop,ICAL_ANY_PARAMETER)) {
00509 
00510        icalparameter_kind kind = icalparameter_isa(param);
00511        kind_string = icalparameter_as_ical_string(param); 
00512 
00513        if(kind==ICAL_VALUE_PARAMETER){
00514            continue;
00515        }
00516 
00517        if (kind_string == 0 ) {
00518          icalerror_warn("Got a parameter of unknown kind for the following property");
00519 
00520          icalerror_warn((property_name) ? property_name : "(NULL)");
00521            continue;
00522        }
00523 
00524        icalmemory_append_string(&buf, &buf_ptr, &buf_size, ";");
00525        icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
00526     }    
00527 
00528     /* Append value */
00529 
00530     icalmemory_append_string(&buf, &buf_ptr, &buf_size, ":");
00531 
00532     value = icalproperty_get_value(prop);
00533 
00534     if (value != 0){
00535        const char *str = icalvalue_as_ical_string(value);
00536        icalerror_assert((str !=0),"Could not get string representation of a value");
00537        icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
00538     } else {
00539        icalmemory_append_string(&buf, &buf_ptr, &buf_size,"ERROR: No Value"); 
00540        
00541     }
00542     
00543     /* Now, copy the buffer to a tmp_buffer, which is safe to give to
00544        the caller without worring about de-allocating it. */
00545 
00546     /* We now use a function to fold the line properly every 75 characters.
00547        That function also adds the newline for us. */
00548     out_buf = fold_property_line (buf);
00549 
00550     icalmemory_free_buffer(buf);
00551 
00552     return out_buf;
00553 }
00554 
00555 
00556 
00557 icalproperty_kind
00558 icalproperty_isa (icalproperty* p)
00559 {
00560    if(p != 0){
00561        return p->kind;
00562    }
00563 
00564    return ICAL_NO_PROPERTY;
00565 }
00566 
00567 int
00568 icalproperty_isa_property (void* property)
00569 {
00570     icalproperty *impl = (icalproperty *) property;
00571 
00572     icalerror_check_arg_rz( (property!=0), "property");
00573     if (strcmp(impl->id,"prop") == 0) {
00574        return 1;
00575     } else {
00576        return 0;
00577     }
00578 }
00579 
00580 
00581 void
00582 icalproperty_add_parameter (icalproperty* p,icalparameter* parameter)
00583 {
00584    icalerror_check_arg_rv( (p!=0),"prop");
00585    icalerror_check_arg_rv( (parameter!=0),"parameter");
00586     
00587    pvl_push(p->parameters, parameter);
00588 
00589 }
00590 
00591 void
00592 icalproperty_set_parameter (icalproperty* prop,icalparameter* parameter)
00593 {
00594     icalparameter_kind kind;
00595     
00596     icalerror_check_arg_rv( (prop!=0),"prop");
00597     icalerror_check_arg_rv( (parameter!=0),"parameter");
00598 
00599     kind = icalparameter_isa(parameter);
00600     if (kind != ICAL_X_PARAMETER)
00601       icalproperty_remove_parameter_by_kind(prop,kind);
00602     else
00603       icalproperty_remove_parameter_by_name(prop, 
00604                                        icalparameter_get_xname(parameter));
00605 
00606     icalproperty_add_parameter(prop,parameter);
00607 }
00608 
00609 void icalproperty_set_parameter_from_string(icalproperty* prop,
00610                                             const char* name, const char* value)
00611 {
00612 
00613     icalparameter_kind kind;
00614     icalparameter *param;
00615 
00616     icalerror_check_arg_rv( (prop!=0),"prop");
00617     icalerror_check_arg_rv( (name!=0),"name");
00618     icalerror_check_arg_rv( (value!=0),"value");
00619     
00620     kind = icalparameter_string_to_kind(name);
00621 
00622     if(kind == ICAL_NO_PARAMETER){
00623         icalerror_set_errno(ICAL_BADARG_ERROR);
00624         return;
00625     }
00626     
00627     param  = icalparameter_new_from_value_string(kind,value);
00628 
00629     if (param == 0){
00630         icalerror_set_errno(ICAL_BADARG_ERROR);
00631         return;
00632     }
00633 
00634     if(kind == ICAL_X_PARAMETER){
00635        icalparameter_set_xname(param, name);
00636     }
00637 
00638     icalproperty_set_parameter(prop,param);
00639 
00640 }
00641 
00642 const char* icalproperty_get_parameter_as_string(icalproperty* prop,
00643                                                  const char* name)
00644 {
00645     icalparameter_kind kind;
00646     icalparameter *param;
00647     char* str;
00648     char* pv;
00649     char* pvql;
00650     char* pvqr;
00651 
00652     icalerror_check_arg_rz( (prop!=0),"prop");
00653     icalerror_check_arg_rz( (name!=0),"name");
00654     
00655     kind = icalparameter_string_to_kind(name);
00656 
00657     if(kind == ICAL_NO_PARAMETER){
00658         /* icalenum_string_to_parameter_kind will set icalerrno */
00659         return 0;
00660     }
00661     
00662     for(param = icalproperty_get_first_parameter(prop,kind); 
00663            param != 0; 
00664            param = icalproperty_get_next_parameter(prop,kind)) {
00665            if (kind != ICAL_X_PARAMETER) {
00666                   break;
00667            }
00668 
00669            if (strcmp(icalparameter_get_xname(param),name)==0) {
00670                   break;
00671            }         
00672     }
00673 
00674     if (param == 0){
00675         return 0;
00676     }
00677 
00678 
00679     str = icalparameter_as_ical_string(param);
00680 
00681     pv = strchr(str,'=');
00682 
00683     if(pv == 0){
00684         icalerror_set_errno(ICAL_INTERNAL_ERROR);
00685         return 0;
00686     }
00687 
00688     // see if this string is quoted, immediately return if not
00689     // otherwise removed the quotes from the string.
00690     ++pv;
00691     pvql = strchr(pv,'"');
00692     if(pvql == 0)
00693         return pv;
00694     pvqr = strrchr(pvql,'"');
00695     if(pvqr == 0){
00696         icalerror_set_errno(ICAL_INTERNAL_ERROR);
00697         return 0;
00698     }
00699     *pvqr = '\0';
00700     return pvql+1;
00701 }
00702 
00709 void
00710 icalproperty_remove_parameter(icalproperty* prop, icalparameter_kind kind)
00711 {
00712   icalproperty_remove_parameter_by_kind(prop, kind);
00713 }
00714 
00715 
00726 void
00727 icalproperty_remove_parameter_by_kind(icalproperty* prop, icalparameter_kind kind)
00728 {
00729     pvl_elem p;     
00730 
00731     icalerror_check_arg_rv((prop!=0),"prop");
00732     
00733     for(p=pvl_head(prop->parameters);p != 0; p = pvl_next(p)){
00734        icalparameter* param = (icalparameter *)pvl_data (p);
00735         if (icalparameter_isa(param) == kind) {
00736             pvl_remove (prop->parameters, p);
00737            icalparameter_free(param);
00738             break;
00739         }
00740     }                       
00741 }
00742 
00743 
00759 void
00760 icalproperty_remove_parameter_by_name(icalproperty* prop, const char *name)
00761 {
00762     pvl_elem p;     
00763 
00764     icalerror_check_arg_rv((prop!=0),"prop");
00765     
00766     for(p=pvl_head(prop->parameters);p != 0; p = pvl_next(p)){
00767        icalparameter* param = (icalparameter *)pvl_data (p);
00768        const char * kind_string;
00769 
00770        if (icalparameter_isa(param) == ICAL_X_PARAMETER)
00771          kind_string = icalparameter_get_xname(param);
00772        else
00773          kind_string = icalparameter_kind_to_string(icalparameter_isa(param));
00774 
00775        if (!kind_string)
00776          continue;
00777 
00778         if (0 == strcmp(kind_string, name)) {
00779             pvl_remove (prop->parameters, p);
00780             icalparameter_free(param);
00781             break;
00782         }
00783     }                       
00784 }
00785 
00786 
00796 void
00797 icalproperty_remove_parameter_by_ref(icalproperty* prop, icalparameter* parameter)
00798 {
00799     pvl_elem p;
00800     icalparameter_kind kind;
00801     const char *name;
00802 
00803     icalerror_check_arg_rv((prop!=0),"prop");
00804     icalerror_check_arg_rv((parameter!=0),"parameter");
00805 
00806     kind = icalparameter_isa(parameter);
00807     name = icalparameter_get_xname(parameter);
00808 
00809     /*
00810      * FIXME If it's an X- parameter, also compare the names. It would be nice
00811      * to have a better abstraction like icalparameter_equals()
00812      */
00813     for(p=pvl_head(prop->parameters);p != 0; p = pvl_next(p)){
00814        icalparameter* p_param = (icalparameter *)pvl_data (p);
00815        if (icalparameter_isa(p_param) == kind &&
00816            (kind != ICAL_X_PARAMETER ||
00817            !strcmp(icalparameter_get_xname(p_param), name))) {
00818             pvl_remove (prop->parameters, p);
00819             icalparameter_free(p_param);
00820             break;
00821        } 
00822     }   
00823 }
00824 
00825 
00826 int
00827 icalproperty_count_parameters (const icalproperty* prop)
00828 {
00829     if(prop != 0){
00830        return pvl_count(prop->parameters);
00831     }
00832 
00833     icalerror_set_errno(ICAL_USAGE_ERROR);
00834     return -1;
00835 }
00836 
00837 
00838 icalparameter*
00839 icalproperty_get_first_parameter(icalproperty* p, icalparameter_kind kind)
00840 {
00841    icalerror_check_arg_rz( (p!=0),"prop");
00842    
00843    p->parameter_iterator = pvl_head(p->parameters);
00844 
00845    if (p->parameter_iterator == 0) {
00846        return 0;
00847    }
00848 
00849    for( p->parameter_iterator = pvl_head(p->parameters);
00850        p->parameter_iterator !=0;
00851        p->parameter_iterator = pvl_next(p->parameter_iterator)){
00852 
00853        icalparameter *param = (icalparameter*)pvl_data(p->parameter_iterator);
00854 
00855        if(icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER){
00856           return param;
00857        }
00858    }
00859 
00860    return 0;
00861 }
00862 
00863 
00864 icalparameter*
00865 icalproperty_get_next_parameter (icalproperty* p, icalparameter_kind kind)
00866 {
00867     icalerror_check_arg_rz( (p!=0),"prop");
00868     
00869     if (p->parameter_iterator == 0) {
00870        return 0;
00871     }
00872     
00873     for( p->parameter_iterator = pvl_next(p->parameter_iterator);
00874         p->parameter_iterator !=0;
00875         p->parameter_iterator = pvl_next(p->parameter_iterator)){
00876        
00877        icalparameter *param = (icalparameter*)pvl_data(p->parameter_iterator);
00878        
00879        if(icalparameter_isa(param) == kind || kind == ICAL_ANY_PARAMETER){
00880            return param;
00881        }
00882     }
00883     
00884     return 0;
00885 
00886 }
00887 
00888 icalparameter*
00889 icalproperty_get_first_x_parameter(icalproperty* p, const char *name)
00890 {
00891    icalerror_check_arg_rz( (p!=0),"prop");
00892    
00893    p->parameter_iterator = pvl_head(p->parameters);
00894 
00895    if (p->parameter_iterator == 0) {
00896        return 0;
00897    }
00898 
00899    for( p->parameter_iterator = pvl_head(p->parameters);
00900        p->parameter_iterator !=0;
00901        p->parameter_iterator = pvl_next(p->parameter_iterator)){
00902 
00903        icalparameter *param = (icalparameter*)pvl_data(p->parameter_iterator);
00904 
00905        if(icalparameter_isa(param) == ICAL_X_PARAMETER &&
00906          !strcmp(icalparameter_get_xname(param), name)){
00907           return param;
00908        }
00909    }
00910 
00911    return 0;
00912 }
00913 
00914 
00915 icalparameter*
00916 icalproperty_get_next_x_parameter (icalproperty* p, const char *name)
00917 {
00918     icalerror_check_arg_rz( (p!=0),"prop");
00919     
00920     if (p->parameter_iterator == 0) {
00921        return 0;
00922     }
00923     
00924     for( p->parameter_iterator = pvl_next(p->parameter_iterator);
00925         p->parameter_iterator !=0;
00926         p->parameter_iterator = pvl_next(p->parameter_iterator)){
00927        
00928        icalparameter *param = (icalparameter*)pvl_data(p->parameter_iterator);
00929        
00930        if(icalparameter_isa(param) == ICAL_X_PARAMETER &&
00931          !strcmp(icalparameter_get_xname(param), name)){
00932            return param;
00933        }
00934     }
00935     
00936     return 0;
00937 
00938 }
00939 
00940 void
00941 icalproperty_set_value (icalproperty* p, icalvalue* value)
00942 {
00943     icalerror_check_arg_rv((p !=0),"prop");
00944     icalerror_check_arg_rv((value !=0),"value");
00945     
00946     if (p->value != 0){
00947        icalvalue_set_parent(p->value,0);
00948        icalvalue_free(p->value);
00949        p->value = 0;
00950     }
00951 
00952     p->value = value;
00953     
00954     icalvalue_set_parent(value,p);
00955 }
00956 
00957 
00958 void icalproperty_set_value_from_string(icalproperty* prop,const char* str,
00959                                         const char* type)
00960 {
00961     icalvalue *oval,*nval;
00962     icalvalue_kind kind = ICAL_NO_VALUE;
00963 
00964     icalerror_check_arg_rv( (prop!=0),"prop"); 
00965     icalerror_check_arg_rv( (str!=0),"str");
00966     icalerror_check_arg_rv( (type!=0),"type");
00967    
00968     if(strcmp(type,"NO")==0){
00969         /* Get the type from the value the property already has, if it exists */
00970         oval = icalproperty_get_value(prop);
00971         if(oval != 0){
00972             /* Use the existing value kind */
00973             kind  = icalvalue_isa(oval);
00974         } else {   
00975             /* Use the default kind for the property */
00976             kind = icalproperty_kind_to_value_kind(icalproperty_isa(prop));
00977         }
00978     } else {
00979         /* Use the given kind string */
00980         kind = icalvalue_string_to_kind(type);
00981     }
00982 
00983     if(kind == ICAL_NO_VALUE){
00984         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
00985         return;
00986     }
00987 
00988     nval = icalvalue_new_from_string(kind, str);
00989 
00990     if(nval == 0){
00991         /* icalvalue_new_from_string sets errno */
00992         assert(icalerrno != ICAL_NO_ERROR);
00993         return;
00994     }
00995 
00996     icalproperty_set_value(prop,nval);
00997 
00998 
00999 }
01000 
01001 icalvalue*
01002 icalproperty_get_value(const icalproperty* prop)
01003 {
01004     icalerror_check_arg_rz( (prop!=0),"prop");
01005     
01006     return prop->value;
01007 }
01008 
01009 const char* icalproperty_get_value_as_string(const icalproperty* prop)
01010 {
01011     icalvalue *value;
01012     
01013     icalerror_check_arg_rz( (prop!=0),"prop");
01014 
01015     value = prop->value; 
01016 
01017     return icalvalue_as_ical_string(value);
01018 }
01019 
01020 
01021 void icalproperty_set_x_name(icalproperty* prop, const char* name)
01022 {
01023     icalerror_check_arg_rv( (name!=0),"name");
01024     icalerror_check_arg_rv( (prop!=0),"prop");
01025 
01026     if (prop->x_name != 0) {
01027         free(prop->x_name);
01028     }
01029 
01030     prop->x_name = icalmemory_strdup(name);
01031 
01032     if(prop->x_name == 0){
01033        icalerror_set_errno(ICAL_NEWFAILED_ERROR);
01034     }
01035 
01036 }
01037                               
01038 const char* icalproperty_get_x_name(icalproperty* prop){
01039     icalerror_check_arg_rz( (prop!=0),"prop");
01040 
01041     return prop->x_name;
01042 }
01043 
01044 
01045 const char* icalproperty_get_property_name(const icalproperty* prop)
01046 {
01047 
01048     const char* property_name = 0;
01049     size_t buf_size = 256;
01050     char* buf = icalmemory_new_buffer(buf_size);
01051     char* buf_ptr = buf;  
01052 
01053     icalerror_check_arg_rz( (prop!=0),"prop");
01054  
01055     if (prop->kind == ICAL_X_PROPERTY && prop->x_name != 0){
01056         property_name = prop->x_name;
01057     } else {
01058         property_name = icalproperty_kind_to_string(prop->kind);
01059     }
01060  
01061     if (property_name == 0 ) {
01062         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
01063         return 0;
01064 
01065     } else {
01066         /* _append_string will automatically grow the buffer if
01067            property_name is longer than the initial buffer size */
01068         icalmemory_append_string(&buf, &buf_ptr, &buf_size, property_name);
01069     }
01070  
01071     /* Add the buffer to the temporary buffer ring -- the caller will
01072        not have to free the memory. */
01073     icalmemory_add_tmp_buffer(buf);
01074  
01075     return buf;
01076 }
01077                             
01078 
01079 
01080 
01081 void icalproperty_set_parent(icalproperty* property,
01082                           icalcomponent* component)
01083 {
01084     icalerror_check_arg_rv( (property!=0),"property");
01085     
01086     property->parent = component;
01087 }
01088 
01089 icalcomponent* icalproperty_get_parent(const icalproperty* property)
01090 {
01091     icalerror_check_arg_rz( (property!=0),"property");
01092 
01093     return property->parent;
01094 }