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> /* For snprintf */ 30 31#ifdef WIN32 32#if defined(_MSC_VER) && (_MSC_VER < 1900) 33#define snprintf _snprintf 34#endif 35#endif 36 37 38#define TMP_BUF_SIZE 1024 39 40/* Define the structs for the restrictions. these data are filled out 41in machine generated code below */ 42 43struct icalrestriction_property_record; 44 45typedef const char* (*restriction_func)(const struct icalrestriction_property_record* rec,icalcomponent* comp,icalproperty* prop); 46 47 48typedef struct icalrestriction_property_record { 49 icalproperty_method method; 50 icalcomponent_kind component; 51 icalproperty_kind property; 52 icalrestriction_kind restriction; 53 restriction_func function; 54} icalrestriction_property_record; 55 56 57typedef struct icalrestriction_component_record { 58 icalproperty_method method; 59 icalcomponent_kind component; 60 icalcomponent_kind subcomponent; 61 icalrestriction_kind restriction; 62 restriction_func function; 63} icalrestriction_component_record; 64 65static const icalrestriction_property_record* 66icalrestriction_get_property_restriction(icalproperty_method method, 67 icalcomponent_kind component, 68 icalproperty_kind property); 69static const icalrestriction_component_record* 70icalrestriction_get_component_restriction(icalproperty_method method, 71 icalcomponent_kind component, 72 icalcomponent_kind subcomponent); 73 74icalrestriction_property_record null_prop_record = {ICAL_METHOD_NONE,ICAL_NO_COMPONENT,ICAL_NO_PROPERTY,ICAL_RESTRICTION_UNKNOWN,0}; 75icalrestriction_component_record null_comp_record = {ICAL_METHOD_NONE,ICAL_NO_COMPONENT,ICAL_NO_COMPONENT,ICAL_RESTRICTION_UNKNOWN,0}; 76 77 78/** Each row gives the result of comparing a restriction against a count. 79 The columns in each row represent 0,1,2+. '-1' indicates 80 'invalid, 'don't care' or 'needs more analysis' So, for 81 ICAL_RESTRICTION_ONE, if there is 1 of a property with that 82 restriction, it passes, but if there are 0 or 2+, it fails. */ 83 84char compare_map[ICAL_RESTRICTION_UNKNOWN+1][3] = { 85 { 1, 1, 1},/*ICAL_RESTRICTION_NONE*/ 86 { 1, 0, 0},/*ICAL_RESTRICTION_ZERO*/ 87 { 0, 1, 0},/*ICAL_RESTRICTION_ONE*/ 88 { 1, 1, 1},/*ICAL_RESTRICTION_ZEROPLUS*/ 89 { 0, 1, 1},/*ICAL_RESTRICTION_ONEPLUS*/ 90 { 1, 1, 0},/*ICAL_RESTRICTION_ZEROORONE*/ 91 { 1, 1, 0},/*ICAL_RESTRICTION_ONEEXCLUSIVE*/ 92 { 1, 1, 0},/*ICAL_RESTRICTION_ONEMUTUAL*/ 93 { 1, 1, 1} /*ICAL_RESTRICTION_UNKNOWN*/ 94}; 95 96const char restr_string_map[ICAL_RESTRICTION_UNKNOWN+1][60] = { 97 "unknown number",/*ICAL_RESTRICTION_NONE*/ 98 "0",/*ICAL_RESTRICTION_ZERO*/ 99 "1",/*ICAL_RESTRICTION_ONE*/ 100 "zero or more",/*ICAL_RESTRICTION_ZEROPLUS*/ 101 "one or more" ,/*ICAL_RESTRICTION_ONEPLUS*/ 102 "zero or one",/*ICAL_RESTRICTION_ZEROORONE*/ 103 "zero or one, exclusive with another property",/*ICAL_RESTRICTION_ONEEXCLUSIVE*/ 104 "zero or one, mutual with another property",/*ICAL_RESTRICTION_ONEMUTUAL*/ 105 "unknown number" /*ICAL_RESTRICTION_UNKNOWN*/ 106}; 107 108 109int 110icalrestriction_compare(icalrestriction_kind restr, int count){ 111 112 /* restr is an unsigned int, ICAL_RESTRICTION_NONE == 0, so the check will always return false */ 113 if ( /*restr < ICAL_RESTRICTION_NONE ||*/ restr > ICAL_RESTRICTION_UNKNOWN 114 || count < 0){ 115 return -1; 116 } 117 118 if (count > 2) { 119 count = 2; 120 } 121 122 return compare_map[restr][count]; 123 124} 125 126/* Special case routines */ 127 128const char* icalrestriction_may_be_draft_final_canceled( 129 const icalrestriction_property_record *rec, 130 icalcomponent* comp, 131 icalproperty* prop) 132{ 133 icalproperty_status stat = icalproperty_get_status(prop); 134 (void)rec; 135 (void)comp; 136 137 if( !( stat == ICAL_STATUS_DRAFT || 138 stat == ICAL_STATUS_FINAL || 139 stat == ICAL_STATUS_CANCELLED )){ 140 141 return "Failed iTIP restrictions for STATUS property. Value must be one of DRAFT, FINAL, or CANCELED"; 142 143 } 144 145 return 0; 146} 147 148const char* icalrestriction_may_be_comp_need_process( 149 const icalrestriction_property_record *rec, 150 icalcomponent* comp, 151 icalproperty* prop) 152{ 153 icalproperty_status stat = icalproperty_get_status(prop); 154 (void)rec; 155 (void)comp; 156 157 if( !( stat == ICAL_STATUS_COMPLETED || 158 stat == ICAL_STATUS_NEEDSACTION || 159 stat == ICAL_STATUS_INPROCESS )){ 160 161 return "Failed iTIP restrictions for STATUS property. Value must be one of COMPLETED, NEEDS-ACTION or IN-PROCESS"; 162 163 } 164 165 return 0; 166} 167const char* icalrestriction_may_be_tent_conf(const icalrestriction_property_record *rec, 168 icalcomponent* comp, 169 icalproperty* prop) 170{ 171 icalproperty_status stat = icalproperty_get_status(prop); 172 173 (void)rec; 174 (void)comp; 175 176 if( !( stat == ICAL_STATUS_TENTATIVE || 177 stat == ICAL_STATUS_CONFIRMED )){ 178 179 return "Failed iTIP restrictions for STATUS property. Value must be one of TENTATIVE or CONFIRMED"; 180 181 } 182 183 return 0; 184} 185const char* icalrestriction_may_be_tent_conf_cancel( 186 const icalrestriction_property_record *rec, 187 icalcomponent* comp, 188 icalproperty* prop) 189{ 190 icalproperty_status stat = icalproperty_get_status(prop); 191 192 (void)rec; 193 (void)comp; 194 195 if( !( stat == ICAL_STATUS_TENTATIVE || 196 stat == ICAL_STATUS_CONFIRMED || 197 stat == ICAL_STATUS_CANCELLED )){ 198 199 return "Failed iTIP restrictions for STATUS property. Value must be one of TENTATIVE, CONFIRMED or CANCELED"; 200 201 } 202 203 return 0; 204} 205 206const char* icalrestriction_must_be_cancel_if_present( 207 const icalrestriction_property_record *rec, 208 icalcomponent* comp, 209 icalproperty* prop) 210{ 211 /* This routine will not be called if prop == 0 */ 212 icalproperty_status stat = icalproperty_get_status(prop); 213 (void)rec; 214 (void)comp; 215 216 if( stat != ICAL_STATUS_CANCELLED) 217 { 218 return "Failed iTIP restrictions for STATUS property. Value must be CANCELLED"; 219 220 } 221 222 223 return 0; 224} 225 226const char* icalrestriction_must_be_canceled_no_attendee( 227 const icalrestriction_property_record *rec, 228 icalcomponent* comp, 229 icalproperty* prop) 230{ 231 (void)rec; 232 (void)comp; 233 (void)prop; 234 235 /* Hack. see rfc2446, 3.2.5 CANCEL for porperty STATUS. I don't 236 understand the note */ 237 238 return 0; 239} 240 241const char* icalrestriction_must_be_recurring( 242 const icalrestriction_property_record *rec, 243 icalcomponent* comp, 244 icalproperty* prop){ 245 /* Hack */ 246 (void)rec; 247 (void)comp; 248 (void)prop; 249 return 0; 250} 251 252const char* icalrestriction_must_have_duration( 253 const icalrestriction_property_record *rec, 254 icalcomponent* comp, 255 icalproperty* prop) 256{ 257 if( !icalcomponent_get_first_property(comp,ICAL_DURATION_PROPERTY)){ 258 259 return "Failed iTIP restrictions for DURATION property. This component must have a DURATION property"; 260 261 } 262 263 return 0; 264} 265 266const char* icalrestriction_must_have_repeat( 267 const icalrestriction_property_record *rec, 268 icalcomponent* comp, 269 icalproperty* prop) 270{ 271 (void)rec; 272 (void)prop; 273 if( !icalcomponent_get_first_property(comp,ICAL_REPEAT_PROPERTY)){ 274 275 return "Failed iTIP restrictions for REPEAT property. This component must have a REPEAT property"; 276 277 } 278 279 return 0; 280} 281 282const char* icalrestriction_must_if_tz_ref( 283 const icalrestriction_property_record *rec, 284 icalcomponent* comp, 285 icalproperty* prop){ 286 287 /* Hack */ 288 (void)rec; 289 (void)comp; 290 (void)prop; 291 return 0; 292} 293 294const char* icalrestriction_no_dtend( 295 const icalrestriction_property_record *rec, 296 icalcomponent* comp, 297 icalproperty* prop) 298{ 299 300 (void)rec; 301 (void)prop; 302 if(icalcomponent_get_first_property(comp,ICAL_DTEND_PROPERTY)){ 303 304 return "Failed iTIP restrictions for DTEND property. The component must not have both DURATION and DTEND"; 305 306 } 307 308 return 0; 309} 310 311const char* icalrestriction_no_duration( 312 const icalrestriction_property_record *rec, 313 icalcomponent* comp, 314 icalproperty* prop) 315{ 316 (void)rec; 317 (void)comp; 318 (void)prop; 319 320 /* _no_dtend takes care of this one */ 321 return 0; 322} 323 324const char* icalrestriction_must_be_email( 325 const icalrestriction_property_record *rec, 326 icalcomponent* comp, 327 icalproperty* prop) 328{ 329 icalproperty_action stat = icalproperty_get_action(prop); 330 331 (void)rec; 332 (void)comp; 333 334 if( !( stat == ICAL_ACTION_EMAIL)){ 335 336 return "Failed iTIP restrictions for ACTION property. Value must be EMAIL."; 337 338 } 339 340 return 0; 341} 342 343int icalrestriction_check_component(icalproperty_method method, 344 icalcomponent* comp) 345{ 346 icalproperty_kind kind; 347 icalcomponent_kind comp_kind; 348 icalrestriction_kind restr; 349 const icalrestriction_property_record *prop_record; 350 const char* funcr = 0; 351 icalproperty *prop; 352 353 int count; 354 int compare; 355 int valid = 1; 356 357 comp_kind = icalcomponent_isa(comp); 358 359 /* Check all of the properties in this component */ 360 361 for(kind = ICAL_ANY_PROPERTY+1; kind != ICAL_NO_PROPERTY; kind++){ 362 count = icalcomponent_count_properties(comp, kind); 363 364 prop_record = icalrestriction_get_property_restriction(method, 365 comp_kind, 366 kind); 367 368 restr = prop_record->restriction; 369 370 if(restr == ICAL_RESTRICTION_ONEEXCLUSIVE || 371 restr == ICAL_RESTRICTION_ONEMUTUAL) { 372 373 /* First treat is as a 0/1 restriction */ 374 restr = ICAL_RESTRICTION_ZEROORONE; 375 compare = icalrestriction_compare(restr,count); 376 377 } else { 378 379 compare = icalrestriction_compare(restr,count); 380 } 381 382 assert(compare != -1); 383 384 if (compare == 0){ 385 char temp[TMP_BUF_SIZE]; 386 387 snprintf(temp, TMP_BUF_SIZE,"Failed iTIP restrictions for %s property. Expected %s instances of the property and got %d", 388 icalenum_property_kind_to_string(kind), 389 restr_string_map[restr], count); 390 391 icalcomponent_add_property 392 (comp, 393 icalproperty_vanew_xlicerror( 394 temp, 395 icalparameter_new_xlicerrortype(ICAL_XLICERRORTYPE_INVALIDITIP), 396 0)); 397 } 398 399 400 prop = icalcomponent_get_first_property(comp, kind); 401 402 if (prop != 0 && prop_record->function !=0 ){ 403 funcr = prop_record->function(prop_record,comp,prop); 404 } 405 406 if(funcr !=0){ 407 icalcomponent_add_property 408 (comp, 409 icalproperty_vanew_xlicerror( 410 funcr, 411 icalparameter_new_xlicerrortype( 412 ICAL_XLICERRORTYPE_INVALIDITIP), 413 0)); 414 415 compare = 0; 416 } 417 418 valid = valid && compare; 419 } 420 421 422 423 return valid; 424 425 426} 427 428int icalrestriction_check(icalcomponent* outer_comp) 429{ 430 icalcomponent_kind comp_kind; 431 icalproperty_method method; 432 icalcomponent* inner_comp; 433 icalproperty *method_prop; 434 int valid; 435 436 icalerror_check_arg_rz( (outer_comp!=0), "outer comp"); 437 438 439 /* Get the Method value from the outer component */ 440 441 comp_kind = icalcomponent_isa(outer_comp); 442 443 if (comp_kind != ICAL_VCALENDAR_COMPONENT){ 444 icalerror_set_errno(ICAL_BADARG_ERROR); 445 return 0; 446 } 447 448 method_prop = icalcomponent_get_first_property(outer_comp, 449 ICAL_METHOD_PROPERTY); 450 451 if (method_prop == 0){ 452 method = ICAL_METHOD_NONE; 453 } else { 454 method = icalproperty_get_method(method_prop); 455 } 456 457 458 /* Check the VCALENDAR wrapper */ 459 valid = icalrestriction_check_component(ICAL_METHOD_NONE,outer_comp); 460 461 462 /* Now check the inner components */ 463 464 for(inner_comp= icalcomponent_get_first_component(outer_comp, 465 ICAL_ANY_COMPONENT); 466 inner_comp != 0; 467 inner_comp= icalcomponent_get_next_component(outer_comp, 468 ICAL_ANY_COMPONENT)){ 469 470 valid = valid && icalrestriction_check_component(method,inner_comp); 471 472 } 473 474 475 return valid; 476 477} 478 479<insert_code_here> 480 481static const icalrestriction_property_record* 482icalrestriction_get_property_restriction(icalproperty_method method, 483 icalcomponent_kind component, 484 icalproperty_kind property) 485{ 486 int i; 487 488 for(i = 0; 489 icalrestriction_property_records[i].restriction != ICAL_RESTRICTION_NONE; 490 i++){ 491 492 if (method == icalrestriction_property_records[i].method && 493 component == icalrestriction_property_records[i].component && 494 property == icalrestriction_property_records[i].property ){ 495 return &icalrestriction_property_records[i]; 496 } 497 } 498 499 return &null_prop_record; 500} 501 502 503static const icalrestriction_component_record* 504icalrestriction_get_component_restriction(icalproperty_method method, 505 icalcomponent_kind component, 506 icalcomponent_kind subcomponent) 507{ 508 509 int i; 510 511 for(i = 0; 512 icalrestriction_component_records[i].restriction != ICAL_RESTRICTION_NONE; 513 i++){ 514 515 if (method == icalrestriction_component_records[i].method && 516 component == icalrestriction_component_records[i].component && 517 subcomponent == icalrestriction_component_records[i].subcomponent ){ 518 return &icalrestriction_component_records[i]; 519 } 520 } 521 522 return &null_comp_record; 523} 524