2 /* ======================================================================
3 File: icalrestriction.c
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of either:
8 The LGPL as published by the Free Software Foundation, version
9 2.1, available at: http://www.fsf.org/copyleft/lesser.html
13 The Mozilla Public License Version 1.0. You may obtain a copy of
14 the License at http://www.mozilla.org/MPL/
16 (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
17 ======================================================================*/
18 /*#line 7 "icalrestriction.c.in"*/
24 #include "icalrestriction.h"
25 #include "icalenums.h"
26 #include "icalerror.h"
32 #define snprintf _snprintf
35 #define TMP_BUF_SIZE 1024
37 /* Define the structs for the restrictions. these data are filled out
38 in machine generated code below */
40 struct icalrestriction_property_record;
42 typedef const char* (*restriction_func)(const struct icalrestriction_property_record* rec,icalcomponent* comp,icalproperty* prop);
45 typedef struct icalrestriction_property_record {
46 icalproperty_method method;
47 icalcomponent_kind component;
48 icalproperty_kind property;
49 icalrestriction_kind restriction;
50 restriction_func function;
51 } icalrestriction_property_record;
54 typedef struct icalrestriction_component_record {
55 icalproperty_method method;
56 icalcomponent_kind component;
57 icalcomponent_kind subcomponent;
58 icalrestriction_kind restriction;
59 restriction_func function;
60 } icalrestriction_component_record;
62 static const icalrestriction_property_record*
63 icalrestriction_get_property_restriction(icalproperty_method method,
64 icalcomponent_kind component,
65 icalproperty_kind property);
66 static const icalrestriction_component_record*
67 icalrestriction_get_component_restriction(icalproperty_method method,
68 icalcomponent_kind component,
69 icalcomponent_kind subcomponent);
71 icalrestriction_property_record null_prop_record = {ICAL_METHOD_NONE,ICAL_NO_COMPONENT,ICAL_NO_PROPERTY,ICAL_RESTRICTION_UNKNOWN,0};
72 icalrestriction_component_record null_comp_record = {ICAL_METHOD_NONE,ICAL_NO_COMPONENT,ICAL_NO_COMPONENT,ICAL_RESTRICTION_UNKNOWN,0};
75 /** Each row gives the result of comparing a restriction against a count.
76 The columns in each row represent 0,1,2+. '-1' indicates
77 'invalid, 'don't care' or 'needs more analysis' So, for
78 ICAL_RESTRICTION_ONE, if there is 1 of a property with that
79 restriction, it passes, but if there are 0 or 2+, it fails. */
81 char compare_map[ICAL_RESTRICTION_UNKNOWN+1][3] = {
82 { 1, 1, 1},/*ICAL_RESTRICTION_NONE*/
83 { 1, 0, 0},/*ICAL_RESTRICTION_ZERO*/
84 { 0, 1, 0},/*ICAL_RESTRICTION_ONE*/
85 { 1, 1, 1},/*ICAL_RESTRICTION_ZEROPLUS*/
86 { 0, 1, 1},/*ICAL_RESTRICTION_ONEPLUS*/
87 { 1, 1, 0},/*ICAL_RESTRICTION_ZEROORONE*/
88 { 1, 1, 0},/*ICAL_RESTRICTION_ONEEXCLUSIVE*/
89 { 1, 1, 0},/*ICAL_RESTRICTION_ONEMUTUAL*/
90 { 1, 1, 1} /*ICAL_RESTRICTION_UNKNOWN*/
93 const char restr_string_map[ICAL_RESTRICTION_UNKNOWN+1][60] = {
94 "unknown number",/*ICAL_RESTRICTION_NONE*/
95 "0",/*ICAL_RESTRICTION_ZERO*/
96 "1",/*ICAL_RESTRICTION_ONE*/
97 "zero or more",/*ICAL_RESTRICTION_ZEROPLUS*/
98 "one or more" ,/*ICAL_RESTRICTION_ONEPLUS*/
99 "zero or one",/*ICAL_RESTRICTION_ZEROORONE*/
100 "zero or one, exclusive with another property",/*ICAL_RESTRICTION_ONEEXCLUSIVE*/
101 "zero or one, mutual with another property",/*ICAL_RESTRICTION_ONEMUTUAL*/
102 "unknown number" /*ICAL_RESTRICTION_UNKNOWN*/
107 icalrestriction_compare(icalrestriction_kind restr, int count){
109 /* restr is an unsigned int, ICAL_RESTRICTION_NONE == 0, so the check will always return false */
110 if ( /*restr < ICAL_RESTRICTION_NONE ||*/ restr > ICAL_RESTRICTION_UNKNOWN
119 return compare_map[restr][count];
123 /* Special case routines */
125 const char* icalrestriction_may_be_draft_final_canceled(
126 const icalrestriction_property_record *rec,
130 icalproperty_status stat = icalproperty_get_status(prop);
134 if( !( stat == ICAL_STATUS_DRAFT ||
135 stat == ICAL_STATUS_FINAL ||
136 stat == ICAL_STATUS_CANCELLED )){
138 return "Failed iTIP restrictions for STATUS property. Value must be one of DRAFT, FINAL, or CANCELED";
145 const char* icalrestriction_may_be_comp_need_process(
146 const icalrestriction_property_record *rec,
150 icalproperty_status stat = icalproperty_get_status(prop);
154 if( !( stat == ICAL_STATUS_COMPLETED ||
155 stat == ICAL_STATUS_NEEDSACTION ||
156 stat == ICAL_STATUS_INPROCESS )){
158 return "Failed iTIP restrictions for STATUS property. Value must be one of COMPLETED, NEEDS-ACTION or IN-PROCESS";
164 const char* icalrestriction_may_be_tent_conf(const icalrestriction_property_record *rec,
168 icalproperty_status stat = icalproperty_get_status(prop);
173 if( !( stat == ICAL_STATUS_TENTATIVE ||
174 stat == ICAL_STATUS_CONFIRMED )){
176 return "Failed iTIP restrictions for STATUS property. Value must be one of TENTATIVE or CONFIRMED";
182 const char* icalrestriction_may_be_tent_conf_cancel(
183 const icalrestriction_property_record *rec,
187 icalproperty_status stat = icalproperty_get_status(prop);
192 if( !( stat == ICAL_STATUS_TENTATIVE ||
193 stat == ICAL_STATUS_CONFIRMED ||
194 stat == ICAL_STATUS_CANCELLED )){
196 return "Failed iTIP restrictions for STATUS property. Value must be one of TENTATIVE, CONFIRMED or CANCELED";
203 const char* icalrestriction_must_be_cancel_if_present(
204 const icalrestriction_property_record *rec,
208 /* This routine will not be called if prop == 0 */
209 icalproperty_status stat = icalproperty_get_status(prop);
213 if( stat != ICAL_STATUS_CANCELLED)
215 return "Failed iTIP restrictions for STATUS property. Value must be CANCELLED";
223 const char* icalrestriction_must_be_canceled_no_attendee(
224 const icalrestriction_property_record *rec,
232 /* Hack. see rfc2446, 3.2.5 CANCEL for porperty STATUS. I don't
233 understand the note */
238 const char* icalrestriction_must_be_recurring(
239 const icalrestriction_property_record *rec,
249 const char* icalrestriction_must_have_duration(
250 const icalrestriction_property_record *rec,
254 if( !icalcomponent_get_first_property(comp,ICAL_DURATION_PROPERTY)){
256 return "Failed iTIP restrictions for DURATION property. This component must have a DURATION property";
263 const char* icalrestriction_must_have_repeat(
264 const icalrestriction_property_record *rec,
270 if( !icalcomponent_get_first_property(comp,ICAL_REPEAT_PROPERTY)){
272 return "Failed iTIP restrictions for REPEAT property. This component must have a REPEAT property";
279 const char* icalrestriction_must_if_tz_ref(
280 const icalrestriction_property_record *rec,
291 const char* icalrestriction_no_dtend(
292 const icalrestriction_property_record *rec,
299 if(icalcomponent_get_first_property(comp,ICAL_DTEND_PROPERTY)){
301 return "Failed iTIP restrictions for DTEND property. The component must not have both DURATION and DTEND";
308 const char* icalrestriction_no_duration(
309 const icalrestriction_property_record *rec,
317 /* _no_dtend takes care of this one */
321 const char* icalrestriction_must_be_email(
322 const icalrestriction_property_record *rec,
326 icalproperty_action stat = icalproperty_get_action(prop);
331 if( !( stat == ICAL_ACTION_EMAIL)){
333 return "Failed iTIP restrictions for ACTION property. Value must be EMAIL.";
340 int icalrestriction_check_component(icalproperty_method method,
343 icalproperty_kind kind;
344 icalcomponent_kind comp_kind;
345 icalrestriction_kind restr;
346 const icalrestriction_property_record *prop_record;
347 const char* funcr = 0;
354 comp_kind = icalcomponent_isa(comp);
356 /* Check all of the properties in this component */
358 for(kind = ICAL_ANY_PROPERTY+1; kind != ICAL_NO_PROPERTY; kind++){
359 count = icalcomponent_count_properties(comp, kind);
361 prop_record = icalrestriction_get_property_restriction(method,
365 restr = prop_record->restriction;
367 if(restr == ICAL_RESTRICTION_ONEEXCLUSIVE ||
368 restr == ICAL_RESTRICTION_ONEMUTUAL) {
370 /* First treat is as a 0/1 restriction */
371 restr = ICAL_RESTRICTION_ZEROORONE;
372 compare = icalrestriction_compare(restr,count);
376 compare = icalrestriction_compare(restr,count);
379 assert(compare != -1);
382 char temp[TMP_BUF_SIZE];
384 snprintf(temp, TMP_BUF_SIZE,"Failed iTIP restrictions for %s property. Expected %s instances of the property and got %d",
385 icalenum_property_kind_to_string(kind),
386 restr_string_map[restr], count);
388 icalcomponent_add_property
390 icalproperty_vanew_xlicerror(
392 icalparameter_new_xlicerrortype(ICAL_XLICERRORTYPE_INVALIDITIP),
397 prop = icalcomponent_get_first_property(comp, kind);
399 if (prop != 0 && prop_record->function !=0 ){
400 funcr = prop_record->function(prop_record,comp,prop);
404 icalcomponent_add_property
406 icalproperty_vanew_xlicerror(
408 icalparameter_new_xlicerrortype(
409 ICAL_XLICERRORTYPE_INVALIDITIP),
415 valid = valid && compare;
425 int icalrestriction_check(icalcomponent* outer_comp)
427 icalcomponent_kind comp_kind;
428 icalproperty_method method;
429 icalcomponent* inner_comp;
430 icalproperty *method_prop;
433 icalerror_check_arg_rz( (outer_comp!=0), "outer comp");
436 /* Get the Method value from the outer component */
438 comp_kind = icalcomponent_isa(outer_comp);
440 if (comp_kind != ICAL_VCALENDAR_COMPONENT){
441 icalerror_set_errno(ICAL_BADARG_ERROR);
445 method_prop = icalcomponent_get_first_property(outer_comp,
446 ICAL_METHOD_PROPERTY);
448 if (method_prop == 0){
449 method = ICAL_METHOD_NONE;
451 method = icalproperty_get_method(method_prop);
455 /* Check the VCALENDAR wrapper */
456 valid = icalrestriction_check_component(ICAL_METHOD_NONE,outer_comp);
459 /* Now check the inner components */
461 for(inner_comp= icalcomponent_get_first_component(outer_comp,
464 inner_comp= icalcomponent_get_next_component(outer_comp,
465 ICAL_ANY_COMPONENT)){
467 valid = valid && icalrestriction_check_component(method,inner_comp);
478 static const icalrestriction_property_record*
479 icalrestriction_get_property_restriction(icalproperty_method method,
480 icalcomponent_kind component,
481 icalproperty_kind property)
486 icalrestriction_property_records[i].restriction != ICAL_RESTRICTION_NONE;
489 if (method == icalrestriction_property_records[i].method &&
490 component == icalrestriction_property_records[i].component &&
491 property == icalrestriction_property_records[i].property ){
492 return &icalrestriction_property_records[i];
496 return &null_prop_record;
500 static const icalrestriction_component_record*
501 icalrestriction_get_component_restriction(icalproperty_method method,
502 icalcomponent_kind component,
503 icalcomponent_kind subcomponent)
509 icalrestriction_component_records[i].restriction != ICAL_RESTRICTION_NONE;
512 if (method == icalrestriction_component_records[i].method &&
513 component == icalrestriction_component_records[i].component &&
514 subcomponent == icalrestriction_component_records[i].subcomponent ){
515 return &icalrestriction_component_records[i];
519 return &null_comp_record;