5358038ea7ea5d44024c9467f7f095cfae862727
[tridge/openchange.git] / branches / plugfest / libexchange2ical / exchange2ical.c
1 /*
2    Common conversion routines for exchange2ical
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
24
25 static void exchange2ical_init(TALLOC_CTX *mem_ctx, struct exchange2ical *exchange2ical)
26 {
27         exchange2ical->TimeZoneStruct = NULL;
28         exchange2ical->TimeZoneDesc = NULL;
29         exchange2ical->method = ICAL_METHOD_NONE;
30         exchange2ical->vtimezone = NULL;
31         exchange2ical->vcalendar = NULL;
32         exchange2ical->mem_ctx = mem_ctx;
33         exchange2ical->partstat = ICAL_PARTSTAT_NONE;
34         exchange2ical->ResponseStatus = NULL;
35         exchange2ical->Recurring = NULL;
36         exchange2ical->RecurrencePattern = NULL;
37         exchange2ical->AppointmentRecurrencePattern = NULL;
38         exchange2ical->Keywords = NULL;
39         exchange2ical->Contacts = NULL;
40         exchange2ical->apptStateFlags = NULL;
41         exchange2ical->sensitivity = NULL;
42         exchange2ical->apptStartWhole = NULL;
43         exchange2ical->apptEndWhole = NULL;
44         exchange2ical->apptSubType = NULL;
45         exchange2ical->OwnerCriticalChange = NULL;
46         exchange2ical->body = NULL;
47         exchange2ical->LastModified = NULL;
48         exchange2ical->Location = NULL;
49         exchange2ical->Importance = NULL;
50         exchange2ical->ExceptionReplaceTime = NULL;
51         exchange2ical->ResponseRequested = NULL;
52         exchange2ical->NonSendableBcc = NULL;
53         exchange2ical->Sequence = NULL;
54         exchange2ical->Subject = NULL;
55         exchange2ical->MessageLocaleId = NULL;
56         exchange2ical->BusyStatus = NULL;
57         exchange2ical->IntendedBusyStatus = NULL;
58         exchange2ical->GlobalObjectId = NULL;
59         exchange2ical->AttendeeCriticalChange = NULL;
60         exchange2ical->OwnerApptId = NULL;
61         exchange2ical->apptReplyTime = NULL;
62         exchange2ical->NotAllowPropose = NULL;
63         exchange2ical->AllowExternCheck = NULL;
64         exchange2ical->apptLastSequence = NULL;
65         exchange2ical->apptSeqTime = NULL;
66         exchange2ical->AutoFillLocation = NULL;
67         exchange2ical->AutoStartCheck = NULL;
68         exchange2ical->CollaborateDoc = NULL;
69         exchange2ical->ConfCheck = NULL;
70         exchange2ical->ConfType = NULL;
71         exchange2ical->Directory = NULL;
72         exchange2ical->MWSURL = NULL;
73         exchange2ical->NetShowURL = NULL;
74         exchange2ical->OnlinePassword = NULL;
75         exchange2ical->OrgAlias = NULL;
76         exchange2ical->SenderName = NULL;
77         exchange2ical->SenderEmailAddress = NULL;
78         exchange2ical->ReminderSet = NULL;
79         exchange2ical->ReminderDelta = NULL;
80         exchange2ical->vevent = NULL;
81         exchange2ical->valarm = NULL;
82         exchange2ical->bodyHTML = NULL;
83         exchange2ical->idx=0;
84 }
85
86 static void exchange2ical_clear(struct exchange2ical *exchange2ical)
87 {
88         if (exchange2ical->AppointmentRecurrencePattern){
89                 talloc_free(exchange2ical->AppointmentRecurrencePattern);
90         }
91         
92         if (exchange2ical->TimeZoneStruct) {
93                 talloc_free(exchange2ical->TimeZoneStruct);
94         }
95
96         exchange2ical_init(exchange2ical->mem_ctx, exchange2ical);
97 }
98
99
100 static void exchange2ical_reset(struct exchange2ical *exchange2ical)
101 {
102         if (exchange2ical->AppointmentRecurrencePattern){
103                 talloc_free(exchange2ical->AppointmentRecurrencePattern);
104         }
105
106         if (exchange2ical->TimeZoneStruct) {
107                 talloc_free(exchange2ical->TimeZoneStruct);
108         }
109         
110         exchange2ical->partstat = ICAL_PARTSTAT_NONE;
111         exchange2ical->ResponseStatus = NULL;
112         exchange2ical->Recurring = NULL;
113         exchange2ical->RecurrencePattern = NULL;
114         exchange2ical->AppointmentRecurrencePattern = NULL;
115         exchange2ical->Keywords = NULL;
116         exchange2ical->Contacts = NULL;
117         exchange2ical->apptStateFlags = NULL;
118         exchange2ical->sensitivity = NULL;
119         exchange2ical->apptStartWhole = NULL;
120         exchange2ical->apptEndWhole = NULL;
121         exchange2ical->apptSubType = NULL;
122         exchange2ical->OwnerCriticalChange = NULL;
123         exchange2ical->body = NULL;
124         exchange2ical->LastModified = NULL;
125         exchange2ical->Location = NULL;
126         exchange2ical->Importance = NULL;
127         exchange2ical->ExceptionReplaceTime = NULL;
128         exchange2ical->ResponseRequested = NULL;
129         exchange2ical->NonSendableBcc = NULL;
130         exchange2ical->Sequence = NULL;
131         exchange2ical->Subject = NULL;
132         exchange2ical->MessageLocaleId = NULL;
133         exchange2ical->BusyStatus = NULL;
134         exchange2ical->IntendedBusyStatus = NULL;
135         exchange2ical->GlobalObjectId = NULL;
136         exchange2ical->AttendeeCriticalChange = NULL;
137         exchange2ical->OwnerApptId = NULL;
138         exchange2ical->apptReplyTime = NULL;
139         exchange2ical->NotAllowPropose = NULL;
140         exchange2ical->AllowExternCheck = NULL;
141         exchange2ical->apptLastSequence = NULL;
142         exchange2ical->apptSeqTime = NULL;
143         exchange2ical->AutoFillLocation = NULL;
144         exchange2ical->AutoStartCheck = NULL;
145         exchange2ical->CollaborateDoc = NULL;
146         exchange2ical->ConfCheck = NULL;
147         exchange2ical->ConfType = NULL;
148         exchange2ical->Directory = NULL;
149         exchange2ical->MWSURL = NULL;
150         exchange2ical->NetShowURL = NULL;
151         exchange2ical->OnlinePassword = NULL;
152         exchange2ical->OrgAlias = NULL;
153         exchange2ical->SenderName = NULL;
154         exchange2ical->SenderEmailAddress = NULL;
155         exchange2ical->ReminderSet = NULL;
156         exchange2ical->ReminderDelta = NULL;
157         exchange2ical->vevent = NULL;
158         exchange2ical->valarm = NULL;
159         exchange2ical->bodyHTML = NULL;
160         exchange2ical->TimeZoneDesc = NULL;
161         exchange2ical->TimeZoneStruct = NULL;
162 }
163
164
165 static int exchange2ical_get_properties(TALLOC_CTX *mem_ctx, struct SRow *aRow, struct exchange2ical *exchange2ical, enum exchange2ical_flags eFlags)
166 {
167         struct Binary_r *apptrecur;
168         const char *messageClass;
169         struct Binary_r *TimeZoneStruct;
170
171         if(eFlags & VcalFlag){
172                 messageClass = octool_get_propval(aRow, PR_MESSAGE_CLASS_UNICODE);
173                 exchange2ical->method = get_ical_method(messageClass);
174                 if (!exchange2ical->method) return -1;
175         }
176         
177         if(((eFlags & RangeFlag) && !(eFlags & EntireFlag))||
178                 (!(eFlags & RangeFlag) && (eFlags & EntireFlag))){
179                 exchange2ical->apptStartWhole = (const struct FILETIME *)octool_get_propval(aRow, PidLidAppointmentStartWhole);
180
181         }
182         
183         if(((eFlags & EventFlag) && !(eFlags & EntireFlag))||
184                 (!(eFlags & EventFlag) && (eFlags & EntireFlag))){
185                 exchange2ical->GlobalObjectId = (struct Binary_r *) octool_get_propval(aRow, PidLidGlobalObjectId);
186                 exchange2ical->Sequence = (uint32_t *) octool_get_propval(aRow, PidLidAppointmentSequence);     
187
188         }
189         
190         if(((eFlags & EventsFlag) && !(eFlags & EntireFlag))||
191                 (!(eFlags & EventsFlag) && (eFlags & EntireFlag))){
192                 exchange2ical->GlobalObjectId = (struct Binary_r *) octool_get_propval(aRow, PidLidGlobalObjectId);
193
194         }
195         
196         if(eFlags & EntireFlag) {
197           
198                 apptrecur = (struct Binary_r *) octool_get_propval(aRow, PidLidAppointmentRecur);
199                 exchange2ical->AppointmentRecurrencePattern = get_AppointmentRecurrencePattern(mem_ctx,apptrecur);
200                 exchange2ical->RecurrencePattern = &exchange2ical->AppointmentRecurrencePattern->RecurrencePattern;
201                 
202                 TimeZoneStruct = (struct Binary_r *) octool_get_propval(aRow, PidLidTimeZoneStruct);
203                 exchange2ical->TimeZoneStruct = get_TimeZoneStruct(mem_ctx, TimeZoneStruct);
204
205                 exchange2ical->TimeZoneDesc = (const char *) octool_get_propval(aRow, PidLidTimeZoneDescription);
206                 exchange2ical->Keywords = (const struct StringArray_r *) octool_get_propval(aRow, PidNameKeywords);
207                 exchange2ical->Recurring = (uint8_t *) octool_get_propval(aRow, PidLidRecurring);
208                 exchange2ical->TimeZoneDesc = (const char *) octool_get_propval(aRow, PidLidTimeZoneDescription);
209                 exchange2ical->ExceptionReplaceTime = (const struct FILETIME *)octool_get_propval(aRow, PidLidExceptionReplaceTime);
210                 exchange2ical->ResponseStatus = (uint32_t *) octool_get_propval(aRow, PidLidResponseStatus);
211                 exchange2ical->apptStateFlags = (uint32_t *) octool_get_propval(aRow, PidLidAppointmentStateFlags);
212                 exchange2ical->Contacts = (const struct StringArray_r *)octool_get_propval(aRow, PidLidContacts);
213                 exchange2ical->apptEndWhole = (const struct FILETIME *)octool_get_propval(aRow, PidLidAppointmentEndWhole);     
214                 exchange2ical->apptSubType = (uint8_t *) octool_get_propval(aRow, PidLidAppointmentSubType);
215                 exchange2ical->OwnerCriticalChange = (const struct FILETIME *)octool_get_propval(aRow, PidLidOwnerCriticalChange);
216                 exchange2ical->Location = (const char *) octool_get_propval(aRow, PidLidLocation);      
217                 exchange2ical->NonSendableBcc = (const char *) octool_get_propval(aRow, PidLidNonSendableBcc);
218                 exchange2ical->BusyStatus = (uint32_t *) octool_get_propval(aRow, PidLidBusyStatus);    
219                 exchange2ical->IntendedBusyStatus = (uint32_t *) octool_get_propval(aRow, PidLidIntendedBusyStatus);    
220                 exchange2ical->AttendeeCriticalChange = (const struct FILETIME *) octool_get_propval(aRow, PidLidAttendeeCriticalChange);       
221                 exchange2ical->apptReplyTime = (const struct FILETIME *)octool_get_propval(aRow, PidLidAppointmentReplyTime);
222                 exchange2ical->NotAllowPropose = (uint8_t *) octool_get_propval(aRow, PidLidAppointmentNotAllowPropose);        
223                 exchange2ical->AllowExternCheck = (uint8_t *) octool_get_propval(aRow, PidLidAllowExternalCheck);
224                 exchange2ical->apptLastSequence = (uint32_t *) octool_get_propval(aRow, PidLidAppointmentLastSequence);
225                 exchange2ical->apptSeqTime = (const struct FILETIME *)octool_get_propval(aRow, PidLidAppointmentSequenceTime);  
226                 exchange2ical->AutoFillLocation = (uint8_t *) octool_get_propval(aRow, PidLidAutoFillLocation);
227                 exchange2ical->AutoStartCheck = (uint8_t *) octool_get_propval(aRow, PidLidAutoStartCheck);
228                 exchange2ical->CollaborateDoc = (const char *) octool_get_propval(aRow, PidLidCollaborateDoc);
229                 exchange2ical->ConfCheck = (uint8_t *) octool_get_propval(aRow, PidLidConferencingCheck);
230                 exchange2ical->ConfType = (uint32_t *) octool_get_propval(aRow, PidLidConferencingType);
231                 exchange2ical->Directory = (const char *) octool_get_propval(aRow, PidLidDirectory);
232                 exchange2ical->MWSURL = (const char *) octool_get_propval(aRow, PidLidMeetingWorkspaceUrl);
233                 exchange2ical->NetShowURL = (const char *) octool_get_propval(aRow, PidLidNetShowUrl);
234                 exchange2ical->OnlinePassword = (const char *) octool_get_propval(aRow, PidLidOnlinePassword);
235                 exchange2ical->OrgAlias = (const char *) octool_get_propval(aRow, PidLidOrganizerAlias);
236                 exchange2ical->ReminderSet = (uint8_t *) octool_get_propval(aRow, PidLidReminderSet);
237                 exchange2ical->ReminderDelta = (uint32_t *) octool_get_propval(aRow, PidLidReminderDelta);
238                 exchange2ical->sensitivity = (uint32_t *) octool_get_propval(aRow, PR_SENSITIVITY);
239                 exchange2ical->created = (const struct FILETIME *)octool_get_propval(aRow, PR_CREATION_TIME);
240                 exchange2ical->body = (const char *)octool_get_propval(aRow, PR_BODY_UNICODE);
241                 exchange2ical->LastModified = (const struct FILETIME *)octool_get_propval(aRow, PR_LAST_MODIFICATION_TIME);
242                 exchange2ical->Importance = (uint32_t *) octool_get_propval(aRow, PR_IMPORTANCE);
243                 exchange2ical->ResponseRequested = (uint8_t *) octool_get_propval(aRow, PR_RESPONSE_REQUESTED);
244                 exchange2ical->Subject = (const char *) octool_get_propval(aRow, PR_SUBJECT_UNICODE);
245                 exchange2ical->MessageLocaleId = (uint32_t *) octool_get_propval(aRow, PR_MESSAGE_LOCALE_ID);
246                 exchange2ical->OwnerApptId = (uint32_t *) octool_get_propval(aRow, PR_OWNER_APPT_ID);
247                 exchange2ical->SenderName = (const char *) octool_get_propval(aRow, PR_SENDER_NAME);
248                 exchange2ical->SenderEmailAddress = (const char *) octool_get_propval(aRow, PR_SENDER_EMAIL_ADDRESS);
249         }
250         
251         return 0;
252         
253 }
254
255
256 static uint8_t exchange2ical_exception_from_ExceptionInfo(struct exchange2ical *exchange2ical, struct exchange2ical_check *exchange2ical_check)
257 {
258         uint32_t        i;
259         icalproperty *prop;
260         icalparameter *param;
261         icaltimetype icaltime;
262         /*sanity checks*/
263         if(!exchange2ical->AppointmentRecurrencePattern) return 1;
264         if(!exchange2ical->AppointmentRecurrencePattern->ExceptionInfo) return 1;
265         if(!exchange2ical->AppointmentRecurrencePattern->ExceptionCount) return 1;
266
267         for(i=0; i<exchange2ical->AppointmentRecurrencePattern->ExceptionCount; i++) {
268                 
269                 /*Check to see if event is acceptable*/
270                 struct tm apptStart=get_tm_from_minutes_UTC(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->StartDateTime);
271                 if (!checkEvent(exchange2ical, exchange2ical_check, &apptStart)){
272                         return 0;
273                 }
274                 
275                 /*Create a new vevent*/
276                 exchange2ical->vevent = icalcomponent_new_vevent();
277                 if ( ! (exchange2ical->vevent) ) {
278                         return 1;
279                 }
280                 icalcomponent_add_component(exchange2ical->vcalendar, exchange2ical->vevent);
281
282                 /*dtstart from StartDateTime*/
283                 if (exchange2ical->apptSubType && (*exchange2ical->apptSubType == 0x1)) {
284                         struct tm       tm;
285                         tm = get_tm_from_minutes_UTC(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->StartDateTime);
286                         icaltime= get_icaldate_from_tm(&tm);
287                         prop = icalproperty_new_dtstart(icaltime);
288                         icalcomponent_add_property(exchange2ical->vevent, prop);
289                 }else {
290                         if(exchange2ical->TimeZoneDesc){
291                                 struct tm       tm;
292                                 tm = get_tm_from_minutes(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->StartDateTime);
293                                 icaltime= get_icaldate_from_tm(&tm);
294                                 prop = icalproperty_new_dtstart(icaltime);
295                                 icalcomponent_add_property(exchange2ical->vevent, prop);
296                                 param = icalparameter_new_tzid(exchange2ical->TimeZoneDesc);
297                                 icalproperty_add_parameter(prop, param);
298                         } else {
299                                 struct tm       tm;
300                                 tm = get_tm_from_minutes_UTC(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->StartDateTime);
301                                 icaltime= get_icaldate_from_tm(&tm);
302                                 prop = icalproperty_new_dtstart(icaltime);
303                                 icalcomponent_add_property(exchange2ical->vevent, prop);
304                         }
305                 }
306                 /*dtend from EndDateTime*/
307                 if (exchange2ical->apptSubType && (*exchange2ical->apptSubType == 0x1)) {
308                         struct tm       tm;
309                         tm = get_tm_from_minutes_UTC(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->EndDateTime);
310                         icaltime= get_icaldate_from_tm(&tm);
311                         prop = icalproperty_new_dtend(icaltime);
312                         icalcomponent_add_property(exchange2ical->vevent, prop);
313                 }else {
314                         if(exchange2ical->TimeZoneDesc){
315                                 struct tm       tm;
316                                 tm = get_tm_from_minutes(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->EndDateTime);
317                                 icaltime= get_icaldate_from_tm(&tm);
318                                 prop = icalproperty_new_dtend(icaltime);
319                                 icalcomponent_add_property(exchange2ical->vevent, prop);
320                                 param = icalparameter_new_tzid(exchange2ical->TimeZoneDesc);
321                                 icalproperty_add_parameter(prop, param);
322                         } else {
323                                 struct tm       tm;
324                                 tm = get_tm_from_minutes_UTC(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->EndDateTime);
325                                 icaltime= get_icaldate_from_tm(&tm);
326                                 prop = icalproperty_new_dtend(icaltime);
327                                 icalcomponent_add_property(exchange2ical->vevent, prop);
328                         }
329                 }
330                 /*recurrence-id from OriginalStartDate*/
331                 if (exchange2ical->apptSubType && (*exchange2ical->apptSubType == 0x1)) {
332                         struct tm       tm;
333                         tm = get_tm_from_minutes_UTC(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->OriginalStartDate);
334                         icaltime= get_icaldate_from_tm(&tm);
335                         prop = icalproperty_new_recurrenceid(icaltime);
336                         icalcomponent_add_property(exchange2ical->vevent, prop);
337                 }else {
338                         if(exchange2ical->TimeZoneDesc){
339                                 struct tm       tm;
340                                 tm = get_tm_from_minutes(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->OriginalStartDate);
341                                 icaltime= get_icaldate_from_tm(&tm);
342                                 prop = icalproperty_new_recurrenceid(icaltime);
343                                 icalcomponent_add_property(exchange2ical->vevent, prop);
344                                 param = icalparameter_new_tzid(exchange2ical->TimeZoneDesc);
345                                 icalproperty_add_parameter(prop, param);
346                         } else {
347                                 struct tm       tm;
348                                 tm = get_tm_from_minutes_UTC(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->OriginalStartDate);
349                                 icaltime= get_icaldate_from_tm(&tm);
350                                 prop = icalproperty_new_recurrenceid(icaltime);
351                                 icalcomponent_add_property(exchange2ical->vevent, prop);
352                         }
353                 }
354                 
355                 /*summary from Subject if subject is set*/
356                 if (exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->OverrideFlags & 0x0001) {
357                         exchange2ical->Subject=(const char *) &exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->Subject.subject;
358                         ical_property_SUMMARY(exchange2ical);
359                 }
360                 
361
362                 /*Valarm*/
363                 /*ReminderSet*/
364                 if(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->OverrideFlags & 0x0008){
365                         exchange2ical->ReminderSet=(uint8_t *) &exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->ReminderDelta.rSet;
366                         /*Reminder Delta*/
367                         if(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->OverrideFlags & 0x0004){
368                                 exchange2ical->ReminderDelta=&exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->ReminderDelta.rDelta;
369                         } else {
370                                 exchange2ical->ReminderDelta=NULL;
371                         }
372                         ical_component_VALARM(exchange2ical);
373                 }
374
375                 /*Location*/
376                 if(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->OverrideFlags & 0x0010){
377                         exchange2ical->Location=(const char *) &exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->Location.location;
378                         ical_property_LOCATION(exchange2ical);
379                 }
380                 
381                 /*Busy Status*/
382                 if(exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->OverrideFlags & 0x0020){
383                         exchange2ical->BusyStatus=&exchange2ical->AppointmentRecurrencePattern->ExceptionInfo->BusyStatus.bStatus;
384                         ical_property_X_MICROSOFT_CDO_BUSYSTATUS(exchange2ical);
385                 }
386         }
387         return 0;
388 }
389
390 static uint8_t exchange2ical_exception_from_EmbeddedObj(struct exchange2ical *exchange2ical, struct exchange2ical_check *exchange2ical_check)
391 {
392         mapi_object_t                   obj_tb_attach;
393         mapi_object_t                   obj_attach;
394         struct SRowSet                  rowset_attach;
395         struct SPropTagArray            *SPropTagArray;
396         const uint32_t                  *attach_num;
397         struct SPropValue               *lpProps;
398         enum MAPISTATUS                 retval;
399         unsigned int                    i;
400         uint32_t                        count;
401         struct SRow                     aRow2;
402         struct SRow                     aRowT;
403         
404         mapi_object_init(&obj_tb_attach);
405         retval = GetAttachmentTable(&exchange2ical->obj_message, &obj_tb_attach);
406         if (retval != MAPI_E_SUCCESS) {
407                 return 1;
408         }else {
409                 SPropTagArray = set_SPropTagArray(exchange2ical->mem_ctx, 0x1, PR_ATTACH_NUM);
410                 retval = SetColumns(&obj_tb_attach, SPropTagArray);
411                 MAPIFreeBuffer(SPropTagArray);
412                 retval = QueryRows(&obj_tb_attach, 0xa, TBL_ADVANCE, &rowset_attach);
413
414                 for (i = 0; i < rowset_attach.cRows; i++) {
415                         
416                         attach_num = (const uint32_t *)find_SPropValue_data(&(rowset_attach.aRow[i]), PR_ATTACH_NUM);
417                         retval = OpenAttach(&exchange2ical->obj_message, *attach_num, &obj_attach);
418
419                         if (retval != MAPI_E_SUCCESS) {
420                                 return 1;
421                         }else {
422                                 SPropTagArray = set_SPropTagArray(exchange2ical->mem_ctx, 0x3,
423                                                                           PR_ATTACH_METHOD,
424                                                                           PR_ATTACHMENT_FLAGS,
425                                                                           PR_ATTACHMENT_HIDDEN
426                                                                           );
427                                                                           
428                                 lpProps = talloc_zero(exchange2ical->mem_ctx, struct SPropValue);
429                                 retval = GetProps(&obj_attach, SPropTagArray, &lpProps, &count);
430                                 MAPIFreeBuffer(SPropTagArray);
431                                 if (retval != MAPI_E_SUCCESS) {
432                                         return 1;
433                                 }else {
434                                         aRow2.ulAdrEntryPad = 0;
435                                         aRow2.cValues = count;
436                                         aRow2.lpProps = lpProps;
437                                         
438                                         uint32_t        *attachmentFlags;
439                                         uint32_t        *attachMethod;
440                                         uint8_t         *attachmentHidden;
441                                         
442                                         attachmentFlags  = (uint32_t *) octool_get_propval(&aRow2, PR_ATTACHMENT_FLAGS);
443                                         attachMethod     = (uint32_t *) octool_get_propval(&aRow2, PR_ATTACH_METHOD);
444                                         attachmentHidden = (uint8_t *) octool_get_propval(&aRow2, PR_ATTACHMENT_HIDDEN);
445
446                                         if((*attachmentFlags & 0x00000002) 
447                                                 && (*attachMethod == 0x00000005) 
448                                                 && (attachmentHidden && (*attachmentHidden))) {
449                                         
450                                                 struct exchange2ical exception;
451                                                 exchange2ical_init(exchange2ical->mem_ctx,&exception);
452                                         
453                                                 mapi_object_init(&exception.obj_message);
454                                                 
455                                                 retval = OpenEmbeddedMessage(&obj_attach, &exception.obj_message, MAPI_READONLY);
456                                                 if (retval != MAPI_E_SUCCESS) {
457                                                         return 1;
458                                                 }else {                                                 
459                                                         SPropTagArray = set_SPropTagArray(exchange2ical->mem_ctx, 0x2d,
460                                                                                                 PidLidFExceptionalBody,
461                                                                                                 PidLidRecurring,
462                                                                                                 PidLidAppointmentRecur,
463                                                                                                 PidLidAppointmentStateFlags,
464                                                                                                 PidLidTimeZoneDescription,
465                                                                                                 PidLidTimeZoneStruct,
466                                                                                                 PidLidAppointmentStartWhole,
467                                                                                                 PidLidAppointmentEndWhole,
468                                                                                                 PidLidAppointmentSubType,
469                                                                                                 PidLidOwnerCriticalChange,
470                                                                                                 PidLidLocation,
471                                                                                                 PidLidExceptionReplaceTime,
472                                                                                                 PidLidNonSendableBcc,
473                                                                                                 PidLidAppointmentSequence,
474                                                                                                 PidLidBusyStatus,
475                                                                                                 PidLidIntendedBusyStatus,
476                                                                                                 PidLidCleanGlobalObjectId,
477                                                                                                 PidLidAttendeeCriticalChange,
478                                                                                                 PidLidAppointmentReplyTime,
479                                                                                                 PidLidAppointmentNotAllowPropose,
480                                                                                                 PidLidAllowExternalCheck,
481                                                                                                 PidLidAppointmentLastSequence,
482                                                                                                 PidLidAppointmentSequenceTime,
483                                                                                                 PidLidAutoFillLocation,
484                                                                                                 PidLidAutoStartCheck,
485                                                                                                 PidLidCollaborateDoc,
486                                                                                                 PidLidConferencingCheck,
487                                                                                                 PidLidConferencingType,
488                                                                                                 PidLidDirectory,
489                                                                                                 PidLidNetShowUrl,
490                                                                                                 PidLidOnlinePassword,
491                                                                                                 PidLidOrganizerAlias,
492                                                                                                 PidLidReminderSet,
493                                                                                                 PidLidReminderDelta,
494                                                                                                 PR_MESSAGE_CLASS_UNICODE,
495                                                                                                 PR_BODY_UNICODE,
496                                                                                                 PR_CREATION_TIME,
497                                                                                                 PR_LAST_MODIFICATION_TIME,
498                                                                                                 PR_IMPORTANCE,
499                                                                                                 PR_RESPONSE_REQUESTED,
500                                                                                                 PR_SUBJECT_UNICODE,
501                                                                                                 PR_OWNER_APPT_ID,
502                                                                                                 PR_SENDER_NAME,
503                                                                                                 PR_SENDER_EMAIL_ADDRESS,
504                                                                                                 PR_MESSAGE_LOCALE_ID
505                                                                   );
506                                                                   
507                                                                   
508                 
509                                                         retval = GetProps(&exception.obj_message, SPropTagArray, &lpProps, &count);
510                                                         
511                                                         if (retval == MAPI_E_SUCCESS) { 
512                                                                 aRow2.ulAdrEntryPad = 0;
513                                                                 aRow2.cValues = count;
514                                                                 aRow2.lpProps = lpProps;
515                                                                 
516                                                                 
517                                                                 /*Get required properties to check if right event*/
518                                                                 exchange2ical_get_properties(exchange2ical->mem_ctx, &aRow2, &exception, exchange2ical_check->eFlags);
519                                         
520                                                                 /*Check to see if event is acceptable*/
521                                                                 if (!checkEvent(&exception, exchange2ical_check, get_tm_from_FILETIME(exception.apptStartWhole))){
522                                                                         break;
523                                                                 }
524
525                                                                 /*Grab Rest of Properties*/
526                                                                 exchange2ical_get_properties(exchange2ical->mem_ctx, &aRow2, &exception, exchange2ical_check->eFlags | EntireFlag);
527                                                                 uint8_t *dBody = (uint8_t *) octool_get_propval(&aRow2, PidLidFExceptionalBody);
528                                                                 retval = GetRecipientTable(&exception.obj_message, 
529                                                                         &exception.Recipients.SRowSet,
530                                                                         &exception.Recipients.SPropTagArray);
531                                                                         
532                                                                 /*Check for set subject*/
533                                                                 if (!exception.Subject){
534                                                                         exception.Subject=exchange2ical->Subject;
535                                                                 }
536                                                                 /*Check for a set apptSubType*/
537                                                                 if (!exception.apptSubType){
538                                                                         exception.apptSubType=exchange2ical->apptSubType;
539                                                                 }
540                                                                 /*check for a set Location*/
541                                                                 if (!exception.Location){
542                                                                         exception.Location=exchange2ical->Location;
543                                                                 }
544                                                                 /*check for set valarm info*/
545                                                                 if(!exception.ReminderSet){
546                                                                         exception.ReminderSet=exchange2ical->ReminderSet;
547                                                                 }
548                                                                 if(!exception.ReminderDelta){
549                                                                         exception.ReminderDelta=exchange2ical->ReminderDelta;
550                                                                 }
551                                                                 
552                                                                 /*Set to same vcalendar as parent*/
553                                                                 exception.vcalendar=exchange2ical->vcalendar;
554                                                                 
555                                                                 /*Set to same uid fallback in case GlobalObjId is missing*/
556                                                                 exception.idx=exchange2ical->idx;
557                                                                 
558                                                                 
559                                                                 /*has a modified summary*/
560                                                                 if(dBody && *dBody){
561                                                                         SPropTagArray = set_SPropTagArray(exchange2ical->mem_ctx, 0x1, PR_BODY_HTML_UNICODE);
562                                                                         retval = GetProps(&exception.obj_message, SPropTagArray, &lpProps, &count);
563                                                                         MAPIFreeBuffer(SPropTagArray);
564                                                                         if (retval == MAPI_E_SUCCESS) {
565                                                                                 aRowT.ulAdrEntryPad = 0;
566                                                                                 aRowT.cValues = count;
567                                                                                 aRowT.lpProps = lpProps;
568                                                                                 exception.bodyHTML = (const char *)octool_get_propval(&aRowT, PR_BODY_HTML_UNICODE);
569                                                                         }
570                                                                 /* has the same summary as parent*/
571                                                                 } else{
572                                                                         exception.body=exchange2ical->body;
573                                                                         exception.bodyHTML=exchange2ical->bodyHTML;
574                                                                 }
575                                                                 
576                                                                 ical_component_VEVENT(&exception);
577                                                                 exception.vcalendar=NULL;
578                                                                 exchange2ical_clear(&exception);
579                                                         }
580                                                 }                                                       
581                                                 mapi_object_release(&exception.obj_message);
582                                         }
583                                         MAPIFreeBuffer(lpProps);
584                                 }
585                         }
586                         
587                 }
588
589         }
590         mapi_object_release(&obj_tb_attach);
591         return 0;       
592 }
593
594 icalcomponent * _Exchange2Ical(mapi_object_t *obj_folder, struct exchange2ical_check *exchange2ical_check)
595 {
596         TALLOC_CTX                      *mem_ctx;
597         enum MAPISTATUS                 retval;
598         int                             ret;
599         struct SRowSet                  SRowSet;
600         struct SRow                     aRow;
601         struct SRow                     aRowT;
602         struct SPropValue               *lpProps;
603         struct SPropTagArray            *SPropTagArray = NULL;
604         struct exchange2ical            exchange2ical;
605         mapi_object_t                   obj_table;
606         uint32_t                        count;
607         int                             i;
608
609         mem_ctx = talloc_named(NULL, 0, "exchange2ical");
610         exchange2ical_init(mem_ctx, &exchange2ical);
611         
612         /* Open the contents table */
613         mapi_object_init(&obj_table);
614         retval = GetContentsTable(obj_folder, &obj_table, 0, &count);
615         if (retval != MAPI_E_SUCCESS){
616                 talloc_free(mem_ctx);
617                 return NULL;
618         }
619         
620         DEBUG(0, ("MAILBOX (%d appointments)\n", count));
621         if (count == 0) {
622                 talloc_free(mem_ctx);
623                 return NULL;
624         }
625
626         SPropTagArray = set_SPropTagArray(mem_ctx, 0x2,
627                                           PR_FID,
628                                           PR_MID);
629                                           
630         retval = SetColumns(&obj_table, SPropTagArray);
631         MAPIFreeBuffer(SPropTagArray);
632         if (retval != MAPI_E_SUCCESS) {
633                 mapi_errstr("SetColumns", retval);
634                 talloc_free(mem_ctx);
635                 return NULL;
636         }
637         
638         while ((retval = QueryRows(&obj_table, count, TBL_ADVANCE, &SRowSet)) != MAPI_E_NOT_FOUND && SRowSet.cRows) {
639                 count -= SRowSet.cRows;
640                 for (i = (SRowSet.cRows-1); i >= 0; i--) {
641                         mapi_object_init(&exchange2ical.obj_message);
642                         retval = OpenMessage(obj_folder,
643                                              SRowSet.aRow[i].lpProps[0].value.d,
644                                              SRowSet.aRow[i].lpProps[1].value.d,
645                                              &exchange2ical.obj_message, 0);
646                         if (retval != MAPI_E_NOT_FOUND) {
647                                 SPropTagArray = set_SPropTagArray(mem_ctx, 0x30,
648                                                                   PidLidGlobalObjectId,
649                                                                   PidNameKeywords,
650                                                                   PidLidRecurring,
651                                                                   PidLidAppointmentRecur,
652                                                                   PidLidAppointmentStateFlags,
653                                                                   PidLidTimeZoneDescription,
654                                                                   PidLidTimeZoneStruct,
655                                                                   PidLidContacts,
656                                                                   PidLidAppointmentStartWhole,
657                                                                   PidLidAppointmentEndWhole,
658                                                                   PidLidAppointmentSubType,
659                                                                   PidLidOwnerCriticalChange,
660                                                                   PidLidLocation,
661                                                                   PidLidNonSendableBcc,
662                                                                   PidLidAppointmentSequence,
663                                                                   PidLidBusyStatus,
664                                                                   PidLidIntendedBusyStatus,
665                                                                   PidLidAttendeeCriticalChange,
666                                                                   PidLidAppointmentReplyTime,
667                                                                   PidLidAppointmentNotAllowPropose,
668                                                                   PidLidAllowExternalCheck,
669                                                                   PidLidAppointmentLastSequence,
670                                                                   PidLidAppointmentSequenceTime,
671                                                                   PidLidAutoFillLocation,
672                                                                   PidLidAutoStartCheck,
673                                                                   PidLidCollaborateDoc,
674                                                                   PidLidConferencingCheck,
675                                                                   PidLidConferencingType,
676                                                                   PidLidDirectory,
677                                                                   PidLidMeetingWorkspaceUrl,
678                                                                   PidLidNetShowUrl,
679                                                                   PidLidOnlinePassword,
680                                                                   PidLidOrganizerAlias,
681                                                                   PidLidReminderSet,
682                                                                   PidLidReminderDelta,
683                                                                   PidLidResponseStatus,
684                                                                   PR_MESSAGE_CLASS_UNICODE,
685                                                                   PR_SENSITIVITY,
686                                                                   PR_BODY_UNICODE,
687                                                                   PR_CREATION_TIME,
688                                                                   PR_LAST_MODIFICATION_TIME,
689                                                                   PR_IMPORTANCE,
690                                                                   PR_RESPONSE_REQUESTED,
691                                                                   PR_SUBJECT_UNICODE,
692                                                                   PR_OWNER_APPT_ID,
693                                                                   PR_SENDER_NAME,
694                                                                   PR_SENDER_EMAIL_ADDRESS,
695                                                                   PR_MESSAGE_LOCALE_ID
696                                                                   );
697                                                                   
698                                                                   
699                                 retval = GetProps(&exchange2ical.obj_message, SPropTagArray, &lpProps, &count);
700
701                                 MAPIFreeBuffer(SPropTagArray);
702         
703                                 if (retval == MAPI_E_SUCCESS) {
704                                         aRow.ulAdrEntryPad = 0;
705                                         aRow.cValues = count;
706                                         aRow.lpProps = lpProps;
707                                         
708                                         /*Get Vcal info if first event*/
709                                         if(i==(SRowSet.cRows-1)){
710                                                 ret = exchange2ical_get_properties(mem_ctx, &aRow, &exchange2ical, VcalFlag);
711                                                 /*TODO: exit nicely*/
712                                                 ical_component_VCALENDAR(&exchange2ical);
713                                         }
714                                         
715                                         
716                                         /*Get required properties to check if right event*/
717                                         ret = exchange2ical_get_properties(mem_ctx, &aRow, &exchange2ical, exchange2ical_check->eFlags);
718                                         
719                                         /*Check to see if event is acceptable*/
720                                         if (!checkEvent(&exchange2ical, exchange2ical_check, get_tm_from_FILETIME(exchange2ical.apptStartWhole))){
721                                                 continue;
722                                         }
723                                         
724                                         /*Set RecipientTable*/
725                                         retval = GetRecipientTable(&exchange2ical.obj_message, 
726                                                            &exchange2ical.Recipients.SRowSet,
727                                                            &exchange2ical.Recipients.SPropTagArray);
728                                         
729                                         /*Set PR_BODY_HTML for x_alt_desc property*/
730                                         SPropTagArray = set_SPropTagArray(mem_ctx, 0x1, PR_BODY_HTML_UNICODE);
731                                         retval = GetProps(&exchange2ical.obj_message, SPropTagArray, &lpProps, &count);
732                                         MAPIFreeBuffer(SPropTagArray);
733                                         if (retval == MAPI_E_SUCCESS) {
734                                                 aRowT.ulAdrEntryPad = 0;
735                                                 aRowT.cValues = count;
736                                                 aRowT.lpProps = lpProps;
737                                                 exchange2ical.bodyHTML = (const char *)octool_get_propval(&aRowT, PR_BODY_HTML_UNICODE);
738                                         }
739                                         
740                                         /*Get rest of properties*/
741                                         ret = exchange2ical_get_properties(mem_ctx, &aRow, &exchange2ical, (exchange2ical_check->eFlags | EntireFlag));
742                                         
743                                         /*add new vevent*/
744                                         ical_component_VEVENT(&exchange2ical);
745                                         
746                                         /*Exceptions to event*/
747                                         if(exchange2ical_check->eFlags != EventFlag){
748                                                 ret = exchange2ical_exception_from_EmbeddedObj(&exchange2ical, exchange2ical_check);
749                                                 if (ret){
750                                                         ret=exchange2ical_exception_from_ExceptionInfo(&exchange2ical, exchange2ical_check);
751                                                 }
752                                         }
753                                         
754                                         /*REMOVE once globalobjid is fixed*/
755                                         exchange2ical.idx++;
756                                         
757                                         MAPIFreeBuffer(lpProps);
758                                         exchange2ical_reset(&exchange2ical);
759                                 }
760                                 
761                         }
762                         mapi_object_release(&exchange2ical.obj_message);
763                 }
764         }
765
766         icalcomponent *icalendar = exchange2ical.vcalendar;
767         exchange2ical_clear(&exchange2ical);
768         
769         /* Uninitialize MAPI subsystem */
770         mapi_object_release(&obj_table);
771         talloc_free(mem_ctx);   
772         return icalendar;
773 }