2 /* ======================================================================
3 File: icalrestriction.c
5 (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
6 ======================================================================*/
7 /*#line 7 "icalrestriction.c.in"*/
13 #include "icalrestriction.h"
14 #include "icalenums.h"
15 #include "icalerror.h"
18 #include <stdio.h> /* For snprintf */
20 #define TMP_BUF_SIZE 1024
23 /* Define the structs for the restrictions. these data are filled out
24 in machine generated code below */
26 struct icalrestriction_property_record;
28 typedef char* (*restriction_func)(struct icalrestriction_property_record* rec,icalcomponent* comp,icalproperty* prop);
31 typedef struct icalrestriction_property_record {
32 icalproperty_method method;
33 icalcomponent_kind component;
34 icalproperty_kind property;
35 icalrestriction_kind restriction;
36 restriction_func function;
37 } icalrestriction_property_record;
40 typedef struct icalrestriction_component_record {
41 icalproperty_method method;
42 icalcomponent_kind component;
43 icalcomponent_kind subcomponent;
44 icalrestriction_kind restriction;
45 restriction_func function;
46 } icalrestriction_component_record;
48 icalrestriction_property_record*
49 icalrestriction_get_property_restriction(icalproperty_method method,
50 icalcomponent_kind component,
51 icalproperty_kind property);
52 icalrestriction_component_record*
53 icalrestriction_get_component_restriction(icalproperty_method method,
54 icalcomponent_kind component,
55 icalcomponent_kind subcomponent);
57 icalrestriction_component_record icalrestriction_component_records[];
58 icalrestriction_property_record icalrestriction_property_records[];
60 icalrestriction_property_record null_prop_record = {ICAL_METHOD_NONE,ICAL_NO_COMPONENT,ICAL_NO_PROPERTY,ICAL_RESTRICTION_UNKNOWN,0};
61 icalrestriction_component_record null_comp_record = {ICAL_METHOD_NONE,ICAL_NO_COMPONENT,ICAL_NO_COMPONENT,ICAL_RESTRICTION_UNKNOWN,0};
64 /* The each row gives the result of comparing a restriction against a
65 count. The columns in each row represent 0,1,2+. '-1' indicates
66 'invalid, 'don't care' or 'needs more analysis' So, for
67 ICAL_RESTRICTION_ONE, if there is 1 of a property with that
68 restriction, it passes, but if there are 0 or 2+, it fails. */
70 char compare_map[ICAL_RESTRICTION_UNKNOWN+1][3] = {
71 { 1, 1, 1},/*ICAL_RESTRICTION_NONE*/
72 { 1, 0, 0},/*ICAL_RESTRICTION_ZERO*/
73 { 0, 1, 0},/*ICAL_RESTRICTION_ONE*/
74 { 1, 1, 1},/*ICAL_RESTRICTION_ZEROPLUS*/
75 { 0, 1, 1},/*ICAL_RESTRICTION_ONEPLUS*/
76 { 1, 1, 0},/*ICAL_RESTRICTION_ZEROORONE*/
77 { 1, 1, 0},/*ICAL_RESTRICTION_ONEEXCLUSIVE*/
78 { 1, 1, 0},/*ICAL_RESTRICTION_ONEMUTUAL*/
79 { 1, 1, 1} /*ICAL_RESTRICTION_UNKNOWN*/
82 char restr_string_map[ICAL_RESTRICTION_UNKNOWN+1][60] = {
83 "unknown number",/*ICAL_RESTRICTION_NONE*/
84 "0",/*ICAL_RESTRICTION_ZERO*/
85 "1",/*ICAL_RESTRICTION_ONE*/
86 "zero or more",/*ICAL_RESTRICTION_ZEROPLUS*/
87 "one or more" ,/*ICAL_RESTRICTION_ONEPLUS*/
88 "zero or one",/*ICAL_RESTRICTION_ZEROORONE*/
89 "zero or one, exclusive with another property",/*ICAL_RESTRICTION_ONEEXCLUSIVE*/
90 "zero or one, mutual with another property",/*ICAL_RESTRICTION_ONEMUTUAL*/
91 "unknown number" /*ICAL_RESTRICTION_UNKNOWN*/
96 icalrestriction_compare(icalrestriction_kind restr, int count){
98 if ( restr < ICAL_RESTRICTION_NONE || restr > ICAL_RESTRICTION_UNKNOWN
107 return compare_map[restr][count];
111 /* Special case routines */
113 char* icalrestriction_may_be_draft_final_canceled(
114 icalrestriction_property_record *rec,
119 icalproperty_status stat = icalproperty_get_status(prop);
121 if( !( stat == ICAL_STATUS_DRAFT ||
122 stat == ICAL_STATUS_FINAL ||
123 stat == ICAL_STATUS_CANCELLED )){
125 return "Failed iTIP restrictions for STATUS property. Value must be one of DRAFT, FINAL, or CANCELED";
132 char* icalrestriction_may_be_comp_need_process(
133 icalrestriction_property_record *rec,
137 icalproperty_status stat = icalproperty_get_status(prop);
139 if( !( stat == ICAL_STATUS_COMPLETED ||
140 stat == ICAL_STATUS_NEEDSACTION ||
141 stat == ICAL_STATUS_INPROCESS )){
143 return "Failed iTIP restrictions for STATUS property. Value must be one of COMPLETED, NEEDS-ACTION or IN-PROCESS";
149 char* icalrestriction_may_be_tent_conf(icalrestriction_property_record *rec,
152 icalproperty_status stat = icalproperty_get_status(prop);
154 if( !( stat == ICAL_STATUS_TENTATIVE ||
155 stat == ICAL_STATUS_CONFIRMED )){
157 return "Failed iTIP restrictions for STATUS property. Value must be one of TENTATIVE or CONFIRMED";
163 char* icalrestriction_may_be_tent_conf_cancel(
164 icalrestriction_property_record *rec,
168 icalproperty_status stat = icalproperty_get_status(prop);
170 if( !( stat == ICAL_STATUS_TENTATIVE ||
171 stat == ICAL_STATUS_CONFIRMED ||
172 stat == ICAL_STATUS_CANCELLED )){
174 return "Failed iTIP restrictions for STATUS property. Value must be one of TENTATIVE, CONFIRMED or CANCELED";
181 char* icalrestriction_must_be_cancel_if_present(
182 icalrestriction_property_record *rec,
186 /* This routine will not be called if prop == 0 */
187 icalproperty_status stat = icalproperty_get_status(prop);
189 if( stat != ICAL_STATUS_CANCELLED)
191 return "Failed iTIP restrictions for STATUS property. Value must be CANCELLED";
199 char* icalrestriction_must_be_canceled_no_attendee(
200 icalrestriction_property_record *rec,
205 /* Hack. see rfc2446, 3.2.5 CANCEL for porperty STATUS. I don't
206 understand the note */
210 char* icalrestriction_must_be_recurring(icalrestriction_property_record *rec,
216 char* icalrestriction_must_have_duration(icalrestriction_property_record *rec,
220 if( !icalcomponent_get_first_property(comp,ICAL_DURATION_PROPERTY)){
222 return "Failed iTIP restrictions for STATUS property. This component must have a DURATION property";
228 char* icalrestriction_must_have_repeat(icalrestriction_property_record *rec,
231 if( !icalcomponent_get_first_property(comp,ICAL_REPEAT_PROPERTY)){
233 return "Failed iTIP restrictions for STATUS property. This component must have a REPEAT property";
239 char* icalrestriction_must_if_tz_ref(icalrestriction_property_record *rec,
246 char* icalrestriction_no_dtend(icalrestriction_property_record *rec,
250 if( !icalcomponent_get_first_property(comp,ICAL_DTEND_PROPERTY)){
252 return "Failed iTIP restrictions for STATUS property. The component must not have both DURATION and DTEND";
258 char* icalrestriction_no_duration(icalrestriction_property_record *rec,
262 /* _no_dtend takes care of this one */
267 int icalrestriction_check_component(icalproperty_method method,
270 icalproperty_kind kind;
271 icalcomponent_kind comp_kind;
272 icalrestriction_kind restr;
273 icalrestriction_property_record *prop_record;
281 comp_kind = icalcomponent_isa(comp);
283 /* Check all of the properties in this component */
285 for(kind = ICAL_ANY_PROPERTY+1; kind != ICAL_NO_PROPERTY; kind++){
286 count = icalcomponent_count_properties(comp, kind);
288 prop_record = icalrestriction_get_property_restriction(method,
292 restr = prop_record->restriction;
294 if(restr == ICAL_RESTRICTION_ONEEXCLUSIVE ||
295 restr == ICAL_RESTRICTION_ONEMUTUAL) {
297 /* First treat is as a 0/1 restriction */
298 restr = ICAL_RESTRICTION_ZEROORONE;
299 compare = icalrestriction_compare(restr,count);
303 compare = icalrestriction_compare(restr,count);
306 assert(compare != -1);
309 char temp[TMP_BUF_SIZE];
311 snprintf(temp, TMP_BUF_SIZE,"Failed iTIP restrictions for %s property. Expected %s instances of the property and got %d",
312 icalenum_property_kind_to_string(kind),
313 restr_string_map[restr], count);
315 icalcomponent_add_property
317 icalproperty_vanew_xlicerror(
319 icalparameter_new_xlicerrortype(ICAL_XLICERRORTYPE_INVALIDITIP),
324 prop = icalcomponent_get_first_property(comp, kind);
326 if (prop != 0 && prop_record->function !=0 ){
327 funcr = prop_record->function(prop_record,comp,prop);
331 icalcomponent_add_property
333 icalproperty_vanew_xlicerror(
335 icalparameter_new_xlicerrortype(
336 ICAL_XLICERRORTYPE_INVALIDITIP),
342 valid = valid && compare;
352 int icalrestriction_check(icalcomponent* outer_comp)
354 icalcomponent_kind comp_kind;
355 icalproperty_method method;
356 icalcomponent* inner_comp;
357 icalproperty *method_prop;
360 icalerror_check_arg_rz( (outer_comp!=0), "outer comp");
363 /* Get the Method value from the outer component */
365 comp_kind = icalcomponent_isa(outer_comp);
367 if (comp_kind != ICAL_VCALENDAR_COMPONENT){
368 icalerror_set_errno(ICAL_BADARG_ERROR);
372 method_prop = icalcomponent_get_first_property(outer_comp,
373 ICAL_METHOD_PROPERTY);
375 if (method_prop == 0){
376 method = ICAL_METHOD_NONE;
378 method = icalproperty_get_method(method_prop);
382 /* Check the VCALENDAR wrapper */
383 valid = icalrestriction_check_component(ICAL_METHOD_NONE,outer_comp);
386 /* Now check the inner components */
388 for(inner_comp= icalcomponent_get_first_component(outer_comp,
391 inner_comp= icalcomponent_get_next_component(outer_comp,
392 ICAL_ANY_COMPONENT)){
394 valid = valid && icalrestriction_check_component(method,inner_comp);
403 icalrestriction_property_record*
404 icalrestriction_get_property_restriction(icalproperty_method method,
405 icalcomponent_kind component,
406 icalproperty_kind property)
411 icalrestriction_property_records[i].restriction != ICAL_RESTRICTION_NONE;
414 if (method == icalrestriction_property_records[i].method &&
415 component == icalrestriction_property_records[i].component &&
416 property == icalrestriction_property_records[i].property ){
417 return &icalrestriction_property_records[i];
421 return &null_prop_record;
425 icalrestriction_component_record*
426 icalrestriction_get_component_restriction(icalproperty_method method,
427 icalcomponent_kind component,
428 icalcomponent_kind subcomponent)
434 icalrestriction_component_records[i].restriction != ICAL_RESTRICTION_NONE;
437 if (method == icalrestriction_component_records[i].method &&
438 component == icalrestriction_component_records[i].component &&
439 subcomponent == icalrestriction_component_records[i].subcomponent ){
440 return &icalrestriction_component_records[i];
444 return &null_comp_record;