1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3
* This program is free software; you can redistribute it and/or
4
* modify it under the terms of the GNU Lesser General Public
5
* License as published by the Free Software Foundation; either
6
* version 2 of the License, or (at your option) version 3.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
* Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public
14
* License along with the program; if not, see <http://www.gnu.org/licenses/>
18
* Suman Manjunath <msuman@novell.com>
20
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
28
#include "exchange-mapi-cal-recur-utils.h"
30
/* Reader/Writer versions */
31
#define READER_VERSION 0x3004
32
#define WRITER_VERSION 0x3004
33
#define READER_VERSION2 0x3006
34
#define WRITER_VERSION2 0x3009
37
struct ChangeHighlight {
43
struct ExtendedException {
44
struct ChangeHighlight ch;
45
uint32_t ReservedEE1Size;
47
uint32_t StartDateTime;
49
uint32_t OrigStartDate;
50
uint16_t WideCharSubjectLength;
51
gchar *WideCharSubject;
52
uint16_t WideCharLocationLength;
53
gchar *WideCharLocation;
54
uint32_t ReservedEE2Size;
58
struct ExceptionInfo {
59
uint32_t StartDateTime;
61
uint32_t OrigStartDate;
62
uint16_t OverrideFlags;
63
uint16_t SubjectLength;
64
uint16_t SubjectLength2;
67
uint32_t ReminderDelta;
69
uint16_t LocationLength;
70
uint16_t LocationLength2;
75
uint32_t AppointmentColor;
79
static icalrecurrencetype_weekday
80
get_ical_weekstart (uint32_t fdow)
83
case FirstDOW_Sunday : return ICAL_SUNDAY_WEEKDAY;
84
case FirstDOW_Monday : return ICAL_MONDAY_WEEKDAY;
85
case FirstDOW_Tuesday : return ICAL_TUESDAY_WEEKDAY;
86
case FirstDOW_Wednesday : return ICAL_WEDNESDAY_WEEKDAY;
87
case FirstDOW_Thursday : return ICAL_THURSDAY_WEEKDAY;
88
case FirstDOW_Friday : return ICAL_FRIDAY_WEEKDAY;
89
case FirstDOW_Saturday : return ICAL_SATURDAY_WEEKDAY;
90
default : return ICAL_SUNDAY_WEEKDAY;
95
get_mapi_weekstart (icalrecurrencetype_weekday weekstart)
98
case ICAL_SUNDAY_WEEKDAY : return FirstDOW_Sunday;
99
case ICAL_MONDAY_WEEKDAY : return FirstDOW_Monday;
100
case ICAL_TUESDAY_WEEKDAY : return FirstDOW_Tuesday;
101
case ICAL_WEDNESDAY_WEEKDAY: return FirstDOW_Wednesday;
102
case ICAL_THURSDAY_WEEKDAY : return FirstDOW_Thursday;
103
case ICAL_FRIDAY_WEEKDAY : return FirstDOW_Friday;
104
case ICAL_SATURDAY_WEEKDAY : return FirstDOW_Saturday;
105
default : return FirstDOW_Sunday;
110
get_mapi_day (icalrecurrencetype_weekday someday)
113
case ICAL_SUNDAY_WEEKDAY : return olSunday;
114
case ICAL_MONDAY_WEEKDAY : return olMonday;
115
case ICAL_TUESDAY_WEEKDAY : return olTuesday;
116
case ICAL_WEDNESDAY_WEEKDAY: return olWednesday;
117
case ICAL_THURSDAY_WEEKDAY : return olThursday;
118
case ICAL_FRIDAY_WEEKDAY : return olFriday;
119
case ICAL_SATURDAY_WEEKDAY : return olSaturday;
125
get_ical_pos (uint32_t pos)
128
case RecurrenceN_First : return 1;
129
case RecurrenceN_Second : return 2;
130
case RecurrenceN_Third : return 3;
131
case RecurrenceN_Fourth : return 4;
132
case RecurrenceN_Last : return (-1);
138
get_mapi_pos (int32_t pos)
141
case 1 : return RecurrenceN_First;
142
case 2 : return RecurrenceN_Second;
143
case 3 : return RecurrenceN_Third;
144
case 4 : return RecurrenceN_Fourth;
145
case -1 : return RecurrenceN_Last;
150
#define cFileTimeUnitsPerSecond 10000000
153
convert_recurrence_minutes_to_date (uint32_t minutes, struct FILETIME *ft)
157
nt = (NTTIME) minutes * (60 * cFileTimeUnitsPerSecond);
159
ft->dwLowDateTime = (uint32_t)((nt << 32) >> 32);
160
ft->dwHighDateTime = (uint32_t)(nt >> 32);
164
convert_date_to_recurrence_minutes (const struct FILETIME *ft)
168
minutes = ft->dwHighDateTime;
169
minutes = minutes << 32;
170
minutes |= ft->dwLowDateTime;
172
minutes = minutes / (60 * cFileTimeUnitsPerSecond);
174
return (uint32_t)(minutes);
178
convert_filetime_to_timet (const struct FILETIME *ft)
182
time = ft->dwHighDateTime;
184
time |= ft->dwLowDateTime;
186
return nt_time_to_unix (time);
190
convert_timet_to_filetime (time_t t, struct FILETIME *ft)
194
unix_to_nt_time (&nt, t);
196
ft->dwLowDateTime = (uint32_t)((nt << 32) >> 32);
197
ft->dwHighDateTime = (uint32_t)(nt >> 32);
201
convert_recurrence_minutes_to_timet (uint32_t minutes)
205
nt = (NTTIME) minutes * (60 * cFileTimeUnitsPerSecond);
207
return nt_time_to_unix (nt);
211
convert_timet_to_recurrence_minutes (time_t t)
215
unix_to_nt_time (&minutes, t);
217
minutes = minutes / (60 * cFileTimeUnitsPerSecond);
219
return (uint32_t)(minutes);
223
check_calendar_type (guint16 type)
225
/* Calendar Type - We support Gregorian only. */
226
if (type == CAL_DEFAULT || type == CAL_GREGORIAN)
229
g_warning ("Calendar type = 0x%04X - Evolution does not handle such calendar types.", type);
235
exchange_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp)
237
struct icalrecurrencetype rt;
240
guint8 *ptr = ba->data;
242
GSList *exdate_list = NULL;
243
gboolean repeats_until_date = FALSE;
245
icalrecurrencetype_clear (&rt);
248
flag16 = *((guint16 *)ptr);
249
ptr += sizeof (guint16);
250
if (READER_VERSION != flag16)
254
flag16 = *((guint16 *)ptr);
255
ptr += sizeof (guint16);
256
if (WRITER_VERSION != flag16)
260
flag16 = *((guint16 *)ptr);
261
ptr += sizeof (guint16);
262
if (flag16 == RecurFrequency_Daily) {
263
rt.freq = ICAL_DAILY_RECURRENCE;
265
flag16 = *((guint16 *)ptr);
266
ptr += sizeof (guint16);
267
if (flag16 == PatternType_Day) {
268
/* Daily every N days */
271
flag16 = *((guint16 *)ptr);
272
ptr += sizeof (guint16);
273
if (!check_calendar_type (flag16))
276
/* FirstDateTime (some crappy mod here) */
277
flag32 = *((guint32 *)ptr);
278
ptr += sizeof (guint32);
281
flag32 = *((guint32 *)ptr);
282
ptr += sizeof (guint32);
283
rt.interval = (short) (flag32 / (24 * 60));
285
/* some constant 0 for the stuff we handle */
286
flag32 = *((guint32 *)ptr);
287
ptr += sizeof (guint32);
291
} else if (flag16 == PatternType_Week) {
292
/* Daily every weekday */
295
flag16 = *((guint16 *)ptr);
296
ptr += sizeof (guint16);
297
if (!check_calendar_type (flag16))
300
/* NOTE: Evolution does not handle daily-every-weekday any different
301
* from a weekly recurrence.
303
rt.freq = ICAL_WEEKLY_RECURRENCE;
305
/* FirstDateTime (some crappy mod here) */
306
flag32 = *((guint32 *)ptr);
307
ptr += sizeof (guint32);
310
flag32 = *((guint32 *)ptr);
311
ptr += sizeof (guint32);
312
rt.interval = (short) (flag32);
314
/* some constant 0 for the stuff we handle */
315
flag32 = *((guint32 *)ptr);
316
ptr += sizeof (guint32);
321
flag32 = *((guint32 *)ptr);
322
ptr += sizeof (guint32);
325
if (flag32 & olSunday)
326
rt.by_day[i++] = ICAL_SUNDAY_WEEKDAY;
327
if (flag32 & olMonday)
328
rt.by_day[i++] = ICAL_MONDAY_WEEKDAY;
329
if (flag32 & olTuesday)
330
rt.by_day[i++] = ICAL_TUESDAY_WEEKDAY;
331
if (flag32 & olWednesday)
332
rt.by_day[i++] = ICAL_WEDNESDAY_WEEKDAY;
333
if (flag32 & olThursday)
334
rt.by_day[i++] = ICAL_THURSDAY_WEEKDAY;
335
if (flag32 & olFriday)
336
rt.by_day[i++] = ICAL_FRIDAY_WEEKDAY;
337
if (flag32 & olSaturday)
338
rt.by_day[i++] = ICAL_SATURDAY_WEEKDAY;
341
} else if (flag16 == RecurFrequency_Weekly) {
342
rt.freq = ICAL_WEEKLY_RECURRENCE;
344
flag16 = *((guint16 *)ptr);
345
ptr += sizeof (guint16);
346
if (flag16 == PatternType_Week) {
347
/* weekly every N weeks (for all events and non-regenerating tasks) */
350
flag16 = *((guint16 *)ptr);
351
ptr += sizeof (guint16);
352
if (!check_calendar_type (flag16))
355
/* FirstDateTime (some crappy mod here) */
356
flag32 = *((guint32 *)ptr);
357
ptr += sizeof (guint32);
360
flag32 = *((guint32 *)ptr);
361
ptr += sizeof (guint32);
362
rt.interval = (short) (flag32);
364
/* some constant 0 */
365
flag32 = *((guint32 *)ptr);
366
ptr += sizeof (guint32);
371
flag32 = *((guint32 *)ptr);
372
ptr += sizeof (guint32);
375
if (flag32 & olSunday)
376
rt.by_day[i++] = ICAL_SUNDAY_WEEKDAY;
377
if (flag32 & olMonday)
378
rt.by_day[i++] = ICAL_MONDAY_WEEKDAY;
379
if (flag32 & olTuesday)
380
rt.by_day[i++] = ICAL_TUESDAY_WEEKDAY;
381
if (flag32 & olWednesday)
382
rt.by_day[i++] = ICAL_WEDNESDAY_WEEKDAY;
383
if (flag32 & olThursday)
384
rt.by_day[i++] = ICAL_THURSDAY_WEEKDAY;
385
if (flag32 & olFriday)
386
rt.by_day[i++] = ICAL_FRIDAY_WEEKDAY;
387
if (flag32 & olSaturday)
388
rt.by_day[i++] = ICAL_SATURDAY_WEEKDAY;
390
} else if (flag16 == 0x0) {
391
/* weekly every N weeks (for all regenerating tasks) */
394
flag16 = *((guint16 *)ptr);
395
ptr += sizeof (guint16);
396
if (!check_calendar_type (flag16))
399
/* FIXME: we don't handle regenerating tasks */
400
g_warning ("Evolution does not handle recurring tasks.");
404
} else if (flag16 == RecurFrequency_Monthly) {
405
rt.freq = ICAL_MONTHLY_RECURRENCE;
407
flag16 = *((guint16 *)ptr);
408
ptr += sizeof (guint16);
409
if (flag16 == PatternType_Month || flag16 == PatternType_MonthEnd) {
410
guint16 pattern = flag16;
411
/* Monthly every N months on day D or last day. */
414
flag16 = *((guint16 *)ptr);
415
ptr += sizeof (guint16);
416
if (!check_calendar_type (flag16))
419
/* FirstDateTime (some crappy mod here) */
420
flag32 = *((guint32 *)ptr);
421
ptr += sizeof (guint32);
424
flag32 = *((guint32 *)ptr);
425
ptr += sizeof (guint32);
426
rt.interval = (short) (flag32);
428
/* some constant 0 for the stuff we handle */
429
flag32 = *((guint32 *)ptr);
430
ptr += sizeof (guint32);
435
flag32 = *((guint32 *)ptr);
436
ptr += sizeof (guint32);
437
if (pattern == PatternType_Month)
438
rt.by_month_day[0] = (short) (flag32);
439
else if (pattern == PatternType_MonthEnd)
440
rt.by_month_day[0] = (short) (-1);
442
} else if (flag16 == PatternType_MonthNth) {
443
gboolean post_process = FALSE;
445
/* Monthly every N months on the Xth Y */
448
flag16 = *((guint16 *)ptr);
449
ptr += sizeof (guint16);
450
if (!check_calendar_type (flag16))
453
/* FirstDateTime (some crappy mod here) */
454
flag32 = *((guint32 *)ptr);
455
ptr += sizeof (guint32);
458
flag32 = *((guint32 *)ptr);
459
ptr += sizeof (guint32);
460
rt.interval = (short) (flag32);
462
/* some constant 0 for the stuff we handle */
463
flag32 = *((guint32 *)ptr);
464
ptr += sizeof (guint32);
469
flag32 = *((guint32 *)ptr);
470
ptr += sizeof (guint32);
471
if (flag32 == olSunday)
472
rt.by_day[0] = ICAL_SUNDAY_WEEKDAY;
473
else if (flag32 == olMonday)
474
rt.by_day[0] = ICAL_MONDAY_WEEKDAY;
475
else if (flag32 == olTuesday)
476
rt.by_day[0] = ICAL_TUESDAY_WEEKDAY;
477
else if (flag32 == olWednesday)
478
rt.by_day[0] = ICAL_WEDNESDAY_WEEKDAY;
479
else if (flag32 == olThursday)
480
rt.by_day[0] = ICAL_THURSDAY_WEEKDAY;
481
else if (flag32 == olFriday)
482
rt.by_day[0] = ICAL_FRIDAY_WEEKDAY;
483
else if (flag32 == olSaturday)
484
rt.by_day[0] = ICAL_SATURDAY_WEEKDAY;
491
flag32 = *((guint32 *)ptr);
492
ptr += sizeof (guint32);
494
rt.by_set_pos[0] = get_ical_pos (flag32);
495
if (rt.by_set_pos[0] == 0)
498
if (mask == (olSunday | olMonday | olTuesday | olWednesday | olThursday | olFriday | olSaturday)) {
499
rt.by_month_day[0] = get_ical_pos (flag32);
500
if (rt.by_month_day[0] == 0)
503
/* FIXME: Can we/LibICAL support any other types here? Namely, weekday and weekend-day */
504
g_warning ("Encountered a recurrence type Evolution cannot handle. ");
510
} else if (flag16 == RecurFrequency_Yearly) {
511
rt.freq = ICAL_YEARLY_RECURRENCE;
513
flag16 = *((guint16 *)ptr);
514
ptr += sizeof (guint16);
515
if (flag16 == PatternType_Month) {
516
/* Yearly on day D of month M */
519
flag16 = *((guint16 *)ptr);
520
ptr += sizeof (guint16);
521
if (!check_calendar_type (flag16))
524
/* FirstDateTime (some crappy mod here) */
525
flag32 = *((guint32 *)ptr);
526
ptr += sizeof (guint32);
529
flag32 = *((guint32 *)ptr);
530
ptr += sizeof (guint32);
531
rt.interval = (short) (flag32 / 12);
533
/* some constant 0 for the stuff we handle */
534
flag32 = *((guint32 *)ptr);
535
ptr += sizeof (guint32);
539
/* MONTH_DAY - but we don't need this */
540
flag32 = *((guint32 *)ptr);
541
ptr += sizeof (guint32);
543
} else if (flag16 == PatternType_MonthNth) {
544
/* Yearly on the Xth Y of month M */
546
g_warning ("Encountered a recurrence pattern Evolution cannot handle.");
549
flag16 = *((guint16 *)ptr);
550
ptr += sizeof (guint16);
551
if (!check_calendar_type (flag16))
554
/* FirstDateTime (some crappy mod here) */
555
flag32 = *((guint32 *)ptr);
556
ptr += sizeof (guint32);
559
flag32 = *((guint32 *)ptr);
560
ptr += sizeof (guint32);
561
rt.interval = (short) (flag32 / 12);
563
/* some constant 0 */
564
flag32 = *((guint32 *)ptr);
565
ptr += sizeof (guint32);
570
flag32 = *((guint32 *)ptr);
571
ptr += sizeof (guint32);
574
flag32 = *((guint32 *)ptr);
575
ptr += sizeof (guint32);
577
/* TODO: Add support for this kinda recurrence in Evolution */
583
/* End Type - followed by Occurence count */
584
flag32 = *((guint32 *)ptr);
585
ptr += sizeof (guint32);
586
if (flag32 == END_AFTER_DATE) {
587
flag32 = *((guint32 *)ptr);
588
ptr += sizeof (guint32);
590
repeats_until_date = TRUE;
591
} else if (flag32 == END_AFTER_N_OCCURRENCES) {
592
flag32 = *((guint32 *)ptr);
593
ptr += sizeof (guint32);
596
} else if (flag32 == END_NEVER_END) {
597
flag32 = *((guint32 *)ptr);
598
ptr += sizeof (guint32);
602
flag32 = *((guint32 *)ptr);
603
ptr += sizeof (guint32);
604
rt.week_start = get_ical_weekstart (flag32);
606
/* number of exceptions */
607
flag32 = *((guint32 *)ptr);
608
ptr += sizeof (guint32);
610
for (i = 0; i < flag32; ++i) {
612
struct icaltimetype tt, *val;
613
ECalComponentDateTime *dt = g_new0 (ECalComponentDateTime, 1);
615
exdate = *((guint32 *)ptr);
616
ptr += sizeof (guint32);
618
tt = icaltime_from_timet_with_zone (convert_recurrence_minutes_to_timet (exdate), 1, 0);
620
val = g_new0(struct icaltimetype, 1);
621
memcpy (val, &tt, sizeof(struct icaltimetype));
624
dt->tzid = g_strdup ("UTC");
626
exdate_list = g_slist_append (exdate_list, dt);
630
/* number of changed exceptions */
631
flag32 = *((guint32 *)ptr);
632
ptr += sizeof (guint32);
633
/* FIXME: Parse modified instances */
635
ptr += flag32 * sizeof (guint32);
638
flag32 = *((guint32 *)ptr);
639
ptr += sizeof (guint32);
642
flag32 = *((guint32 *)ptr);
643
ptr += sizeof (guint32);
644
if (repeats_until_date) {
645
rt.until = icaltime_from_timet_with_zone (convert_recurrence_minutes_to_timet (flag32), 1, 0);
649
flag32 = *((guint32 *)ptr);
650
ptr += sizeof (guint32);
651
if (flag32 != READER_VERSION2)
655
flag32 = *((guint32 *)ptr);
656
ptr += sizeof (guint32);
657
if (flag32 != WRITER_VERSION2)
660
/* start time in mins */
661
flag32 = *((guint32 *)ptr);
662
ptr += sizeof (guint32);
664
/* end time in mins */
665
flag32 = *((guint32 *)ptr);
666
ptr += sizeof (guint32);
668
/* modified exceptions */
669
flag16 = *((guint16 *)ptr);
670
ptr += sizeof (guint16);
674
/* reserved block1 size - has to be 0 */
675
flag32 = *((guint32 *)ptr);
676
ptr += sizeof (guint32);
680
/* reserved block2 size - has to be 0 */
681
flag32 = *((guint32 *)ptr);
682
ptr += sizeof (guint32);
686
/* Set the recurrence */
693
e_cal_component_set_rrule_list (comp, &l);
696
/* FIXME: this also has modified instances */
697
e_cal_component_set_exdate_list (comp, exdate_list);
699
g_print ("\n== MAPI to ICAL == The recurrence blob data is as follows:\n");
700
for (i = 0; i < ba->len; ++i)
701
g_print ("0x%02X ", ba->data[i]);
702
g_print("\n== End of stream ==\n");
708
compute_startdate (ECalComponent *comp)
710
ECalComponentDateTime dtstart;
713
e_cal_component_get_dtstart (comp, &dtstart);
714
dtstart.value->hour = dtstart.value->minute = dtstart.value->second = 0;
715
flag32 = convert_timet_to_recurrence_minutes (icaltime_as_timet_with_zone (*(dtstart.value), 0));
717
e_cal_component_free_datetime (&dtstart);
723
compute_rdaily_firstdatetime (ECalComponent *comp, guint32 period)
725
return (compute_startdate (comp) % period);
729
compute_rweekly_firstdatetime (ECalComponent *comp, icalrecurrencetype_weekday week_start, guint32 period)
731
ECalComponentDateTime dtstart;
733
int cur_weekday = 0, weekstart_weekday = 0, diff = 0;
736
e_cal_component_get_dtstart (comp, &dtstart);
737
dtstart.value->hour = dtstart.value->minute = dtstart.value->second = 0;
738
cur_weekday = icaltime_day_of_week (*(dtstart.value));
739
t = icaltime_as_timet_with_zone (*(dtstart.value), 0);
740
e_cal_component_free_datetime (&dtstart);
742
switch (week_start) {
743
case ICAL_SUNDAY_WEEKDAY : weekstart_weekday = 1; break;
744
case ICAL_MONDAY_WEEKDAY : weekstart_weekday = 2; break;
745
case ICAL_TUESDAY_WEEKDAY : weekstart_weekday = 3; break;
746
case ICAL_WEDNESDAY_WEEKDAY : weekstart_weekday = 4; break;
747
case ICAL_THURSDAY_WEEKDAY : weekstart_weekday = 5; break;
748
case ICAL_FRIDAY_WEEKDAY : weekstart_weekday = 6; break;
749
case ICAL_SATURDAY_WEEKDAY : weekstart_weekday = 7; break;
750
default : weekstart_weekday = 1; break;
753
diff = cur_weekday - weekstart_weekday;
757
t -= (diff * 24 * 60 * 60);
759
t -= ((diff + 7) * 24 * 60 * 60);
761
flag32 = convert_timet_to_recurrence_minutes (t);
763
return (flag32 % period);
766
/* The most fucked up algorithm ever conceived by (..you know who..) */
768
compute_rmonthly_firstdatetime (ECalComponent *comp, guint32 period)
770
const guint8 dinm[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
771
ECalComponentDateTime dtstart;
772
guint32 flag32, monthindex, i;
774
e_cal_component_get_dtstart (comp, &dtstart);
775
monthindex = (guint32)((((guint64)(12) * (dtstart.value->year - 1601)) + (dtstart.value->month - 1)) % period);
776
e_cal_component_free_datetime (&dtstart);
778
for (flag32 = 0, i = 0; i < monthindex; ++i)
779
flag32 += dinm[(i % 12) + 1] * 24 * 60;
785
calculate_no_of_occurrences (ECalComponent *comp, const struct icalrecurrencetype *rt)
787
ECalComponentDateTime dtstart;
788
icalrecur_iterator *iter;
789
struct icaltimetype next;
792
e_cal_component_get_dtstart (comp, &dtstart);
794
for (iter = icalrecur_iterator_new (*rt, *(dtstart.value)),
795
next = icalrecur_iterator_next(iter);
796
!icaltime_is_null_time(next);
797
next = icalrecur_iterator_next(iter))
800
icalrecur_iterator_free (iter);
801
e_cal_component_free_datetime (&dtstart);
807
compare_guint32 (gconstpointer a, gconstpointer b, gpointer user_data)
809
return (*((guint32 *) a) - *((guint32 *) b));
813
exchange_mapi_cal_util_rrule_to_bin (ECalComponent *comp, GSList *modified_comps)
815
struct icalrecurrencetype *rt;
817
guint32 flag32, end_type;
819
GSList *rrule_list = NULL, *exdate_list = NULL;
820
GByteArray *ba = NULL;
822
if (!e_cal_component_has_recurrences (comp))
825
e_cal_component_get_rrule_list (comp, &rrule_list);
826
e_cal_component_get_exdate_list (comp, &exdate_list);
828
if (g_slist_length (rrule_list) != 1)
831
rt = (struct icalrecurrencetype *)(rrule_list->data);
833
ba = g_byte_array_new ();
836
flag16 = READER_VERSION;
837
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
840
flag16 = WRITER_VERSION;
841
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
843
if (rt->freq == ICAL_DAILY_RECURRENCE) {
844
flag16 = RecurFrequency_Daily;
845
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
847
/* Pattern Type - it would be PatternType_Day since we have only "Daily every N days"
848
* The other type would be parsed as a weekly recurrence.
850
flag16 = PatternType_Day;
851
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
854
flag16 = CAL_DEFAULT;
855
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
858
flag32 = compute_rdaily_firstdatetime (comp, (rt->interval * (60 * 24)));
859
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
862
flag32 = (rt->interval * (60 * 24));
863
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
865
/* This would be 0 for the stuff we handle */
867
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
869
/* No PatternTypeSpecific for PatternType_Day */
871
} else if (rt->freq == ICAL_WEEKLY_RECURRENCE) {
872
flag16 = RecurFrequency_Weekly;
873
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
875
/* Pattern Type - it would be PatternType_Week since we don't support any other type. */
876
flag16 = PatternType_Week;
877
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
880
flag16 = CAL_DEFAULT;
881
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
884
flag32 = compute_rweekly_firstdatetime (comp, rt->week_start, (rt->interval * (60 * 24 * 7)));
885
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
888
flag32 = rt->interval;
889
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
891
/* This would be 0 for the stuff we handle */
893
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
896
for (flag32 = 0x0, i = 0; i < ICAL_BY_DAY_SIZE; ++i) {
897
if (rt->by_day[i] == ICAL_SUNDAY_WEEKDAY)
899
else if (rt->by_day[i] == ICAL_MONDAY_WEEKDAY)
901
else if (rt->by_day[i] == ICAL_TUESDAY_WEEKDAY)
903
else if (rt->by_day[i] == ICAL_WEDNESDAY_WEEKDAY)
904
flag32 |= olWednesday;
905
else if (rt->by_day[i] == ICAL_THURSDAY_WEEKDAY)
906
flag32 |= olThursday;
907
else if (rt->by_day[i] == ICAL_FRIDAY_WEEKDAY)
909
else if (rt->by_day[i] == ICAL_SATURDAY_WEEKDAY)
910
flag32 |= olSaturday;
914
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
916
} else if (rt->freq == ICAL_MONTHLY_RECURRENCE) {
917
guint16 pattern = 0x0; guint32 mask = 0x0, flag = 0x0;
919
flag16 = RecurFrequency_Monthly;
920
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
922
if (rt->by_month_day[0] >= 1 && rt->by_month_day[0] <= 31) {
923
pattern = PatternType_Month;
924
flag = rt->by_month_day[0];
925
} else if (rt->by_month_day[0] == -1) {
926
pattern = PatternType_MonthNth;
927
mask = (olSunday | olMonday | olTuesday | olWednesday | olThursday | olFriday | olSaturday);
928
flag = RecurrenceN_Last;
929
} else if (rt->by_day[0] >= ICAL_SUNDAY_WEEKDAY && rt->by_day[0] <= ICAL_SATURDAY_WEEKDAY) {
930
pattern = PatternType_MonthNth;
931
mask = get_mapi_day (rt->by_day[0]);
932
flag = get_mapi_pos (rt->by_set_pos[0]);
937
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
940
flag16 = CAL_DEFAULT;
941
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
944
flag32 = compute_rmonthly_firstdatetime (comp, rt->interval);
945
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
948
flag32 = rt->interval;
949
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
951
/* This would be 0 for the stuff we handle */
953
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
955
if (pattern == PatternType_Month) {
957
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
960
g_warning ("Possibly setting incorrect values in the stream. ");
961
} else if (pattern == PatternType_MonthNth) {
963
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
966
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
969
g_warning ("Possibly setting incorrect values in the stream. ");
971
g_warning ("Possibly setting incorrect values in the stream. ");
973
} else if (rt->freq == ICAL_YEARLY_RECURRENCE) {
974
flag16 = RecurFrequency_Yearly;
975
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
977
/* Pattern Type - it would be PatternType_Month since we don't support any other type. */
978
flag16 = PatternType_Month;
979
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
982
flag16 = CAL_DEFAULT;
983
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
985
/* FirstDateTime - uses the same function as monthly recurrence */
986
flag32 = compute_rmonthly_firstdatetime (comp, 0xC);
987
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
989
/* INTERVAL - should be 12 for yearly recurrence */
991
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
993
/* This would be 0 for the stuff we handle */
995
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
999
ECalComponentDateTime dtstart;
1000
e_cal_component_get_dtstart (comp, &dtstart);
1001
flag32 = dtstart.value->day;
1002
e_cal_component_free_datetime (&dtstart);
1004
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1008
/* End Type followed by Occurence count */
1009
if (!icaltime_is_null_time (rt->until)) {
1010
flag32 = END_AFTER_DATE;
1011
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1013
flag32 = calculate_no_of_occurrences (comp, rt);
1014
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1016
end_type = END_AFTER_DATE;
1017
} else if (rt->count) {
1018
flag32 = END_AFTER_N_OCCURRENCES;
1019
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1022
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1024
end_type = END_AFTER_N_OCCURRENCES;
1026
flag32 = END_NEVER_END;
1027
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1030
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1032
end_type = END_NEVER_END;
1036
flag32 = get_mapi_weekstart (rt->week_start);
1037
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1039
/* DeletedInstances */
1040
flag32 = g_slist_length (exdate_list);
1041
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1044
guint32 *sorted_list = g_new0(guint32, flag32);
1045
/* FIXME: This should include modified dates */
1046
for (i = 0, l = exdate_list; l; ++i, l = l->next) {
1047
ECalComponentDateTime *dt = (ECalComponentDateTime *)(l->data);
1048
dt->value->hour = dt->value->minute = dt->value->second = 0;
1049
sorted_list[i] = convert_timet_to_recurrence_minutes (icaltime_as_timet_with_zone (*(dt->value), 0));
1052
g_qsort_with_data (sorted_list, flag32, sizeof (guint32), compare_guint32, NULL);
1054
for (i = 0; i < flag32; ++i)
1055
ba = g_byte_array_append (ba, (const guint8 *)&(sorted_list[i]), sizeof (guint32));
1057
g_free (sorted_list);
1060
/* FIXME: Add support for modified instances */
1061
/* ModifiedInstanceCount */
1063
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1068
flag32 = compute_startdate (comp);
1069
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1073
if (end_type == END_NEVER_END)
1074
flag32 = 0x5AE980DF;
1075
else if (end_type == END_AFTER_N_OCCURRENCES) {
1076
ECalComponentDateTime dtstart;
1077
gchar *rrule_str = icalrecurrencetype_as_string_r (rt);
1078
time_t *array = g_new0 (time_t, rt->count);
1080
e_cal_component_get_dtstart (comp, &dtstart);
1081
dtstart.value->hour = dtstart.value->minute = dtstart.value->second = 0;
1083
icalrecur_expand_recurrence (rrule_str, icaltime_as_timet_with_zone (*(dtstart.value), 0), rt->count, array);
1085
flag32 = convert_timet_to_recurrence_minutes (array[(rt->count) - 1]);
1089
e_cal_component_free_datetime (&dtstart);
1090
} else if (end_type == END_AFTER_DATE) {
1091
struct icaltimetype until;
1092
memcpy (&until, &(rt->until), sizeof(struct icaltimetype));
1093
until.hour = until.minute = until.second = 0;
1094
flag32 = convert_timet_to_recurrence_minutes (icaltime_as_timet_with_zone (until, 0));
1098
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1100
/* Reader Version 2 */
1101
flag32 = READER_VERSION2;
1102
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1104
/* Writer Version 2 */
1105
flag32 = WRITER_VERSION2;
1106
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1108
/* StartTimeOffset */
1110
ECalComponentDateTime dtstart;
1111
e_cal_component_get_dtstart (comp, &dtstart);
1112
flag32 = (dtstart.value->hour * 60) + dtstart.value->minute;
1113
e_cal_component_free_datetime (&dtstart);
1115
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1119
ECalComponentDateTime dtend;
1120
e_cal_component_get_dtend (comp, &dtend);
1121
flag32 = (dtend.value->hour * 60) + dtend.value->minute;
1122
e_cal_component_free_datetime (&dtend);
1124
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1126
/* FIXME: Add support for modified instances */
1127
/* ModifiedExceptionCount */
1129
ba = g_byte_array_append (ba, (const guint8 *)&flag16, sizeof (guint16));
1131
/* FIXME: Add the ExceptionInfo here */
1133
/* Reserved Block 1 Size */
1135
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1137
/* FIXME: Add the ExtendedExceptionInfo here */
1139
/* Reserved Block 2 Size */
1141
ba = g_byte_array_append (ba, (const guint8 *)&flag32, sizeof (guint32));
1144
e_cal_component_free_exdate_list (exdate_list);
1145
e_cal_component_free_recur_list (rrule_list);
1147
g_print ("\n== ICAL to MAPI == The recurrence blob data is as follows:\n");
1148
for (i = 0; i < ba->len; ++i)
1149
g_print ("0x%02X ", ba->data[i]);
1150
g_print("\n== End of stream ==\n");