bump to 1.0.0 and clean up spec file
[platform/upstream/libical.git] / src / libical / icalrestriction.c.in
1 /*  -*- Mode: C -*- */
2 /*  ======================================================================
3   File: icalrestriction.c
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of either:
7
8     The LGPL as published by the Free Software Foundation, version
9     2.1, available at: http://www.fsf.org/copyleft/lesser.html
10
11   Or:
12
13     The Mozilla Public License Version 1.0. You may obtain a copy of
14     the License at http://www.mozilla.org/MPL/
15
16  (C) COPYRIGHT 2000, Eric Busboom, http://www.softwarestudio.org
17  ======================================================================*/
18 /*#line 7 "icalrestriction.c.in"*/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include "icalrestriction.h"
25 #include "icalenums.h"
26 #include "icalerror.h"
27
28 #include <assert.h>
29 #include <stdio.h>
30
31 #if defined(_MSC_VER)
32 #define snprintf _snprintf
33 #endif
34
35 #define TMP_BUF_SIZE 1024
36
37 /* Define the structs for the restrictions. these data are filled out
38 in machine generated code below */
39
40 struct icalrestriction_property_record;
41
42 typedef const char* (*restriction_func)(const struct icalrestriction_property_record* rec,icalcomponent* comp,icalproperty* prop);
43
44
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;
52
53
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;
61
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);
70
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};
73
74
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. */
80
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*/
91 };
92
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*/
103 };
104
105
106 int
107 icalrestriction_compare(icalrestriction_kind restr, int count){
108
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
111          || count < 0){
112         return -1;
113     }
114
115     if (count > 2) {
116         count = 2;
117     }
118
119     return compare_map[restr][count];
120
121 }
122
123 /* Special case routines */
124
125 const char* icalrestriction_may_be_draft_final_canceled(
126     const icalrestriction_property_record *rec,
127     icalcomponent* comp,
128     icalproperty* prop)
129 {
130     icalproperty_status stat = icalproperty_get_status(prop);
131     (void)rec;
132     (void)comp;
133
134     if( !( stat == ICAL_STATUS_DRAFT ||
135            stat == ICAL_STATUS_FINAL ||
136            stat == ICAL_STATUS_CANCELLED )){
137
138         return "Failed iTIP restrictions for STATUS property. Value must be one of DRAFT, FINAL, or CANCELED";
139
140     }
141
142     return 0;    
143 }
144
145 const char* icalrestriction_may_be_comp_need_process(
146     const icalrestriction_property_record *rec,
147     icalcomponent* comp,
148     icalproperty* prop)
149 {
150     icalproperty_status stat = icalproperty_get_status(prop);
151     (void)rec;
152     (void)comp;
153
154     if( !( stat == ICAL_STATUS_COMPLETED ||
155            stat == ICAL_STATUS_NEEDSACTION ||
156            stat == ICAL_STATUS_INPROCESS )){
157
158         return "Failed iTIP restrictions for STATUS property. Value must be one of COMPLETED, NEEDS-ACTION or IN-PROCESS";
159
160     }
161
162     return 0;    
163 }
164 const char* icalrestriction_may_be_tent_conf(const icalrestriction_property_record *rec,
165                                        icalcomponent* comp,
166                                        icalproperty* prop)
167 {
168     icalproperty_status stat = icalproperty_get_status(prop);
169
170     (void)rec;
171     (void)comp;
172
173     if( !( stat == ICAL_STATUS_TENTATIVE ||
174            stat == ICAL_STATUS_CONFIRMED )){
175
176         return "Failed iTIP restrictions for STATUS property. Value must be one of TENTATIVE or CONFIRMED";
177
178     }
179
180     return 0;    
181 }
182 const char* icalrestriction_may_be_tent_conf_cancel(
183     const icalrestriction_property_record *rec,
184     icalcomponent* comp,
185     icalproperty* prop)
186 {
187     icalproperty_status stat = icalproperty_get_status(prop);
188
189     (void)rec;
190     (void)comp;
191
192     if( !( stat == ICAL_STATUS_TENTATIVE ||
193            stat == ICAL_STATUS_CONFIRMED ||
194            stat == ICAL_STATUS_CANCELLED )){
195
196         return "Failed iTIP restrictions for STATUS property. Value must be one of TENTATIVE, CONFIRMED or CANCELED";
197
198     }
199
200     return 0;    
201 }
202
203 const char* icalrestriction_must_be_cancel_if_present(
204     const icalrestriction_property_record *rec,
205     icalcomponent* comp,
206     icalproperty* prop)
207 {
208     /* This routine will not be called if prop == 0 */
209     icalproperty_status stat = icalproperty_get_status(prop);
210     (void)rec;
211     (void)comp;
212
213     if( stat != ICAL_STATUS_CANCELLED)
214     {
215         return "Failed iTIP restrictions for STATUS property. Value must be CANCELLED";
216
217     }
218  
219
220     return 0;    
221 }
222
223 const char* icalrestriction_must_be_canceled_no_attendee(
224     const icalrestriction_property_record *rec,
225     icalcomponent* comp,
226     icalproperty* prop)
227 {
228     (void)rec;
229     (void)comp;
230     (void)prop;
231
232     /* Hack. see rfc2446, 3.2.5 CANCEL for porperty STATUS. I don't
233        understand the note */
234
235     return 0;    
236 }
237
238 const char* icalrestriction_must_be_recurring(
239                 const icalrestriction_property_record *rec,
240                 icalcomponent* comp, 
241                 icalproperty* prop){
242     /* Hack */
243     (void)rec;
244     (void)comp;
245     (void)prop;
246     return 0;    
247 }
248
249 const char* icalrestriction_must_have_duration(
250         const icalrestriction_property_record *rec,
251         icalcomponent* comp, 
252         icalproperty* prop)
253 {    
254     if( !icalcomponent_get_first_property(comp,ICAL_DURATION_PROPERTY)){
255
256         return "Failed iTIP restrictions for DURATION property. This component must have a DURATION property";
257
258     }
259
260     return 0;    
261 }
262
263 const char* icalrestriction_must_have_repeat(
264                 const icalrestriction_property_record *rec,
265                 icalcomponent* comp,
266                 icalproperty* prop)
267 {
268     (void)rec;
269     (void)prop;
270     if( !icalcomponent_get_first_property(comp,ICAL_REPEAT_PROPERTY)){
271
272         return "Failed iTIP restrictions for REPEAT property. This component must have a REPEAT property";
273
274     }
275
276     return 0;    
277 }
278
279 const char* icalrestriction_must_if_tz_ref(
280                 const icalrestriction_property_record *rec,
281                 icalcomponent* comp,
282                 icalproperty* prop){
283
284     /* Hack */
285     (void)rec;
286     (void)comp;
287     (void)prop;
288     return 0;    
289 }
290
291 const char* icalrestriction_no_dtend(
292                 const icalrestriction_property_record *rec,
293                 icalcomponent* comp,
294                 icalproperty* prop)
295 {
296
297     (void)rec;
298     (void)prop;
299     if(icalcomponent_get_first_property(comp,ICAL_DTEND_PROPERTY)){
300
301         return "Failed iTIP restrictions for DTEND property. The component must not have both DURATION and DTEND";
302
303     }
304
305     return 0;    
306 }
307
308 const char* icalrestriction_no_duration(
309                 const icalrestriction_property_record *rec,
310                 icalcomponent* comp,
311                 icalproperty* prop)
312 {
313     (void)rec;
314     (void)comp;
315     (void)prop;
316
317     /* _no_dtend takes care of this one */
318     return 0;    
319 }
320
321 const char* icalrestriction_must_be_email(
322     const icalrestriction_property_record *rec,
323     icalcomponent* comp,
324     icalproperty* prop)
325 {
326     icalproperty_action stat = icalproperty_get_action(prop);
327
328     (void)rec;
329     (void)comp;
330
331     if( !( stat == ICAL_ACTION_EMAIL)){
332
333         return "Failed iTIP restrictions for ACTION property. Value must be EMAIL.";
334
335     }
336
337     return 0;    
338 }
339
340 int icalrestriction_check_component(icalproperty_method method,
341                                     icalcomponent* comp)
342 {
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;
348     icalproperty *prop;
349
350     int count;
351     int compare;
352     int valid = 1;
353
354     comp_kind = icalcomponent_isa(comp);
355
356     /* Check all of the properties in this component */
357
358     for(kind = ICAL_ANY_PROPERTY+1; kind != ICAL_NO_PROPERTY; kind++){
359         count = icalcomponent_count_properties(comp, kind);
360         
361         prop_record = icalrestriction_get_property_restriction(method, 
362                                                          comp_kind,
363                                                          kind);
364
365         restr = prop_record->restriction;
366
367         if(restr == ICAL_RESTRICTION_ONEEXCLUSIVE ||
368             restr == ICAL_RESTRICTION_ONEMUTUAL) {
369
370             /* First treat is as a 0/1 restriction */
371             restr = ICAL_RESTRICTION_ZEROORONE;
372             compare = icalrestriction_compare(restr,count);
373
374         } else {
375
376             compare = icalrestriction_compare(restr,count);
377         }
378
379         assert(compare != -1);
380
381         if (compare == 0){
382             char temp[TMP_BUF_SIZE];
383             
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);
387             
388             icalcomponent_add_property
389                 (comp,
390                  icalproperty_vanew_xlicerror(
391                      temp,
392                      icalparameter_new_xlicerrortype(ICAL_XLICERRORTYPE_INVALIDITIP),
393                      0));   
394         } 
395
396
397         prop = icalcomponent_get_first_property(comp, kind);
398
399         if (prop != 0 && prop_record->function !=0  ){
400             funcr =  prop_record->function(prop_record,comp,prop);
401         }
402
403         if(funcr !=0){
404             icalcomponent_add_property
405                 (comp,
406                  icalproperty_vanew_xlicerror(
407                      funcr,
408                      icalparameter_new_xlicerrortype(
409                          ICAL_XLICERRORTYPE_INVALIDITIP),
410                      0));   
411
412             compare = 0;
413         }
414
415         valid = valid && compare;
416     }
417
418
419
420     return valid;
421
422
423 }
424
425 int icalrestriction_check(icalcomponent* outer_comp)
426 {
427     icalcomponent_kind comp_kind;
428     icalproperty_method method;
429     icalcomponent* inner_comp;
430     icalproperty *method_prop;
431     int valid;
432     
433     icalerror_check_arg_rz( (outer_comp!=0), "outer comp");
434
435
436     /* Get the Method value from the outer component */
437
438     comp_kind = icalcomponent_isa(outer_comp);
439
440     if (comp_kind != ICAL_VCALENDAR_COMPONENT){
441         icalerror_set_errno(ICAL_BADARG_ERROR);
442         return 0;
443     }
444
445     method_prop = icalcomponent_get_first_property(outer_comp,
446                                                    ICAL_METHOD_PROPERTY);
447
448     if (method_prop == 0){
449         method = ICAL_METHOD_NONE;
450     } else {
451         method = icalproperty_get_method(method_prop);
452     }
453    
454
455     /* Check the VCALENDAR wrapper */
456     valid = icalrestriction_check_component(ICAL_METHOD_NONE,outer_comp);
457
458
459     /* Now check the inner components */
460
461     for(inner_comp= icalcomponent_get_first_component(outer_comp,
462                                                       ICAL_ANY_COMPONENT);
463         inner_comp != 0;
464         inner_comp= icalcomponent_get_next_component(outer_comp,
465                                                      ICAL_ANY_COMPONENT)){
466
467         valid = valid && icalrestriction_check_component(method,inner_comp);
468
469     }
470
471
472     return valid;
473
474 }
475
476 <insert_code_here>
477
478 static const icalrestriction_property_record*
479 icalrestriction_get_property_restriction(icalproperty_method method,
480                                          icalcomponent_kind component,
481                                          icalproperty_kind property)
482 {
483     int i;
484
485     for(i = 0;
486         icalrestriction_property_records[i].restriction != ICAL_RESTRICTION_NONE;
487         i++){
488
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];
493         }
494     }
495         
496     return &null_prop_record;
497 }
498
499
500 static const icalrestriction_component_record*
501 icalrestriction_get_component_restriction(icalproperty_method method,
502                                           icalcomponent_kind component,
503                                           icalcomponent_kind subcomponent)
504 {
505
506     int i;
507
508     for(i = 0;
509         icalrestriction_component_records[i].restriction != ICAL_RESTRICTION_NONE;
510         i++){
511
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];
516         }
517     }
518         
519     return &null_comp_record;
520 }