Commit a modified version of Matthieu Patou <mat@matws.net> path on disabling tdb2...
[jelmer/openchange-proposed.git/.git] / libexchange2ical / exchange2ical_property.c
1 /*
2    Convert Exchange appointments and meetings to ICAL files
3
4    OpenChange Project
5
6    Copyright (C) Julien Kerihuel 2008
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "libexchange2ical/libexchange2ical.h"
23 #include <ldb.h>
24
25 struct RRULE_byday {
26         uint16_t        DayOfWeek;
27         const char      *DayName;
28 };
29
30 static const struct RRULE_byday RRULE_byday[] = {
31         { 0x0000,       "SU" },
32         { 0x0001,       "MO" },
33         { 0x0002,       "TU" },
34         { 0x0003,       "WE" },
35         { 0x0004,       "TH" },
36         { 0x0005,       "FR" },
37         { 0x0006,       "SA" },
38         { 0x0007,       NULL }
39 };
40
41 static const char *get_filename(const char *filename)
42 {
43         const char *substr;
44
45         if (!filename) return NULL;
46
47         substr = rindex(filename, '/');
48         if (substr) return substr;
49
50         return filename;
51 }
52
53
54 void ical_property_ATTACH(struct exchange2ical *exchange2ical)
55 {
56         mapi_object_t                   obj_tb_attach;
57         mapi_object_t                   obj_attach;
58         mapi_object_t                   obj_stream;
59         struct SRowSet                  rowset_attach;
60         struct SPropTagArray            *SPropTagArray = NULL;
61         const uint32_t                  *attach_num = NULL;
62         struct SPropValue               *lpProps;
63         enum MAPISTATUS                 retval;
64         unsigned int                    i;
65         uint32_t                        count;
66         struct SRow                     aRow2;
67
68         
69         mapi_object_init(&obj_tb_attach);
70         retval = GetAttachmentTable(&exchange2ical->obj_message, &obj_tb_attach);
71         if (retval == MAPI_E_SUCCESS) {
72                 SPropTagArray = set_SPropTagArray(exchange2ical->mem_ctx, 0x1, PR_ATTACH_NUM);
73                 retval = SetColumns(&obj_tb_attach, SPropTagArray);
74                 MAPIFreeBuffer(SPropTagArray);
75                 retval = QueryRows(&obj_tb_attach, 0xa, TBL_ADVANCE, &rowset_attach);
76                 
77                 for (i = 0; i < rowset_attach.cRows; i++) {
78                         attach_num = (const uint32_t *)find_SPropValue_data(&(rowset_attach.aRow[i]), PR_ATTACH_NUM);
79                         retval = OpenAttach(&exchange2ical->obj_message, *attach_num, &obj_attach);
80
81                         if (retval == MAPI_E_SUCCESS) {
82
83                                 SPropTagArray = set_SPropTagArray(exchange2ical->mem_ctx, 0x7,
84                                                                           PR_ATTACH_FILENAME,
85                                                                           PR_ATTACH_LONG_FILENAME,
86                                                                           PR_ATTACH_METHOD,
87                                                                           PR_ATTACHMENT_FLAGS,
88                                                                           PR_ATTACHMENT_HIDDEN,
89                                                                           PR_ATTACH_MIME_TAG,
90                                                                           PR_ATTACH_DATA_BIN
91                                                                           );
92                                                                           
93                                 lpProps = talloc_zero(exchange2ical->mem_ctx, struct SPropValue);
94                                 retval = GetProps(&obj_attach, MAPI_UNICODE, SPropTagArray, &lpProps, &count);
95                                 MAPIFreeBuffer(SPropTagArray);
96                                 if (retval == MAPI_E_SUCCESS) {
97
98                                         uint32_t                *attachmentFlags = NULL;
99                                         uint32_t                *attachMethod = NULL;
100                                         uint8_t                 *attachmentHidden = NULL;
101                                         const char              *data = NULL;
102                                         const char              *fmttype = NULL;
103                                         const char              *attach_filename = NULL;
104                                         DATA_BLOB               body;
105                                         icalattach              *icalattach = NULL;
106                                         icalproperty            *prop = NULL;
107                                         icalparameter           *param = NULL;
108                                                 
109                                         
110                                         aRow2.ulAdrEntryPad = 0;
111                                         aRow2.cValues = count;
112                                         aRow2.lpProps = lpProps;
113                                         
114                                         attachmentFlags  = octool_get_propval(&aRow2, PR_ATTACHMENT_FLAGS);
115                                         attachMethod     = octool_get_propval(&aRow2, PR_ATTACH_METHOD);
116                                         attachmentHidden = octool_get_propval(&aRow2, PR_ATTACHMENT_HIDDEN);
117
118                                         if(attachmentFlags && !(*attachmentFlags & 0x00000007) 
119                                                 && (*attachMethod == 0x00000001) 
120                                                 && (!attachmentHidden || !(*attachmentHidden))) {
121
122                                                 /* Get data of attachment */
123                                                 retval = OpenStream(&obj_attach, PR_ATTACH_DATA_BIN, 0, &obj_stream);
124                                                 retval = octool_get_stream(exchange2ical->mem_ctx, &obj_stream, &body);
125                                                 data=ldb_base64_encode(exchange2ical->mem_ctx, (const char *)body.data, body.length);
126                                                 
127                                                 /*Create a new icalattach from above data*/
128 #if HAVE_ICAL_0_46
129                                                 /* the function signature for icalattach_new_from_data() changed in 0.46, released 2010-08-30 */
130                                                 /* we can switch to just using the new signature after everyone has had a reasonable chance to update (say end of 2011) */
131                                                 icalattach = icalattach_new_from_data(data, 0, 0);
132 #else
133                                                 icalattach = icalattach_new_from_data((unsigned char *)data,0,0);
134 #endif
135                                                 /*Add attach property to vevent component*/
136                                                 prop = icalproperty_new_attach(icalattach);
137                                                 icalcomponent_add_property(exchange2ical->vevent, prop);
138
139                                                 /* Attachment filename for X-FILENAME parameter*/
140                                                 attach_filename = get_filename(octool_get_propval(&aRow2, PR_ATTACH_LONG_FILENAME));
141                                                 if (!attach_filename || (attach_filename && !strcmp(attach_filename, ""))) {
142                                                         attach_filename = get_filename(octool_get_propval(&aRow2, PR_ATTACH_FILENAME));
143                                                 }
144                                                 
145                                                 /* fmttype parameter */
146                                                 fmttype = (const char *) octool_get_propval(&aRow2, PR_ATTACH_MIME_TAG);
147                                                 if(fmttype) {
148                                                         param = icalparameter_new_fmttype(fmttype);
149                                                         icalproperty_add_parameter(prop, param);
150                                                 }
151                                                 
152                                                 /* ENCODING parameter */
153                                                 param =icalparameter_new_encoding(ICAL_ENCODING_BASE64);
154                                                 icalproperty_add_parameter(prop,param);
155                                                 
156                                                 /* VALUE parameter */
157                                                 param=icalparameter_new_value(ICAL_VALUE_BINARY);
158                                                 icalproperty_add_parameter(prop,param);
159                                                 
160                                                 /* X-FILENAME parameter */
161                                                 param = icalparameter_new_x(attach_filename);
162                                                 icalparameter_set_xname(param,"X-FILENAME");
163                                                 icalproperty_add_parameter(prop,param);
164                                         }
165                                         MAPIFreeBuffer(lpProps);
166                                 }
167                         }
168                 }
169         }
170         mapi_object_release(&obj_tb_attach);
171 }
172
173
174 // TODO: check this - need an example
175 void ical_property_ATTENDEE(struct exchange2ical *exchange2ical)
176 {
177         uint32_t        i;
178         const char      *smtp;
179         const char      *display_name;
180         uint32_t        *RecipientFlags;
181         uint32_t        *RecipientType;
182         uint32_t        *TrackStatus;
183         struct SRowSet  *SRowSet;
184
185         /* Sanity check */
186         if (!exchange2ical->apptStateFlags) return;
187         if (!(*exchange2ical->apptStateFlags & 0x1)) return;
188         SRowSet = &(exchange2ical->Recipients.SRowSet);
189
190         /* Loop over the recipient table */
191         for (i = 0; i < SRowSet->cRows; i++) {
192                 smtp = (const char *) octool_get_propval(&(SRowSet->aRow[i]), PR_SMTP_ADDRESS);
193                 display_name = (const char *) octool_get_propval(&(SRowSet->aRow[i]), PR_RECIPIENT_DISPLAY_NAME);
194                 RecipientFlags = (uint32_t *) octool_get_propval(&(SRowSet->aRow[i]), PR_RECIPIENT_FLAGS);
195                 RecipientType = (uint32_t *) octool_get_propval(&(SRowSet->aRow[i]), PR_RECIPIENT_TYPE);
196                 TrackStatus  = (uint32_t *) octool_get_propval(&(SRowSet->aRow[i]), PR_RECIPIENT_TRACKSTATUS);
197
198
199                 if (RecipientFlags && !(*RecipientFlags & 0x20) && !(*RecipientFlags & 0x2) &&
200                     (RecipientType && *RecipientType)) {
201                         icalproperty *prop;
202                         icalparameter *cn;
203                         icalparameter *participantType;
204                         enum icalparameter_partstat     partstat = ICAL_PARTSTAT_NONE;
205
206                         if (smtp) {
207                                 char *mailtoURL;
208                                 mailtoURL = talloc_strdup(exchange2ical->mem_ctx, "mailto:");
209                                 mailtoURL = talloc_strdup_append(mailtoURL, smtp);
210                                 prop = icalproperty_new_attendee(mailtoURL);
211                                 icalcomponent_add_property(exchange2ical->vevent, prop);
212                         } else {
213                                 prop = icalproperty_new_attendee("invalid:nomail");
214                                 icalcomponent_add_property(exchange2ical->vevent, prop);
215                         }
216
217                         if (display_name) {
218                                 cn = icalparameter_new_cn(display_name);
219                                 icalproperty_add_parameter(prop, cn);
220                         }
221
222                         if (*RecipientType == 0x3) {
223                                 icalparameter *cutype = icalparameter_new_cutype(ICAL_CUTYPE_RESOURCE);
224                                 icalproperty_add_parameter(prop, cutype);
225                         }
226
227                         switch (*RecipientType) {
228                         case 0x00000002:
229                                 participantType = icalparameter_new_role(ICAL_ROLE_OPTPARTICIPANT);
230                                 icalproperty_add_parameter(prop, participantType);
231                                 break;
232                         case 0x00000003:
233                                 participantType = icalparameter_new_role(ICAL_ROLE_NONPARTICIPANT);
234                                 icalproperty_add_parameter(prop, participantType);
235                                 break;
236                         }
237
238                 
239                         
240                         if((exchange2ical->method==ICAL_METHOD_REPLY) || (exchange2ical->method==ICAL_METHOD_COUNTER)){
241                                 partstat = exchange2ical->partstat;     
242                         }else if(exchange2ical->method==ICAL_METHOD_PUBLISH){
243                                 if(TrackStatus){
244                                         partstat = get_ical_partstat_from_status(*TrackStatus);
245                                 }else if(exchange2ical->ResponseStatus){
246                                         partstat = get_ical_partstat_from_status(*exchange2ical->ResponseStatus);
247                                 }
248                         }
249                         
250                         if (partstat != ICAL_PARTSTAT_NONE) {
251                                 icalparameter *param;
252                                 param = icalparameter_new_partstat(partstat);
253                                 icalproperty_add_parameter(prop, param);
254                         }
255
256                         if (exchange2ical->ResponseRequested) {
257                                 icalparameter *rsvp;
258                                 if (*(exchange2ical->ResponseRequested)) {
259                                         rsvp = icalparameter_new_rsvp(ICAL_RSVP_TRUE);
260                                 } else {
261                                         rsvp = icalparameter_new_rsvp(ICAL_RSVP_FALSE);
262                                 }
263                                 icalproperty_add_parameter(prop, rsvp);
264                         }
265                 }
266         }
267 }
268
269
270 void ical_property_CATEGORIES(struct exchange2ical *exchange2ical)
271 {
272         uint32_t        i;
273         icalproperty    *prop;
274
275         /* Sanity check */
276         if (!exchange2ical->Keywords) return;
277         if (!exchange2ical->Keywords->cValues) return;
278
279         for (i = 0; i < exchange2ical->Keywords->cValues; i++) {
280                 prop = icalproperty_new_categories(exchange2ical->Keywords->lppszA[i]); 
281                 icalcomponent_add_property(exchange2ical->vevent, prop);
282         }
283
284 }
285
286
287 void ical_property_CLASS(struct exchange2ical *exchange2ical)
288 {
289         icalproperty    *prop;
290
291         /* Sanity check */
292         if (!exchange2ical->sensitivity) return;
293
294         prop = icalproperty_new_class(get_ical_class(*exchange2ical->sensitivity));
295         icalcomponent_add_property(exchange2ical->vevent, prop);
296 }
297
298
299 void ical_property_CONTACT(struct exchange2ical *exchange2ical)
300 {
301         icalproperty    *prop;
302         uint32_t        i;
303
304         /* Sanity check */
305         if (!exchange2ical->Contacts) return;
306         if (!exchange2ical->Contacts->cValues) return;
307
308         for (i = 0; i < exchange2ical->Contacts->cValues; i++) {
309                 prop = icalproperty_new_contact(exchange2ical->Contacts->lppszA[i]);
310                 icalcomponent_add_property(exchange2ical->vevent, prop);
311         }
312 }
313
314
315 void ical_property_CREATED(struct exchange2ical *exchange2ical)
316 {
317         icalproperty            *prop;
318         struct icaltimetype     icaltime;
319
320         /* Sanity check */
321         if (!exchange2ical->created) return;
322
323         icaltime = get_icaltime_from_FILETIME_UTC(exchange2ical->created);
324
325         prop = icalproperty_new_created(icaltime);
326         icalcomponent_add_property(exchange2ical->vevent, prop);
327 }
328
329 void ical_property_DTSTART(struct exchange2ical *exchange2ical)
330 {
331         icalproperty            *prop;
332         icalparameter           *tzid;
333         struct icaltimetype     icaltime;
334
335         /* Sanity check */
336         if (!exchange2ical->apptStartWhole) return;
337
338         /* If this is an all-day appointment */
339         if (exchange2ical->apptSubType && (*exchange2ical->apptSubType == 0x1)) {
340                 icaltime = get_icaldate_from_FILETIME(exchange2ical->apptStartWhole);
341                 prop = icalproperty_new_dtstart(icaltime);
342                 icalcomponent_add_property(exchange2ical->vevent, prop);
343         } else {
344                 if (exchange2ical->TimeZoneDesc) {
345                         icaltime = get_icaltime_from_FILETIME(exchange2ical->apptStartWhole);
346                         prop = icalproperty_new_dtstart(icaltime);
347                         icalcomponent_add_property(exchange2ical->vevent, prop);
348                         tzid = icalparameter_new_tzid(exchange2ical->TimeZoneDesc);
349                         icalproperty_add_parameter(prop, tzid);
350                 } else {
351                         icaltime = get_icaltime_from_FILETIME_UTC(exchange2ical->apptStartWhole);
352                         prop = icalproperty_new_dtstart(icaltime);
353                         icalcomponent_add_property(exchange2ical->vevent, prop);
354                 }
355         
356                 
357         }
358 }
359
360
361 void ical_property_DTEND(struct exchange2ical *exchange2ical)
362 {
363         icalproperty            *prop;
364         icalparameter           *tzid;
365         struct icaltimetype     icaltime;
366
367         /* Sanity check */
368         if (!exchange2ical->apptEndWhole) return;
369
370         /* If this is an all-day appointment */
371         if (exchange2ical->apptSubType && (*exchange2ical->apptSubType == 0x1)) {
372                 icaltime = get_icaldate_from_FILETIME(exchange2ical->apptEndWhole);
373                 prop = icalproperty_new_dtend(icaltime);
374                 icalcomponent_add_property(exchange2ical->vevent, prop);
375         } else {
376                 if (exchange2ical->TimeZoneDesc) {
377                         icaltime = get_icaltime_from_FILETIME(exchange2ical->apptEndWhole);
378                         prop = icalproperty_new_dtend(icaltime);
379                         icalcomponent_add_property(exchange2ical->vevent, prop);
380                         tzid = icalparameter_new_tzid(exchange2ical->TimeZoneDesc);
381                         icalproperty_add_parameter(prop, tzid);
382                 } else {
383                         icaltime = get_icaltime_from_FILETIME_UTC(exchange2ical->apptEndWhole);
384                         prop = icalproperty_new_dtend(icaltime);
385                         icalcomponent_add_property(exchange2ical->vevent, prop);
386                 }
387                 
388         }
389 }
390
391
392 void ical_property_DTSTAMP(struct exchange2ical *exchange2ical)
393 {
394         icalproperty            *prop;
395         struct icaltimetype     icaltime;
396         struct tm               *tm;
397         icalparameter           *tzid;
398         time_t                  t;
399
400         /* Sanity check */
401         /*If OwnerCriticalChange field is null, get time system time*/
402         if (!exchange2ical->OwnerCriticalChange) {
403                 t=time(NULL);
404                 tm = gmtime(&t);
405                 icaltime = get_icaltimetype_from_tm_UTC(tm);
406                 prop = icalproperty_new_dtstamp(icaltime);
407                 icalcomponent_add_property(exchange2ical->vevent, prop);
408                 return;
409         } else {
410               icaltime = get_icaltime_from_FILETIME_UTC(exchange2ical->OwnerCriticalChange);
411               prop = icalproperty_new_dtstamp(icaltime);
412               icalcomponent_add_property(exchange2ical->vevent, prop);
413               if (exchange2ical->TimeZoneDesc) {
414                         tzid = icalparameter_new_tzid(exchange2ical->TimeZoneDesc);
415                         icalproperty_add_parameter(prop, tzid);
416                 }
417         }
418 }
419
420
421 void ical_property_DESCRIPTION(struct exchange2ical *exchange2ical)
422 {
423         icalproperty    *prop;
424
425         if (exchange2ical->method == ICAL_METHOD_REPLY) return;
426         if (!exchange2ical->body) return;
427
428         prop = icalproperty_new_description(exchange2ical->body);
429         icalcomponent_add_property(exchange2ical->vevent, prop);
430 }
431
432
433 void ical_property_EXDATE(struct exchange2ical *exchange2ical)
434 {
435         uint32_t        i;
436         uint32_t        j;
437         uint8_t         modified;
438         struct icaltimetype     icaltime;
439         struct icaltimetype     dttime;
440
441         icalproperty    *prop;
442         struct RecurrencePattern *pat = exchange2ical->RecurrencePattern;
443
444         /* Sanity check */
445         if (exchange2ical->Recurring && (*exchange2ical->Recurring == 0x0)) return;
446         if (!pat) return;
447         if (!pat->DeletedInstanceCount) return;
448
449         for (i = 0; i < pat->DeletedInstanceCount; i++) {
450                 modified=0;
451                 if(pat->ModifiedInstanceDates && pat->ModifiedInstanceCount){
452                         for(j=0; j < pat->ModifiedInstanceCount; j++){
453                                 if(pat->ModifiedInstanceDates[j]==pat->DeletedInstanceDates[i]){
454                                         modified=1;
455                                         break;
456                                 }
457                         }
458                 }
459                 /* If this is an all-day appointment */
460                 if (!modified && exchange2ical->apptSubType && (*exchange2ical->apptSubType == 0x1)) {
461                         struct tm       tm;
462                         tm = get_tm_from_minutes_UTC(pat->DeletedInstanceDates[i]);
463                         icaltime= get_icaldate_from_tm(&tm);
464                         prop = icalproperty_new_exdate(icaltime);
465                         icalcomponent_add_property(exchange2ical->vevent, prop);
466                 } else if (!modified){
467                         /* number of minutes between midnight of the specified
468                         * day and midnight, January 1, 1601 */
469                         struct tm       tm;
470                         tm = get_tm_from_minutes_UTC(pat->DeletedInstanceDates[i]);
471                         icaltime= get_icaltimetype_from_tm(&tm);
472
473                         if (exchange2ical->TimeZoneDesc) {
474                                 /*Get time from dtstart*/
475                                 if (exchange2ical->apptEndWhole){
476                                         dttime = get_icaltime_from_FILETIME(exchange2ical->apptStartWhole);
477                                         icaltime.hour   = dttime.hour;
478                                         icaltime.minute = dttime.minute;
479                                 }
480
481                                 prop = icalproperty_new_exdate(icaltime);
482                                 icalcomponent_add_property(exchange2ical->vevent, prop);
483                                 icalparameter *tzid = icalparameter_new_tzid(exchange2ical->TimeZoneDesc);
484                                 icalproperty_add_parameter(prop, tzid);
485                         } else {
486                                 /*Get time from dtstart*/
487                                 icaltime.is_utc = 1;
488                                 if (exchange2ical->apptEndWhole){
489                                         dttime = get_icaltime_from_FILETIME_UTC(exchange2ical->apptStartWhole);
490                                         icaltime.hour   = dttime.hour;
491                                         icaltime.minute = dttime.minute;
492                                 }
493                                 prop = icalproperty_new_exdate(icaltime);
494                                 icalcomponent_add_property(exchange2ical->vevent, prop);
495                         }
496                 }               
497                 
498         }
499 }
500
501
502 void ical_property_LAST_MODIFIED(struct exchange2ical *exchange2ical)
503 {
504         icalproperty            *prop;
505         struct icaltimetype     icaltime;
506         icalparameter           *tzid;
507
508
509         /* Sanity check */
510         if (!exchange2ical->LastModified) return;
511         if (exchange2ical->TimeZoneDesc) {
512                 icaltime=get_icaltime_from_FILETIME(exchange2ical->LastModified);
513                 prop = icalproperty_new_lastmodified(icaltime);
514                 tzid = icalparameter_new_tzid(exchange2ical->TimeZoneDesc);
515                 icalproperty_add_parameter(prop, tzid);
516         } else {
517                 icaltime=get_icaltime_from_FILETIME_UTC(exchange2ical->LastModified);
518                 prop = icalproperty_new_lastmodified(icaltime);
519         }
520         icalcomponent_add_property(exchange2ical->vevent, prop);
521 }
522
523
524 void ical_property_LOCATION(struct exchange2ical *exchange2ical)
525 {
526         icalproperty *prop;
527         /* Sanity check */
528         if (!exchange2ical->Location) return;
529
530         prop = icalproperty_new_location(exchange2ical->Location);
531         icalcomponent_add_property(exchange2ical->vevent, prop);
532 }
533
534
535 void ical_property_ORGANIZER(struct exchange2ical *exchange2ical)
536 {
537         const char      *smtp;
538         const char      *display_name;
539         uint32_t        *RecipientFlags;
540         uint32_t        *RecipientType;
541         uint32_t        i;
542         struct SRowSet  *SRowSet;
543
544         /* Sanity check */
545         if (!exchange2ical->apptStateFlags) return;
546         if (!(*exchange2ical->apptStateFlags & 0x1)) return;
547
548         SRowSet = &(exchange2ical->Recipients.SRowSet);
549
550         /* Loop over the recipient table */
551         for (i = 0; i < SRowSet->cRows; i++) {
552                 smtp = (const char *) octool_get_propval(&(SRowSet->aRow[i]), PR_SMTP_ADDRESS);
553                 display_name = (const char *) octool_get_propval(&(SRowSet->aRow[i]), PR_RECIPIENT_DISPLAY_NAME);
554                 RecipientFlags = (uint32_t *) octool_get_propval(&(SRowSet->aRow[i]), PR_RECIPIENT_FLAGS);
555                 RecipientType = (uint32_t *) octool_get_propval(&(SRowSet->aRow[i]), PR_RECIPIENT_TYPE);
556
557                 if (RecipientFlags && !(*RecipientFlags & 0x20) &&
558                     ((*RecipientFlags & 0x2) || (RecipientType && !*RecipientType))) {
559                         icalproperty *prop;
560                         icalparameter *cn;
561
562                         if (smtp) {
563                                 char *mailtoURL;
564                                 mailtoURL = talloc_strdup(exchange2ical->mem_ctx, "mailto:");
565                                 mailtoURL = talloc_strdup_append(mailtoURL, smtp);
566                                 prop = icalproperty_new_organizer(mailtoURL);
567                                 icalcomponent_add_property(exchange2ical->vevent, prop);
568                                 talloc_free(mailtoURL);
569                         } else {
570                                 prop = icalproperty_new_organizer("invalid:nomail");
571                                 icalcomponent_add_property(exchange2ical->vevent, prop);
572                         }
573
574                         if (display_name) {
575                                 cn = icalparameter_new_cn(display_name);
576                                 icalproperty_add_parameter(prop, cn);
577                         }
578                 }
579         }
580 }
581
582
583 void ical_property_PRIORITY(struct exchange2ical *exchange2ical)
584 {
585         icalproperty *prop;
586         /* Sanity check */
587         if (!exchange2ical->Importance) return;
588
589         switch (*exchange2ical->Importance) {
590         case 0x00000000:
591                 prop = icalproperty_new_priority(9);
592                 break;
593         case 0x00000001:
594                 prop = icalproperty_new_priority(5);
595                 break;
596         case 0x00000002:
597                 prop = icalproperty_new_priority(1);
598                 break;
599         default:
600                 prop = icalproperty_new_priority(5);
601         }
602         icalcomponent_add_property(exchange2ical->vevent, prop);
603 }
604
605
606 void ical_property_RRULE_Daily(struct exchange2ical *exchange2ical)
607 {
608         struct icalrecurrencetype recurrence;
609         icalproperty *prop;
610         struct RecurrencePattern *pat = exchange2ical->RecurrencePattern;
611
612
613         icalrecurrencetype_clear(&recurrence);
614         recurrence.freq = ICAL_DAILY_RECURRENCE;
615         recurrence.interval = (pat->Period / 1440);
616
617         if (pat->EndType == END_AFTER_N_OCCURRENCES || pat->EndType == END_AFTER_DATE) {
618                 recurrence.count = pat->OccurrenceCount;
619         }
620         prop = icalproperty_new_rrule(recurrence);
621         icalcomponent_add_property(exchange2ical->vevent, prop);
622 }
623
624
625 void ical_property_RRULE_Weekly(struct exchange2ical *exchange2ical)
626 {
627         struct icalrecurrencetype recurrence;
628         icalproperty *prop;
629         struct RecurrencePattern *pat = exchange2ical->RecurrencePattern;
630         uint32_t rdfDaysBitmask = pat->PatternTypeSpecific.WeekRecurrencePattern;
631         short idx = 0;
632
633         icalrecurrencetype_clear(&recurrence);
634         recurrence.freq = ICAL_WEEKLY_RECURRENCE;
635         recurrence.interval = pat->Period;
636         
637         if(pat->Period > 1){
638                 switch(pat->FirstDOW){
639                         case FirstDOW_Sunday:
640                                 recurrence.week_start=ICAL_SUNDAY_WEEKDAY;
641                                 break;
642                         case FirstDOW_Monday:
643                                 recurrence.week_start=ICAL_MONDAY_WEEKDAY;
644                                 break;
645                         case FirstDOW_Tuesday:
646                                 recurrence.week_start=ICAL_TUESDAY_WEEKDAY;
647                                 break;
648                         case FirstDOW_Wednesday:
649                                 recurrence.week_start=ICAL_WEDNESDAY_WEEKDAY;
650                                 break;
651                         case FirstDOW_Thursday:
652                                 recurrence.week_start=ICAL_THURSDAY_WEEKDAY;
653                                 break;
654                         case FirstDOW_Friday:
655                                 recurrence.week_start=ICAL_FRIDAY_WEEKDAY;
656                                 break;
657                         case FirstDOW_Saturday:
658                                 recurrence.week_start=ICAL_SATURDAY_WEEKDAY;
659                                 break;
660                 }
661         }
662         
663         if (rdfDaysBitmask & Su) {
664                 recurrence.by_day[idx] = ICAL_SUNDAY_WEEKDAY;
665                 ++idx;
666         }
667         if (rdfDaysBitmask & M) {
668                 recurrence.by_day[idx] = ICAL_MONDAY_WEEKDAY;
669                 ++idx;
670         }
671         if (rdfDaysBitmask & Tu) {
672                 recurrence.by_day[idx] = ICAL_TUESDAY_WEEKDAY;
673                 ++idx;
674         }
675         if (rdfDaysBitmask & W) {
676                 recurrence.by_day[idx] = ICAL_WEDNESDAY_WEEKDAY;
677                 ++idx;
678         }
679         if (rdfDaysBitmask & Th) {
680                 recurrence.by_day[idx] = ICAL_THURSDAY_WEEKDAY;
681                 ++idx;
682         }
683         if (rdfDaysBitmask & F) {
684                 recurrence.by_day[idx] = ICAL_FRIDAY_WEEKDAY;
685                 ++idx;
686         }
687         if (rdfDaysBitmask & Sa) {
688                 recurrence.by_day[idx] = ICAL_FRIDAY_WEEKDAY;
689                 ++idx;
690         }
691         recurrence.by_day[idx] = ICAL_RECURRENCE_ARRAY_MAX;
692
693         if (pat->EndType == END_AFTER_N_OCCURRENCES || pat->EndType == END_AFTER_DATE) {
694                 recurrence.count = pat->OccurrenceCount;
695         }
696
697         prop = icalproperty_new_rrule(recurrence);
698         icalcomponent_add_property(exchange2ical->vevent, prop);
699 }
700
701
702 void ical_property_RRULE_Monthly(struct exchange2ical *exchange2ical)
703 {
704         struct icalrecurrencetype recurrence;
705         icalproperty *prop;
706         struct RecurrencePattern *pat = exchange2ical->RecurrencePattern;
707         uint32_t day = pat->PatternTypeSpecific.Day;
708
709         icalrecurrencetype_clear(&recurrence);
710         recurrence.freq = ICAL_MONTHLY_RECURRENCE;
711         recurrence.interval = pat->Period;
712
713         if (day == 0x0000001F) {
714                 recurrence.by_month_day[0] = -1;
715         } else {
716                 recurrence.by_month_day[0] = day;
717         }
718         recurrence.by_month_day[1] = ICAL_RECURRENCE_ARRAY_MAX;
719
720         if (pat->EndType == END_AFTER_N_OCCURRENCES || pat->EndType == END_AFTER_DATE) {
721                 recurrence.count = pat->OccurrenceCount;
722         }
723
724         prop = icalproperty_new_rrule(recurrence);
725         icalcomponent_add_property(exchange2ical->vevent, prop);
726 }
727
728
729 void ical_property_RRULE_NthMonthly(struct exchange2ical *exchange2ical)
730 {
731         struct icalrecurrencetype recurrence;
732         icalproperty *prop;
733         struct RecurrencePattern *pat = exchange2ical->RecurrencePattern;
734         uint32_t rdfDaysBitmask = pat->PatternTypeSpecific.MonthRecurrencePattern.WeekRecurrencePattern;
735         short idx = 0;
736         enum RecurrenceN setpos = pat->PatternTypeSpecific.MonthRecurrencePattern.N;
737
738         icalrecurrencetype_clear(&recurrence);
739         recurrence.freq = ICAL_MONTHLY_RECURRENCE;
740         recurrence.interval = pat->Period;
741
742         if (rdfDaysBitmask & Su) {
743                 recurrence.by_day[idx] = ICAL_SUNDAY_WEEKDAY;
744                 ++idx;
745         }
746         if (rdfDaysBitmask & M) {
747                 recurrence.by_day[idx] = ICAL_MONDAY_WEEKDAY;
748                 ++idx;
749         }
750         if (rdfDaysBitmask & Tu) {
751                 recurrence.by_day[idx] = ICAL_TUESDAY_WEEKDAY;
752                 ++idx;
753         }
754         if (rdfDaysBitmask & W) {
755                 recurrence.by_day[idx] = ICAL_WEDNESDAY_WEEKDAY;
756                 ++idx;
757         }
758         if (rdfDaysBitmask & Th) {
759                 recurrence.by_day[idx] = ICAL_THURSDAY_WEEKDAY;
760                 ++idx;
761         }
762         if (rdfDaysBitmask & F) {
763                 recurrence.by_day[idx] = ICAL_FRIDAY_WEEKDAY;
764                 ++idx;
765         }
766         if (rdfDaysBitmask & Sa) {
767                 recurrence.by_day[idx] = ICAL_FRIDAY_WEEKDAY;
768                 ++idx;
769         }
770         recurrence.by_day[idx] = ICAL_RECURRENCE_ARRAY_MAX;
771
772         if (setpos == RecurrenceN_First) {
773                 recurrence.by_set_pos[0] = 1;
774                 recurrence.by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
775         } else if (setpos == RecurrenceN_Second) {
776                 recurrence.by_set_pos[0] = 2;
777                 recurrence.by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
778         } else if (setpos == RecurrenceN_Third) {
779                 recurrence.by_set_pos[0] = 3;
780                 recurrence.by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
781         } else if (setpos == RecurrenceN_Fourth) {
782                 recurrence.by_set_pos[0] = 4;
783                 recurrence.by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
784         } else if (setpos == RecurrenceN_Last) {
785                 recurrence.by_set_pos[0] = -1;
786                 recurrence.by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
787         }
788
789         if (pat->EndType == END_AFTER_N_OCCURRENCES || pat->EndType == END_AFTER_DATE) {
790                 recurrence.count = pat->OccurrenceCount;
791         }
792
793         prop = icalproperty_new_rrule(recurrence);
794         icalcomponent_add_property(exchange2ical->vevent, prop);
795 }
796
797
798 void ical_property_RRULE_Yearly(struct exchange2ical *exchange2ical)
799 {
800         struct icalrecurrencetype recurrence;
801         icalproperty *prop;
802         struct RecurrencePattern *pat = exchange2ical->RecurrencePattern;
803         uint32_t day = pat->PatternTypeSpecific.Day;
804         struct icaltimetype icaltime;
805
806         icalrecurrencetype_clear(&recurrence);
807         recurrence.freq = ICAL_YEARLY_RECURRENCE;
808         recurrence.interval = (pat->Period / 12);
809
810         if (day == 0x0000001F) {
811                 recurrence.by_month_day[0] = -1;
812         } else {
813                 recurrence.by_month_day[0] = day;
814         }
815         recurrence.by_month_day[1] = ICAL_RECURRENCE_ARRAY_MAX;
816
817         icaltime = get_icaltime_from_FILETIME_UTC(exchange2ical->apptStartWhole);
818         recurrence.by_month[0] = icaltime.month;
819         recurrence.by_month[1] = ICAL_RECURRENCE_ARRAY_MAX;
820
821
822         
823         if (pat->EndType == END_AFTER_N_OCCURRENCES || pat->EndType == END_AFTER_DATE) {
824                 recurrence.count = pat->OccurrenceCount;
825         } 
826         
827         prop = icalproperty_new_rrule(recurrence);
828         icalcomponent_add_property(exchange2ical->vevent, prop);
829 }
830
831 void ical_property_RRULE_NthYearly(struct exchange2ical *exchange2ical)
832 {
833         struct icalrecurrencetype recurrence;
834         icalproperty *prop;
835         struct RecurrencePattern *pat = exchange2ical->RecurrencePattern;
836         uint32_t rdfDaysBitmask = pat->PatternTypeSpecific.MonthRecurrencePattern.WeekRecurrencePattern;
837         short idx = 0;
838         enum RecurrenceN setpos = pat->PatternTypeSpecific.MonthRecurrencePattern.N;
839
840         struct icaltimetype icaltime;
841
842         icalrecurrencetype_clear(&recurrence);
843         recurrence.freq = ICAL_YEARLY_RECURRENCE;
844         recurrence.interval = (pat->Period / 12);
845
846         if (rdfDaysBitmask & Su) {
847                 recurrence.by_day[idx] = ICAL_SUNDAY_WEEKDAY;
848                 ++idx;
849         }
850         if (rdfDaysBitmask & M) {
851                 recurrence.by_day[idx] = ICAL_MONDAY_WEEKDAY;
852                 ++idx;
853         }
854         if (rdfDaysBitmask & Tu) {
855                 recurrence.by_day[idx] = ICAL_TUESDAY_WEEKDAY;
856                 ++idx;
857         }
858         if (rdfDaysBitmask & W) {
859                 recurrence.by_day[idx] = ICAL_WEDNESDAY_WEEKDAY;
860                 ++idx;
861         }
862         if (rdfDaysBitmask & Th) {
863                 recurrence.by_day[idx] = ICAL_THURSDAY_WEEKDAY;
864                 ++idx;
865         }
866         if (rdfDaysBitmask & F) {
867                 recurrence.by_day[idx] = ICAL_FRIDAY_WEEKDAY;
868                 ++idx;
869         }
870         if (rdfDaysBitmask & Sa) {
871                 recurrence.by_day[idx] = ICAL_FRIDAY_WEEKDAY;
872                 ++idx;
873         }
874         recurrence.by_day[idx] = ICAL_RECURRENCE_ARRAY_MAX;
875
876         if (setpos == RecurrenceN_First) {
877                 recurrence.by_set_pos[0] = 1;
878                 recurrence.by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
879         } else if (setpos == RecurrenceN_Second) {
880                 recurrence.by_set_pos[0] = 2;
881                 recurrence.by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
882         } else if (setpos == RecurrenceN_Third) {
883                 recurrence.by_set_pos[0] = 3;
884                 recurrence.by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
885         } else if (setpos == RecurrenceN_Fourth) {
886                 recurrence.by_set_pos[0] = 4;
887                 recurrence.by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
888         } else if (setpos == RecurrenceN_Last) {
889                 recurrence.by_set_pos[0] = -1;
890                 recurrence.by_set_pos[1] = ICAL_RECURRENCE_ARRAY_MAX;
891         }
892
893         icaltime = get_icaltime_from_FILETIME(exchange2ical->apptStartWhole);
894         recurrence.by_month[0] = icaltime.month;
895         recurrence.by_month[1] = ICAL_RECURRENCE_ARRAY_MAX;
896         
897         if (pat->EndType == END_AFTER_N_OCCURRENCES || pat->EndType == END_AFTER_DATE) {
898                 recurrence.count = pat->OccurrenceCount;
899         }
900
901         prop = icalproperty_new_rrule(recurrence);
902         icalcomponent_add_property(exchange2ical->vevent, prop);
903 }
904
905
906 void ical_property_RRULE(struct exchange2ical *exchange2ical)
907 {
908         struct RecurrencePattern *pat;
909
910         /* Sanity check */
911         if (!(exchange2ical->RecurrencePattern)) return;
912
913         pat = exchange2ical->RecurrencePattern;
914
915         switch(pat->PatternType) {
916         case PatternType_Day:
917                 ical_property_RRULE_Daily(exchange2ical);
918                 break;
919         case PatternType_Week:
920                 ical_property_RRULE_Weekly(exchange2ical);
921                 break;
922         case PatternType_Month:
923                 if ((pat->Period % 12 ) == 0) {
924                         ical_property_RRULE_Yearly(exchange2ical);
925                 } else {
926                         ical_property_RRULE_Monthly(exchange2ical);
927                 }
928                 break;
929         case PatternType_MonthNth:
930                 if ((pat->Period % 12 ) == 0) {
931                         ical_property_RRULE_NthYearly(exchange2ical);
932                 } else {
933                         ical_property_RRULE_NthMonthly(exchange2ical);
934                 }
935                 break;
936         default:
937                 printf("RRULE pattern type not implemented yet!:0x%x\n", pat->PatternType);
938         }
939 }
940
941 void ical_property_RRULE_daylight_standard(icalcomponent* component , struct SYSTEMTIME st)
942 {
943         struct icalrecurrencetype recurrence;
944         icalproperty *prop;
945         
946         icalrecurrencetype_clear(&recurrence);
947         recurrence.freq = ICAL_YEARLY_RECURRENCE;
948
949         if(st.wYear ==0x0000){
950                 recurrence.by_month[0]=st.wMonth;
951                 /* Microsoft day of week = libIcal day of week +1; */
952                 /* Day encode = day + occurrence*8 */
953                 if (st.wDay==5){
954                         /* Last occurrence of day in the month*/
955                         recurrence.by_day[0] = -1 * (st.wDayOfWeek + 9);
956                 }else{
957                         /* st.wDay occurrence of day in the month */
958                         recurrence.by_day[0] = (st.wDayOfWeek + 1 + st.wDay*8);
959                 }
960                 
961         }else{
962                 recurrence.by_month_day[0]=st.wDay;
963                 recurrence.by_month[0]=st.wMonth;
964         }
965
966         
967         prop = icalproperty_new_rrule(recurrence);
968         icalcomponent_add_property(component, prop);
969 }
970
971
972 void ical_property_RECURRENCE_ID(struct exchange2ical *exchange2ical)
973 {       
974         struct icaltimetype     icaltime;
975         icalproperty            *prop;
976         icalparameter           *tzid;
977         struct GlobalObjectId   *GlbObjId;
978
979         
980         if (exchange2ical->ExceptionReplaceTime){
981                 /*if parent has an all day event*/
982                 if (exchange2ical->apptSubType && (*exchange2ical->apptSubType == 0x1)) {
983                         icaltime = get_icaldate_from_FILETIME(exchange2ical->ExceptionReplaceTime);
984                         prop = icalproperty_new_recurrenceid(icaltime);
985                         icalcomponent_add_property(exchange2ical->vevent, prop);
986                 } else {
987                         if (exchange2ical->TimeZoneDesc) {
988                                 icaltime=get_icaltime_from_FILETIME(exchange2ical->ExceptionReplaceTime);
989                                 prop = icalproperty_new_recurrenceid(icaltime);
990                                 icalcomponent_add_property(exchange2ical->vevent, prop);
991                                 tzid = icalparameter_new_tzid(exchange2ical->TimeZoneDesc);
992                                 icalproperty_add_parameter(prop, tzid);
993                         } else {
994                                 icaltime = get_icaltime_from_FILETIME_UTC(exchange2ical->ExceptionReplaceTime);
995                                 prop = icalproperty_new_recurrenceid(icaltime);
996                                 icalcomponent_add_property(exchange2ical->vevent, prop);
997                         }
998                 }
999         } else if (exchange2ical->GlobalObjectId){
1000                 GlbObjId = get_GlobalObjectId(exchange2ical->mem_ctx, exchange2ical->GlobalObjectId);
1001                 if(GlbObjId){
1002                         icaltime=get_icaldate_from_GlobalObjectId(GlbObjId);
1003                         prop = icalproperty_new_recurrenceid(icaltime);
1004                         icalcomponent_add_property(exchange2ical->vevent, prop);
1005                         talloc_free(GlbObjId);
1006
1007                 }
1008         }
1009         
1010 }
1011
1012
1013 void ical_property_RESOURCES(struct exchange2ical *exchange2ical)
1014 {
1015         char            *NonSendableBcc = NULL;
1016         icalproperty    *prop;
1017
1018         /* Sanity check */
1019         if (!exchange2ical->NonSendableBcc) return;
1020         
1021         NonSendableBcc = talloc_strdup(exchange2ical->mem_ctx, exchange2ical->NonSendableBcc);
1022         all_string_sub(NonSendableBcc, ";", ",", 0);
1023         prop = icalproperty_new_resources(NonSendableBcc);
1024         icalcomponent_add_property(exchange2ical->vevent, prop);
1025         talloc_free(NonSendableBcc);
1026 }
1027
1028
1029 void ical_property_SEQUENCE(struct exchange2ical *exchange2ical)
1030 {
1031         icalproperty *prop;
1032         if (!exchange2ical->Sequence) {
1033                 prop = icalproperty_new_sequence(0);
1034         } else {
1035                 prop = icalproperty_new_sequence(*(exchange2ical->Sequence));
1036         }
1037         icalcomponent_add_property(exchange2ical->vevent, prop);
1038 }
1039
1040
1041 void ical_property_SUMMARY(struct exchange2ical *exchange2ical)
1042 {
1043         icalproperty *prop;
1044         icalparameter *language;
1045
1046         if (exchange2ical->Subject) {
1047                 prop = icalproperty_new_summary(exchange2ical->Subject);
1048         } else {
1049                 prop = icalproperty_new_summary("");
1050         }
1051
1052         if (exchange2ical->MessageLocaleId) {
1053                 const char *langtag = mapi_get_locale_from_lcid( *(exchange2ical->MessageLocaleId) ); 
1054                 language = icalparameter_new_language( langtag );
1055                 icalproperty_add_parameter(prop, language);
1056         }
1057
1058         icalcomponent_add_property(exchange2ical->vevent, prop);
1059 }
1060
1061
1062 void ical_property_TRANSP(struct exchange2ical *exchange2ical)
1063 {
1064         icalproperty *prop;
1065
1066         /* Sanity check */
1067         if (!exchange2ical->BusyStatus) return;
1068
1069         switch (*exchange2ical->BusyStatus) {
1070         case 0x00000000:
1071                 prop = icalproperty_new_transp(ICAL_TRANSP_TRANSPARENT);
1072                 break;
1073         case 0x00000001:
1074         case 0x00000002:
1075         case 0x00000003:
1076                 prop = icalproperty_new_transp(ICAL_TRANSP_OPAQUE);
1077                 break;
1078         default:
1079                 prop = icalproperty_new_transp(ICAL_TRANSP_NONE);
1080         }
1081         icalcomponent_add_property(exchange2ical->vevent, prop);
1082 }
1083
1084
1085 void ical_property_TRIGGER(struct exchange2ical *exchange2ical)
1086 {
1087         struct icaltriggertype duration;
1088         icalproperty *prop;
1089         if (!exchange2ical->ReminderDelta) return;
1090         if (*exchange2ical->ReminderDelta == 0x5AE980E1) {
1091                 duration = icaltriggertype_from_int(-15 * 60);
1092                 prop = icalproperty_new_trigger(duration);
1093                 icalcomponent_add_property(exchange2ical->valarm, prop);
1094         } else {
1095                 duration = icaltriggertype_from_int(*(exchange2ical->ReminderDelta) * -1 * 60);
1096                 prop = icalproperty_new_trigger(duration);
1097                 icalcomponent_add_property(exchange2ical->valarm, prop);
1098         }
1099 }
1100
1101
1102 #define GLOBAL_OBJECT_ID_DATA_START     "\x76\x43\x61\x6c\x2d\x55\x69\x64\x01\x00\x00\x00"
1103
1104 void ical_property_UID(struct exchange2ical *exchange2ical)
1105 {
1106         uint32_t                i;
1107         const char              *uid;
1108         char*                   outstr;
1109         struct GlobalObjectId   *GlbObjId;
1110         icalproperty            *prop;
1111
1112         outstr = talloc_strdup(exchange2ical->mem_ctx, "");
1113         
1114         if(exchange2ical->GlobalObjectId){
1115                 GlbObjId = get_GlobalObjectId(exchange2ical->mem_ctx, exchange2ical->GlobalObjectId);
1116         }
1117         
1118       
1119         if (exchange2ical->GlobalObjectId && (exchange2ical->GlobalObjectId->cb >= 36) && GlbObjId) {
1120                 if (GlbObjId->Size >= 16 && (0 == memcmp(GlbObjId->Data, GLOBAL_OBJECT_ID_DATA_START, 12))) {
1121                         fflush(0);
1122                         for (i = 12; i < exchange2ical->GlobalObjectId->cb; i++) {
1123                                 char objID[6];
1124                                 snprintf(objID, 6, "%.2X", exchange2ical->GlobalObjectId->lpb[i]);
1125                                 outstr = talloc_strdup_append(outstr, objID);
1126                         }
1127
1128                         uid = (const char *)&(GlbObjId->Data[13]);
1129                         outstr = talloc_strdup_append(outstr, uid);
1130                 } else {
1131                         fflush(0);
1132                         for (i = 0; i < 16; i++) {
1133                                 char objID[6];
1134                                 snprintf(objID, 6, "%.2X", exchange2ical->GlobalObjectId->lpb[i]);
1135                                 outstr = talloc_strdup_append(outstr, objID);
1136                         }
1137                         /* YH, YL, Month and D must be set to 0 */
1138                         outstr = talloc_strdup_append(outstr, "00000000");
1139
1140                         for (i = 20; i < exchange2ical->GlobalObjectId->cb; i++) {
1141                                 char objID[6];
1142                                 snprintf(objID, 6, "%.2X", exchange2ical->GlobalObjectId->lpb[i]);
1143                                 outstr = talloc_strdup_append(outstr, objID);
1144                         }
1145                 }
1146                 talloc_free(GlbObjId);
1147         } else {
1148                 char objID[32];
1149                 snprintf(objID, 32, "%i", exchange2ical->idx);
1150                 outstr = talloc_strdup(outstr, objID);
1151         }
1152         
1153         prop = icalproperty_new_uid(outstr);
1154         icalcomponent_add_property(exchange2ical->vevent, prop);
1155         talloc_free(outstr);
1156 }
1157
1158
1159 static icalproperty * ical_property_add_x_property_value(icalcomponent *parent, const char* propname, const char* value)
1160 {
1161         icalproperty *prop;
1162         icalvalue *icalText;
1163
1164         /* Sanity checks */
1165         if (!parent) return NULL;
1166         if (!propname) return NULL;
1167         if (!value) return NULL;
1168
1169         icalText = icalvalue_new_text(value);
1170         prop = icalproperty_new_x(icalvalue_as_ical_string(icalText));
1171         icalvalue_free(icalText);
1172         icalproperty_set_x_name(prop, propname);
1173         icalcomponent_add_property(parent, prop);
1174         return prop;
1175 }
1176
1177 void ical_property_X_ALT_DESC(struct exchange2ical *exchange2ical)
1178 {
1179         icalproperty *prop;
1180         icalparameter *param;
1181         
1182         /*sanity check */
1183         if(!exchange2ical->bodyHTML) return;
1184         prop = ical_property_add_x_property_value(exchange2ical->vevent, "X-ALT-DESC",exchange2ical->bodyHTML);
1185         param = icalparameter_new_fmttype("text/html");
1186         icalproperty_add_parameter(prop, param);        
1187 }
1188
1189 void ical_property_X_MICROSOFT_CDO_ATTENDEE_CRITICAL_CHANGE(struct exchange2ical *exchange2ical)
1190 {
1191         struct tm       *tm;
1192         char            outstr[200];
1193
1194         /* Sanity check */
1195         if (!exchange2ical->AttendeeCriticalChange) return;
1196
1197         tm = get_tm_from_FILETIME(exchange2ical->AttendeeCriticalChange);
1198         strftime(outstr, sizeof(outstr), "%Y%m%dT%H%M%SZ", tm);
1199         ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-ATTENDEE-CRITICAL-CHANGE", outstr);
1200 }
1201
1202
1203 void ical_property_X_MICROSOFT_CDO_BUSYSTATUS(struct exchange2ical *exchange2ical)
1204 {
1205         /*sanity check*/
1206         if(!exchange2ical->BusyStatus) return;
1207         
1208         switch (*exchange2ical->BusyStatus) {
1209         case 0x00000000:
1210                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-BUSYSTATUS", "FREE");
1211                 break;
1212         case 0x00000001:
1213                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-BUSYSTATUS", "TENTATIVE");
1214                 break;
1215         case 0x00000002:
1216                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-BUSYSTATUS", "BUSY");
1217                 break;
1218         case 0x00000003:
1219                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-BUSYSTATUS", "OOF");
1220                 break;
1221         }
1222 }
1223 void ical_property_X_MICROSOFT_MSNCALENDAR_IMPORTANCE(struct exchange2ical *exchange2ical)
1224 {
1225         /* Sanity check */
1226         if (!exchange2ical->Importance) return;
1227
1228         switch (*exchange2ical->Importance) {
1229         case 0x00000000:
1230                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-MSNCALENDAR-IMPORTANCE", "0");
1231                 break;
1232         case 0x00000001:
1233                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-MSNCALENDAR-IMPORTANCE", "1");
1234                 break;
1235         case 0x00000002:
1236                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-MSNCALENDAR-IMPORTANCE", "2");
1237                 break;
1238         }
1239 }
1240
1241 void ical_property_X_MICROSOFT_CDO_INTENDEDSTATUS(struct exchange2ical *exchange2ical)
1242 {
1243         if (!exchange2ical->IntendedBusyStatus) return;
1244
1245         switch (*exchange2ical->IntendedBusyStatus) {
1246         case 0x00000000:
1247                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-INTENDEDSTATUS", "FREE");
1248                 break;
1249         case 0x00000001:
1250                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-INTENDEDSTATUS", "TENTATIVE");
1251                 break;
1252         case 0x00000002:
1253                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-INTENDEDSTATUS", "BUSY");
1254                 break;
1255         case 0x00000003:
1256                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-INTENDEDSTATUS", "OOF");
1257                 break;
1258         }
1259 }
1260
1261
1262 void ical_property_X_MICROSOFT_CDO_OWNERAPPTID(struct exchange2ical *exchange2ical)
1263 {
1264         char outstr[200];
1265         /* Sanity check */
1266         if (!exchange2ical->OwnerApptId) return;
1267         snprintf(outstr, 200, "%d", *(exchange2ical->OwnerApptId));
1268         ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-OWNERAPPTID", outstr);
1269 }
1270
1271
1272 void ical_property_X_MICROSOFT_CDO_OWNER_CRITICAL_CHANGE(struct exchange2ical *exchange2ical)
1273 {
1274         struct tm       *tm;
1275         char            outstr[200];
1276         
1277         /* Sanity check */
1278         if (!exchange2ical->OwnerCriticalChange) return;
1279
1280
1281         tm = get_tm_from_FILETIME(exchange2ical->OwnerCriticalChange);
1282         
1283
1284         strftime(outstr, sizeof(outstr), "%Y%m%dT%H%M%SZ", tm);
1285         ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-OWNER-CRITICAL-CHANGE", outstr);
1286 }
1287
1288
1289 void ical_property_X_MICROSOFT_CDO_REPLYTIME(struct exchange2ical *exchange2ical)
1290 {
1291         struct tm       *tm;
1292         char            outstr[200];
1293
1294         /* Sanity check */
1295         if (!exchange2ical->apptReplyTime) return;
1296
1297         tm = get_tm_from_FILETIME(exchange2ical->apptReplyTime);
1298         strftime(outstr, sizeof(outstr), "%Y%m%dT%H%M%SZ", tm);
1299         ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-CDO-REPLYTIME", outstr);
1300 }
1301
1302
1303 void ical_property_X_MICROSOFT_DISALLOW_COUNTER(struct exchange2ical *exchange2ical)
1304 {
1305         /* Sanity check */
1306         if (!exchange2ical->NotAllowPropose) return;
1307
1308         if (*(exchange2ical->NotAllowPropose) == true) {
1309                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-DISALLOW-COUNTER", "TRUE");
1310         } else {
1311                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-DISALLOW-COUNTER", "FALSE");
1312         }
1313 }
1314
1315
1316 void ical_property_X_MS_OLK_ALLOWEXTERNCHECK(struct exchange2ical *exchange2ical)
1317 {
1318         /* Sanity check */
1319         if (!exchange2ical->AllowExternCheck) return;
1320
1321         if (*(exchange2ical->AllowExternCheck) == true) {
1322                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-ALLOWEXTERNCHECK", "TRUE");
1323         } else {
1324                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MICROSOFT-ALLOWEXTERNCHECK", "FALSE");
1325         }
1326 }
1327
1328
1329 void ical_property_X_MS_OLK_APPTLASTSEQUENCE(struct exchange2ical *exchange2ical)
1330 {
1331         char outstr[20];
1332         /* Sanity check */
1333         if (!exchange2ical->apptLastSequence) return;
1334
1335         snprintf(outstr, 20, "%d", *exchange2ical->apptLastSequence);
1336         ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-APPTLASTSEQUENCE", outstr);
1337 }
1338
1339
1340 void ical_property_X_MS_OLK_APPTSEQTIME(struct exchange2ical *exchange2ical)
1341 {
1342         struct tm       *tm = NULL;
1343         char            outstr[200];
1344
1345         /* Sanity check */
1346         if (!exchange2ical->apptSeqTime) return;
1347
1348         tm = get_tm_from_FILETIME(exchange2ical->apptSeqTime);
1349         strftime(outstr, sizeof(outstr), "%Y%m%dT%H%M%SZ", tm);
1350         ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-APPTSEQTIME", outstr);
1351 }
1352
1353
1354 void ical_property_X_MS_OLK_AUTOFILLLOCATION(struct exchange2ical *exchange2ical)
1355 {
1356         /* Sanity check */
1357         if (!exchange2ical->AutoFillLocation) return;
1358
1359         if (*(exchange2ical->AutoFillLocation) == true) {
1360                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-AUTOFILLLOCATION", "TRUE");
1361         } else {
1362                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-AUTOFILLLOCATION", "FALSE");
1363         }
1364 }
1365
1366
1367 void ical_property_X_MS_OLK_AUTOSTARTCHECK(struct exchange2ical *exchange2ical)
1368 {
1369         /* Sanity check */
1370         if (!exchange2ical->AutoStartCheck) return;
1371         if (*(exchange2ical->AutoStartCheck) == true) {
1372                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-AUTOSTARTCHECK", "TRUE");
1373         } else {
1374                 ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-AUTOSTARTCHECK", "FALSE");
1375         }
1376 }
1377
1378
1379 void ical_property_X_MS_OLK_COLLABORATEDOC(struct exchange2ical *exchange2ical)
1380 {
1381         /* Sanity check */
1382         if (!exchange2ical->CollaborateDoc) return;
1383         if(!(*exchange2ical->CollaborateDoc)) return;
1384
1385         ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-COLLABORATEDOC", exchange2ical->CollaborateDoc);
1386 }
1387
1388
1389 void ical_property_X_MS_OLK_CONFCHECK(struct exchange2ical *exchange2ical)
1390 {
1391         /* Sanity check */
1392         if (!exchange2ical->ConfCheck) return;
1393         
1394         ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-CONFCHECK", (*exchange2ical->ConfCheck == true) ? "TRUE" : "FALSE");
1395 }
1396
1397
1398 void ical_property_X_MS_OLK_CONFTYPE(struct exchange2ical *exchange2ical)
1399 {
1400         char outstr[20];
1401         /* Sanity check */
1402         if (!exchange2ical->ConfType) return;
1403
1404         snprintf(outstr, 20, "%d", *exchange2ical->ConfType);
1405         ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-CONFTYPE", outstr);
1406 }
1407
1408
1409 void ical_property_X_MS_OLK_DIRECTORY(struct exchange2ical *exchange2ical)
1410 {
1411         /*Sanity Check*/
1412         if(!exchange2ical->Directory) return;
1413         if(!(*exchange2ical->Directory)) return;
1414
1415         ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-DIRECTORY", exchange2ical->Directory);
1416 }
1417
1418
1419 void ical_property_X_MS_OLK_MWSURL(struct exchange2ical *exchange2ical)
1420 {
1421         /*Sanity Check*/
1422         if(!exchange2ical->MWSURL) return;
1423
1424         ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-MWSURL", exchange2ical->MWSURL);
1425 }
1426
1427
1428 void ical_property_X_MS_OLK_NETSHOWURL(struct exchange2ical *exchange2ical)
1429 {
1430         /*Sanity Check*/
1431         if(!exchange2ical->NetShowURL) return;
1432         if(!(*exchange2ical->NetShowURL)) return;
1433
1434         ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-NETSHOWURL", exchange2ical->NetShowURL);
1435 }
1436
1437 void ical_property_X_MS_OLK_ONLINEPASSWORD(struct exchange2ical *exchange2ical)
1438 {
1439         /*Sanity Check*/
1440         if(!exchange2ical->OnlinePassword) return;
1441         if(!(*exchange2ical->OnlinePassword)) return;
1442
1443         ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-ONLINEPASSWORD", exchange2ical->OnlinePassword);
1444 }
1445
1446 void ical_property_X_MS_OLK_ORGALIAS(struct exchange2ical *exchange2ical)
1447 {
1448         /* Sanity check */
1449         if(!exchange2ical->OrgAlias) return;
1450         if(!(*exchange2ical->OrgAlias)) return;
1451
1452         ical_property_add_x_property_value(exchange2ical->vevent, "X-MS-OLK-ORGALIAS", exchange2ical->OrgAlias);
1453 }
1454
1455
1456 // TODO: double check this - need an example.
1457 void ical_property_X_MS_OLK_SENDER(struct exchange2ical *exchange2ical)
1458 {
1459         icalproperty *prop;
1460         icalparameter *param;
1461         char outstr[200];
1462
1463         /* Sanity check */
1464         if (!exchange2ical->apptStateFlags) return;
1465         if (!(*exchange2ical->apptStateFlags & 0x1)) return;
1466         if (!exchange2ical->SenderName) return;
1467
1468         if (exchange2ical->SenderEmailAddress) {
1469                 snprintf(outstr, 200, "mailto:%s",exchange2ical->SenderEmailAddress);
1470                 prop = icalproperty_new_x(outstr);
1471         } else {
1472                 prop = icalproperty_new_x("invalid:nomail");
1473         }
1474
1475         icalproperty_set_x_name(prop, "X-MS-OLK-SENDER");
1476         icalcomponent_add_property(exchange2ical->vevent, prop);
1477
1478         param = icalparameter_new_cn(exchange2ical->SenderName);
1479         icalproperty_add_parameter(prop, param);
1480 }