1 /*======================================================================
2 FILE: icalclassify.c
3 CREATOR: ebusboom 23 aug 2000
4
5 (C) COPYRIGHT 2000, Eric Busboom <eric@civicknowledge.com>
6
7 This library is free software; you can redistribute it and/or modify
8 it under the terms of either:
9
10 The LGPL as published by the Free Software Foundation, version
11 2.1, available at: https://www.gnu.org/licenses/lgpl-2.1.html
12
13 Or:
14
15 The Mozilla Public License Version 2.0. You may obtain a copy of
16 the License at https://www.mozilla.org/MPL/
17 ======================================================================*/
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include "icalclassify.h"
24 #include "icalmemory.h"
25
26 #include <ctype.h>
27 #include <stdlib.h>
28
29 struct icalclassify_parts
30 {
31 icalcomponent *c;
32 icalcomponent_kind inner_kind;
33 icalproperty_method method;
34 char *organizer;
35 icalparameter_partstat reply_partstat;
36 char *reply_attendee;
37 char *uid;
38 int sequence;
39 struct icaltimetype dtstamp;
40 struct icaltimetype recurrence_id;
41 };
42
icalclassify_lowercase(const char * str)43 char *icalclassify_lowercase(const char *str)
44 {
45 char *p = 0;
46 char *xnew;
47
48 if (str == 0) {
49 return 0;
50 }
51
52 xnew = icalmemory_strdup(str);
53 for (p = xnew; *p != 0; p++) {
54 *p = tolower((int)*p);
55 }
56
57 return xnew;
58 }
59
60 /* Return a set of components that intersect in time with comp. For
61 component X and Y to intersect:
62 X.DTSTART < Y.DTEND && X.DTEND > Y.DTSTART
63 */
64
icalclassify_find_overlaps(icalset * set,icalcomponent * comp)65 icalcomponent *icalclassify_find_overlaps(icalset *set, icalcomponent *comp)
66 {
67 icalcomponent *return_set;
68 icalcomponent *c;
69 struct icaltime_span span, compspan;
70
71 icalerror_clear_errno();
72 compspan = icalcomponent_get_span(comp);
73
74 if (icalerrno != ICAL_NO_ERROR) {
75 return 0;
76 }
77
78 return_set = icalcomponent_new(ICAL_XROOT_COMPONENT);
79
80 for (c = icalset_get_first_component(set); c != 0; c = icalset_get_next_component(set)) {
81
82 icalerror_clear_errno();
83
84 span = icalcomponent_get_span(c);
85
86 if (icalerrno != ICAL_NO_ERROR) {
87 continue;
88 }
89
90 if (compspan.start < span.end && compspan.end > span.start) {
91
92 icalcomponent *clone = icalcomponent_new_clone(c);
93
94 icalcomponent_add_component(return_set, clone);
95 }
96 }
97
98 if (icalcomponent_count_components(return_set, ICAL_ANY_COMPONENT) != 0) {
99 return return_set;
100 } else {
101 icalcomponent_free(return_set);
102 return 0;
103 }
104 }
105
icalclassify_find_attendee(icalcomponent * c,const char * attendee)106 icalproperty *icalclassify_find_attendee(icalcomponent *c, const char *attendee)
107 {
108 icalproperty *p;
109 icalcomponent *inner;
110 char *lattendee;
111 char *upn;
112
113 if (attendee == 0) {
114 return 0;
115 }
116
117 lattendee = icalclassify_lowercase(attendee);
118 upn = strchr(lattendee, ':');
119
120 if (upn == 0) {
121 upn = lattendee;
122 } else {
123 upn++; /* skip the ";" */
124 }
125
126 inner = icalcomponent_get_first_real_component(c);
127
128 for (p = icalcomponent_get_first_property(inner, ICAL_ATTENDEE_PROPERTY);
129 p != 0;
130 p = icalcomponent_get_next_property(inner, ICAL_ATTENDEE_PROPERTY)) {
131 char *this_upn;
132 char *this_attendee = icalclassify_lowercase(icalproperty_get_attendee(p));
133
134 if (!this_attendee)
135 continue;
136
137 this_upn = strchr(this_attendee, ':');
138
139 if (this_upn == 0) {
140 free(this_attendee);
141 continue;
142 } else {
143 this_upn++;
144 }
145
146 if (strcmp(this_upn, upn) == 0) {
147 free(lattendee);
148 free(this_attendee);
149 return p;
150 }
151
152 free(this_attendee);
153 }
154 free(lattendee);
155
156 return 0;
157 }
158
icalssutil_free_parts(struct icalclassify_parts * parts)159 void icalssutil_free_parts(struct icalclassify_parts *parts)
160 {
161 if (parts == 0) {
162 return;
163 }
164
165 if (parts->organizer != 0) {
166 free(parts->organizer);
167 }
168
169 if (parts->uid != 0) {
170 free(parts->uid);
171 }
172
173 if (parts->reply_attendee) {
174 free(parts->reply_attendee);
175 }
176 }
177
icalssutil_get_parts(icalcomponent * c,struct icalclassify_parts * parts)178 void icalssutil_get_parts(icalcomponent *c, struct icalclassify_parts *parts)
179 {
180 icalproperty *p;
181 icalcomponent *inner;
182
183 memset(parts, 0, sizeof(struct icalclassify_parts));
184
185 parts->method = ICAL_METHOD_NONE;
186 parts->sequence = 0;
187 parts->reply_partstat = ICAL_PARTSTAT_NONE;
188
189 if (c == 0) {
190 return;
191 }
192
193 parts->c = c;
194
195 p = icalcomponent_get_first_property(c, ICAL_METHOD_PROPERTY);
196 if (p != 0) {
197 parts->method = icalproperty_get_method(p);
198 }
199
200 inner = icalcomponent_get_first_real_component(c);
201
202 parts->inner_kind = icalcomponent_isa(inner);
203
204 p = icalcomponent_get_first_property(inner, ICAL_ORGANIZER_PROPERTY);
205 if (p != 0) {
206 const char *p_organizer = icalproperty_get_organizer(p);
207
208 if (p_organizer != 0) {
209 parts->organizer = strdup(p_organizer);
210 }
211 }
212
213 p = icalcomponent_get_first_property(inner, ICAL_SEQUENCE_PROPERTY);
214 if (p != 0) {
215 parts->sequence = icalproperty_get_sequence(p);
216 }
217
218 p = icalcomponent_get_first_property(inner, ICAL_UID_PROPERTY);
219 if (p != 0) {
220 const char *p_uid = icalproperty_get_uid(p);
221
222 if (p_uid != 0) {
223 parts->uid = strdup(p_uid);
224 }
225 }
226
227 p = icalcomponent_get_first_property(inner, ICAL_RECURRENCEID_PROPERTY);
228 if (p != 0) {
229 parts->recurrence_id = icalproperty_get_recurrenceid(p);
230 }
231
232 p = icalcomponent_get_first_property(inner, ICAL_DTSTAMP_PROPERTY);
233 if (p != 0) {
234 parts->dtstamp = icalproperty_get_dtstamp(p);
235 }
236
237 if (parts->method == ICAL_METHOD_REPLY) {
238 icalparameter *param;
239
240 p = icalcomponent_get_first_property(inner, ICAL_ATTENDEE_PROPERTY);
241
242 if (p != 0) {
243 const char *attendee = 0;
244
245 param = icalproperty_get_first_parameter(p, ICAL_PARTSTAT_PARAMETER);
246
247 if (param != 0) {
248 parts->reply_partstat = icalparameter_get_partstat(param);
249 }
250 attendee = icalproperty_get_attendee(p);
251 if (attendee)
252 parts->reply_attendee = strdup(attendee);
253 }
254 }
255 }
256
icalssutil_is_rescheduled(icalcomponent * a,icalcomponent * b)257 int icalssutil_is_rescheduled(icalcomponent *a, icalcomponent *b)
258 {
259 icalproperty *p1, *p2;
260 icalcomponent *i1, *i2;
261 char *temp1, *temp2;
262 int i;
263
264 icalproperty_kind kind_array[] = {
265 ICAL_DTSTART_PROPERTY,
266 ICAL_DTEND_PROPERTY,
267 ICAL_DURATION_PROPERTY,
268 ICAL_DUE_PROPERTY,
269 ICAL_RRULE_PROPERTY,
270 ICAL_RDATE_PROPERTY,
271 ICAL_EXRULE_PROPERTY,
272 ICAL_EXDATE_PROPERTY,
273 ICAL_NO_PROPERTY
274 };
275
276 i1 = icalcomponent_get_first_real_component(a);
277 i2 = icalcomponent_get_first_real_component(b);
278
279 for (i = 0; kind_array[i] != ICAL_NO_PROPERTY; i++) {
280 int cmp;
281
282 p1 = icalcomponent_get_first_property(i1, kind_array[i]);
283 p2 = icalcomponent_get_first_property(i2, kind_array[i]);
284
285 if ((p1 != 0) ^ (p2 != 0)) {
286 /* Return true if the property exists in one component and not
287 the other */
288 return 1;
289 } else if (!p1 && !p2)
290 continue;
291
292 temp1 = icalproperty_as_ical_string_r(p1);
293 temp2 = icalproperty_as_ical_string_r(p2);
294 cmp = strcmp(temp1, temp2);
295 free(temp1);
296 free(temp2);
297
298 if (p1 && cmp != 0) {
299 return 1;
300 }
301 }
302
303 return 0;
304 }
305
306 #define icalclassify_pre \
307 int rtrn = 0;
308
309 #define icalclassify_post \
310 return rtrn;
311
icalclassify_publish_new(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)312 int icalclassify_publish_new(struct icalclassify_parts *comp,
313 struct icalclassify_parts *match, const char *user)
314 {
315 icalclassify_pre;
316 _unused(user);
317
318 if (comp->method == ICAL_METHOD_PUBLISH &&
319 match == 0 && comp->inner_kind != ICAL_VFREEBUSY_COMPONENT) {
320 rtrn = 1;
321 }
322
323 icalclassify_post;
324 }
325
icalclassify_publish_update(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)326 int icalclassify_publish_update(struct icalclassify_parts *comp,
327 struct icalclassify_parts *match, const char *user)
328 {
329 icalclassify_pre;
330 _unused(user);
331
332 if (comp->method == ICAL_METHOD_PUBLISH &&
333 match != 0 && comp->inner_kind != ICAL_VFREEBUSY_COMPONENT) {
334 rtrn = 1;
335 }
336
337 icalclassify_post;
338 }
339
icalclassify_publish_freebusy(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)340 int icalclassify_publish_freebusy(struct icalclassify_parts *comp,
341 struct icalclassify_parts *match, const char *user)
342 {
343 icalclassify_pre;
344
345 _unused(match);
346 _unused(user);
347 if (comp->method == ICAL_METHOD_PUBLISH && comp->inner_kind == ICAL_VFREEBUSY_COMPONENT) {
348 rtrn = 1;
349 }
350
351 icalclassify_post;
352 }
353
icalclassify_request_new(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)354 int icalclassify_request_new(struct icalclassify_parts *comp,
355 struct icalclassify_parts *match, const char *user)
356 {
357 /* Method is REQUEST, and there is no match */
358
359 icalclassify_pre _unused(user);
360
361 if (match->c == 0 && comp->method == ICAL_METHOD_REQUEST) {
362 rtrn = 1;
363 }
364
365 icalclassify_post}
366
icalclassify_request_update(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)367 int icalclassify_request_update(struct icalclassify_parts *comp,
368 struct icalclassify_parts *match, const char *user)
369 {
370 /* REQUEST method, Higher SEQUENCE than match, and all
371 time-related properties are unchanged */
372
373 icalclassify_pre _unused(user);
374
375 if (match != 0 &&
376 comp->sequence >= match->sequence && !icalssutil_is_rescheduled(comp->c, match->c)) {
377 rtrn = 1;
378 }
379
380 icalclassify_post}
381
icalclassify_request_reschedule(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)382 int icalclassify_request_reschedule(struct icalclassify_parts *comp,
383 struct icalclassify_parts *match, const char *user)
384 {
385 /* REQUEST method, Higher SEQUENCE than match, and one or more
386 time-related properties are changed */
387 icalclassify_pre _unused(user);
388
389 if (match->c != 0 &&
390 comp->sequence > match->sequence && icalssutil_is_rescheduled(comp->c, match->c)) {
391 rtrn = 1;
392 }
393
394 icalclassify_post}
395
icalclassify_request_delegate(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)396 int icalclassify_request_delegate(struct icalclassify_parts *comp,
397 struct icalclassify_parts *match, const char *user)
398 {
399 icalproperty *attendee;
400 icalparameter *param;
401
402 icalclassify_pre;
403 _unused(match);
404
405 attendee = icalclassify_find_attendee(comp->c, user);
406
407 if (attendee == 0) {
408 return 0;
409 }
410
411 param = icalproperty_get_first_parameter(attendee, ICAL_DELEGATEDFROM_PARAMETER);
412
413 if (param != 0) {
414 rtrn = 1;
415 }
416
417 icalclassify_post}
418
icalclassify_request_new_organizer(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)419 int icalclassify_request_new_organizer(struct icalclassify_parts *comp,
420 struct icalclassify_parts *match, const char *user)
421 {
422 /* Organizer has changed between match and component */
423 icalclassify_pre _unused(comp);
424 _unused(match);
425 _unused(user);
426
427 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
428 icalclassify_post}
429
icalclassify_request_status(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)430 int icalclassify_request_status(struct icalclassify_parts *comp,
431 struct icalclassify_parts *match, const char *user)
432 {
433 icalclassify_pre _unused(comp);
434 _unused(match);
435 _unused(user);
436
437 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
438 icalclassify_post}
439
icalclassify_request_forward(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)440 int icalclassify_request_forward(struct icalclassify_parts *comp,
441 struct icalclassify_parts *match, const char *user)
442 {
443 icalclassify_pre _unused(comp);
444 _unused(match);
445 _unused(user);
446
447 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
448 icalclassify_post}
449
icalclassify_request_freebusy(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)450 int icalclassify_request_freebusy(struct icalclassify_parts *comp,
451 struct icalclassify_parts *match, const char *user)
452 {
453 icalclassify_pre _unused(comp);
454 _unused(match);
455 _unused(user);
456
457 icalerror_set_errno(ICAL_UNIMPLEMENTED_ERROR);
458 icalclassify_post}
459
icalclassify_reply_accept(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)460 int icalclassify_reply_accept(struct icalclassify_parts *comp,
461 struct icalclassify_parts *match, const char *user)
462 {
463 icalproperty *attendee;
464
465 icalclassify_pre;
466 _unused(user);
467
468 attendee = icalclassify_find_attendee(match->c, comp->reply_attendee);
469
470 if (attendee != 0 && comp->reply_partstat == ICAL_PARTSTAT_ACCEPTED) {
471 rtrn = 1;
472 }
473
474 icalclassify_post}
475
icalclassify_reply_decline(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)476 int icalclassify_reply_decline(struct icalclassify_parts *comp,
477 struct icalclassify_parts *match, const char *user)
478 {
479 icalproperty *attendee;
480
481 icalclassify_pre;
482 _unused(user);
483
484 attendee = icalclassify_find_attendee(match->c, comp->reply_attendee);
485
486 if (attendee != 0 && comp->reply_partstat == ICAL_PARTSTAT_DECLINED) {
487 rtrn = 1;
488 }
489 icalclassify_post}
490
icalclassify_reply_delegate(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)491 int icalclassify_reply_delegate(struct icalclassify_parts *comp,
492 struct icalclassify_parts *match, const char *user)
493 {
494 icalproperty *attendee;
495
496 icalclassify_pre;
497 _unused(user);
498
499 attendee = icalclassify_find_attendee(match->c, comp->reply_attendee);
500
501 if (attendee != 0 && comp->reply_partstat == ICAL_PARTSTAT_DELEGATED) {
502 rtrn = 1;
503 }
504 icalclassify_post}
505
icalclassify_reply_crasher_accept(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)506 int icalclassify_reply_crasher_accept(struct icalclassify_parts *comp,
507 struct icalclassify_parts *match, const char *user)
508 {
509 icalproperty *attendee;
510
511 icalclassify_pre;
512 _unused(user);
513
514 attendee = icalclassify_find_attendee(match->c, comp->reply_attendee);
515
516 if (attendee == 0 && comp->reply_partstat == ICAL_PARTSTAT_ACCEPTED) {
517 rtrn = 1;
518 }
519 icalclassify_post}
520
icalclassify_reply_crasher_decline(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)521 int icalclassify_reply_crasher_decline(struct icalclassify_parts *comp,
522 struct icalclassify_parts *match, const char *user)
523 {
524 icalproperty *attendee;
525
526 icalclassify_pre;
527 _unused(user);
528
529 attendee = icalclassify_find_attendee(match->c, comp->reply_attendee);
530
531 if (attendee == 0 && comp->reply_partstat == ICAL_PARTSTAT_DECLINED) {
532 rtrn = 1;
533 }
534 icalclassify_post}
535
icalclassify_add_instance(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)536 int icalclassify_add_instance(struct icalclassify_parts *comp,
537 struct icalclassify_parts *match, const char *user)
538 {
539 icalclassify_pre _unused(match);
540 _unused(user);
541
542 if (comp->method == ICAL_METHOD_ADD) {
543 rtrn = 1;
544 }
545 icalclassify_post}
546
icalclassify_cancel_event(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)547 int icalclassify_cancel_event(struct icalclassify_parts *comp,
548 struct icalclassify_parts *match, const char *user)
549 {
550 icalclassify_pre _unused(match);
551 _unused(user);
552 if (comp->method == ICAL_METHOD_CANCEL) {
553 rtrn = 1;
554 }
555 icalclassify_post}
556
icalclassify_cancel_instance(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)557 int icalclassify_cancel_instance(struct icalclassify_parts *comp,
558 struct icalclassify_parts *match, const char *user)
559 {
560 icalclassify_pre _unused(match);
561 _unused(user);
562 if (comp->method == ICAL_METHOD_CANCEL) {
563 rtrn = 1;
564 }
565 icalclassify_post}
566
icalclassify_cancel_all(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)567 int icalclassify_cancel_all(struct icalclassify_parts *comp,
568 struct icalclassify_parts *match, const char *user)
569 {
570 icalclassify_pre _unused(match);
571 _unused(user);
572 if (comp->method == ICAL_METHOD_CANCEL) {
573 rtrn = 1;
574 }
575 icalclassify_post}
576
icalclassify_refesh(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)577 int icalclassify_refesh(struct icalclassify_parts *comp,
578 struct icalclassify_parts *match, const char *user)
579 {
580 icalclassify_pre _unused(match);
581 _unused(user);
582 if (comp->method == ICAL_METHOD_REFRESH) {
583 rtrn = 1;
584 }
585 icalclassify_post}
586
icalclassify_counter(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)587 int icalclassify_counter(struct icalclassify_parts *comp,
588 struct icalclassify_parts *match, const char *user)
589 {
590 icalclassify_pre _unused(match);
591 _unused(user);
592 if (comp->method == ICAL_METHOD_COUNTER) {
593 rtrn = 1;
594 }
595 icalclassify_post}
596
icalclassify_delinecounter(struct icalclassify_parts * comp,struct icalclassify_parts * match,const char * user)597 int icalclassify_delinecounter(struct icalclassify_parts *comp,
598 struct icalclassify_parts *match, const char *user)
599 {
600 icalclassify_pre _unused(match);
601 _unused(user);
602
603 if (comp->method == ICAL_METHOD_DECLINECOUNTER) {
604 rtrn = 1;
605 }
606
607 icalclassify_post}
608
609 static const struct icalclassify_map
610 {
611 icalproperty_method method;
612 int (*fn) (struct icalclassify_parts *comp, struct icalclassify_parts *match,
613 const char *user);
614 icalproperty_xlicclass class;
615 } icalclassify_map[] = {
616 {ICAL_METHOD_PUBLISH, icalclassify_publish_new, ICAL_XLICCLASS_PUBLISHNEW},
617 {ICAL_METHOD_PUBLISH, icalclassify_publish_update, ICAL_XLICCLASS_PUBLISHUPDATE},
618 {ICAL_METHOD_PUBLISH, icalclassify_publish_freebusy, ICAL_XLICCLASS_PUBLISHFREEBUSY},
619 {ICAL_METHOD_REQUEST, icalclassify_request_delegate, ICAL_XLICCLASS_REQUESTDELEGATE},
620 {ICAL_METHOD_REQUEST, icalclassify_request_new, ICAL_XLICCLASS_REQUESTNEW},
621 {ICAL_METHOD_REQUEST, icalclassify_request_update, ICAL_XLICCLASS_REQUESTUPDATE},
622 {ICAL_METHOD_REQUEST, icalclassify_request_reschedule, ICAL_XLICCLASS_REQUESTRESCHEDULE},
623 {ICAL_METHOD_REQUEST, icalclassify_request_new_organizer, ICAL_XLICCLASS_REQUESTNEWORGANIZER},
624 {ICAL_METHOD_REQUEST, icalclassify_request_forward, ICAL_XLICCLASS_REQUESTFORWARD},
625 {ICAL_METHOD_REQUEST, icalclassify_request_status, ICAL_XLICCLASS_REQUESTSTATUS},
626 {ICAL_METHOD_REQUEST, icalclassify_request_freebusy, ICAL_XLICCLASS_REQUESTFREEBUSY},
627 {ICAL_METHOD_REPLY, icalclassify_reply_accept, ICAL_XLICCLASS_REPLYACCEPT},
628 {ICAL_METHOD_REPLY, icalclassify_reply_decline, ICAL_XLICCLASS_REPLYDECLINE},
629 {ICAL_METHOD_REPLY, icalclassify_reply_delegate, ICAL_XLICCLASS_REPLYDELEGATE},
630 {ICAL_METHOD_REPLY, icalclassify_reply_crasher_accept, ICAL_XLICCLASS_REPLYCRASHERACCEPT},
631 {ICAL_METHOD_REPLY, icalclassify_reply_crasher_decline, ICAL_XLICCLASS_REPLYCRASHERDECLINE},
632 {ICAL_METHOD_ADD, icalclassify_add_instance, ICAL_XLICCLASS_ADDINSTANCE},
633 {ICAL_METHOD_CANCEL, icalclassify_cancel_event, ICAL_XLICCLASS_CANCELEVENT},
634 {ICAL_METHOD_CANCEL, icalclassify_cancel_instance, ICAL_XLICCLASS_CANCELINSTANCE},
635 {ICAL_METHOD_CANCEL, icalclassify_cancel_all, ICAL_XLICCLASS_CANCELALL},
636 {ICAL_METHOD_REFRESH, icalclassify_refesh, ICAL_XLICCLASS_REFRESH},
637 {ICAL_METHOD_COUNTER, icalclassify_counter, ICAL_XLICCLASS_COUNTER},
638 {ICAL_METHOD_DECLINECOUNTER, icalclassify_delinecounter, ICAL_XLICCLASS_DECLINECOUNTER},
639 {ICAL_METHOD_NONE, NULL, ICAL_XLICCLASS_NONE}
640 };
641
icalclassify(icalcomponent * c,icalcomponent * match,const char * user)642 icalproperty_xlicclass icalclassify(icalcomponent *c, icalcomponent *match, const char *user)
643 {
644 icalcomponent *inner;
645 icalproperty *p;
646 icalproperty_method method;
647 icalproperty_xlicclass class = ICAL_XLICCLASS_UNKNOWN;
648
649 int i;
650
651 struct icalclassify_parts comp_parts;
652 struct icalclassify_parts match_parts;
653
654 inner = icalcomponent_get_first_real_component(c);
655
656 if (inner == 0) {
657 return ICAL_XLICCLASS_NONE;
658 }
659
660 icalssutil_get_parts(c, &comp_parts);
661 icalssutil_get_parts(match, &match_parts);
662
663 /* Determine if the incoming component is obsoleted by the match */
664 if (match != 0 && (comp_parts.method == ICAL_METHOD_REQUEST)) {
665 assert(!((icaltime_is_utc(comp_parts.dtstamp) == 1) ^
666 (icaltime_is_utc(match_parts.dtstamp) == 1)));
667
668 if (comp_parts.sequence < match_parts.sequence &&
669 icaltime_compare(comp_parts.dtstamp, match_parts.dtstamp) > 0) {
670 /* comp has a smaller sequence and a later DTSTAMP */
671 class = ICAL_XLICCLASS_MISSEQUENCED;
672 goto CLEANUP;
673 }
674
675 if ((comp_parts.sequence < match_parts.sequence) ||
676 (comp_parts.sequence == match_parts.sequence &&
677 icaltime_compare(comp_parts.dtstamp, match_parts.dtstamp) <= 0)) {
678 class = ICAL_XLICCLASS_OBSOLETE;
679 goto CLEANUP;
680 }
681 }
682
683 p = icalcomponent_get_first_property(c, ICAL_METHOD_PROPERTY);
684 if (p == 0) {
685 class = ICAL_XLICCLASS_UNKNOWN;
686 goto CLEANUP;
687 }
688 method = icalproperty_get_method(p);
689
690 for (i = 0; icalclassify_map[i].method != ICAL_METHOD_NONE; i++) {
691 if (icalclassify_map[i].method == method) {
692 if ((*(icalclassify_map[i].fn)) (&comp_parts, &match_parts, user) == 1) {
693 class = icalclassify_map[i].class;
694 break;
695 }
696 }
697 }
698
699 CLEANUP:
700 icalssutil_free_parts(&comp_parts);
701 icalssutil_free_parts(&match_parts);
702
703 return class;
704 }
705