"Fossies" - the Fresh Open Source Software Archive 
Member "evolution-mapi-3.46.1/src/libexchangemapi/e-mapi-cal-utils.c" (2 Dec 2022, 71639 Bytes) of package /linux/misc/evolution-mapi-3.46.1.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "e-mapi-cal-utils.c" see the
Fossies "Dox" file reference documentation.
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with the program; if not, see <http://www.gnu.org/licenses/>
15 *
16 *
17 * Authors:
18 * Suman Manjunath <msuman@novell.com>
19 *
20 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
21 *
22 */
23
24 #include "evolution-mapi-config.h"
25
26 #include <glib/gstdio.h>
27 #include <glib/gi18n-lib.h>
28 #include <libecal/libecal.h>
29 #include <libedataserver/libedataserver.h>
30
31 #include "e-mapi-mail-utils.h"
32 #include "e-mapi-cal-utils.h"
33
34 #ifndef O_BINARY
35 #define O_BINARY 0
36 #endif
37
38 /* This property changed names in openchange, try to support both */
39 #ifndef PidLidTaskAcceptanceState
40 #define PidLidTaskAcceptanceState PidLidAcceptanceState
41 #endif
42
43 #define d(x)
44
45 #define DEFAULT_APPT_REMINDER_MINS 15
46 #define DEFAULT_TASK_REMINDER_MINS 1080
47
48
49 static ICalParameterRole
50 get_role_from_type (OlMailRecipientType type)
51 {
52 switch (type) {
53 case olCC:
54 return I_CAL_ROLE_OPTPARTICIPANT;
55 case olOriginator:
56 case olTo:
57 case olBCC:
58 default:
59 return I_CAL_ROLE_REQPARTICIPANT;
60 }
61 }
62
63 static OlMailRecipientType
64 get_type_from_role (ICalParameterRole role)
65 {
66 switch (role) {
67 case I_CAL_ROLE_OPTPARTICIPANT:
68 return olCC;
69 case I_CAL_ROLE_CHAIR:
70 case I_CAL_ROLE_REQPARTICIPANT:
71 case I_CAL_ROLE_NONPARTICIPANT:
72 default:
73 return olTo;
74 }
75 }
76
77 static ICalParameterPartstat
78 get_partstat_from_trackstatus (uint32_t trackstatus)
79 {
80 switch (trackstatus) {
81 case olResponseOrganized:
82 case olResponseAccepted:
83 return I_CAL_PARTSTAT_ACCEPTED;
84 case olResponseTentative:
85 return I_CAL_PARTSTAT_TENTATIVE;
86 case olResponseDeclined:
87 return I_CAL_PARTSTAT_DECLINED;
88 default:
89 return I_CAL_PARTSTAT_NEEDSACTION;
90 }
91 }
92
93 static uint32_t
94 get_trackstatus_from_partstat (ICalParameterPartstat partstat)
95 {
96 switch (partstat) {
97 case I_CAL_PARTSTAT_ACCEPTED:
98 return olResponseAccepted;
99 case I_CAL_PARTSTAT_TENTATIVE:
100 return olResponseTentative;
101 case I_CAL_PARTSTAT_DECLINED:
102 return olResponseDeclined;
103 default:
104 return olResponseNone;
105 }
106 }
107
108 static ICalPropertyTransp
109 get_transp_from_prop (uint32_t prop)
110 {
111 /* FIXME: is this mapping correct ? */
112 switch (prop) {
113 case olFree:
114 case olTentative:
115 return I_CAL_TRANSP_TRANSPARENT;
116 case olBusy:
117 case olOutOfOffice:
118 default:
119 return I_CAL_TRANSP_OPAQUE;
120 }
121 }
122
123 static uint32_t
124 get_prop_from_transp (ICalPropertyTransp transp)
125 {
126 /* FIXME: is this mapping correct ? */
127 switch (transp) {
128 case I_CAL_TRANSP_TRANSPARENT:
129 case I_CAL_TRANSP_TRANSPARENTNOCONFLICT:
130 return olFree;
131 case I_CAL_TRANSP_OPAQUE:
132 case I_CAL_TRANSP_OPAQUENOCONFLICT:
133 default:
134 return olBusy;
135 }
136 }
137
138 static ICalPropertyStatus
139 get_taskstatus_from_prop (uint32_t prop)
140 {
141 /* FIXME: is this mapping correct ? */
142 switch (prop) {
143 case olTaskComplete:
144 return I_CAL_STATUS_COMPLETED;
145 case olTaskWaiting:
146 case olTaskInProgress:
147 return I_CAL_STATUS_INPROCESS;
148 case olTaskDeferred:
149 return I_CAL_STATUS_CANCELLED;
150 case olTaskNotStarted:
151 default:
152 return I_CAL_STATUS_NEEDSACTION;
153 }
154 }
155
156 static uint32_t
157 get_prop_from_taskstatus (ICalPropertyStatus status)
158 {
159 /* FIXME: is this mapping correct ? */
160 switch (status) {
161 case I_CAL_STATUS_INPROCESS:
162 return olTaskInProgress;
163 case I_CAL_STATUS_COMPLETED:
164 return olTaskComplete;
165 case I_CAL_STATUS_CANCELLED:
166 return olTaskDeferred;
167 default:
168 return olTaskNotStarted;
169 }
170 }
171
172 static ICalProperty_Class
173 get_class_from_prop (uint32_t prop)
174 {
175 /* FIXME: is this mapping correct ? */
176 switch (prop) {
177 case olPersonal:
178 case olPrivate:
179 return I_CAL_CLASS_PRIVATE;
180 case olConfidential:
181 return I_CAL_CLASS_CONFIDENTIAL;
182 case olNormal:
183 default:
184 return I_CAL_CLASS_PUBLIC;
185 }
186 }
187
188 static uint32_t
189 get_prop_from_class (ICalProperty_Class classif)
190 {
191 /* FIXME: is this mapping correct ? */
192 switch (classif) {
193 case I_CAL_CLASS_PRIVATE:
194 return olPrivate;
195 case I_CAL_CLASS_CONFIDENTIAL:
196 return olConfidential;
197 default:
198 return olNormal;
199 }
200 }
201
202 static gint
203 get_priority_from_prop (uint32_t prop)
204 {
205 switch (prop) {
206 case PRIORITY_LOW : return 7;
207 case PRIORITY_HIGH : return 1;
208 case PRIORITY_NORMAL :
209 default : return 5;
210 }
211 }
212
213 static uint32_t
214 get_prio_prop_from_priority (gint priority)
215 {
216 if (priority > 0 && priority <= 4)
217 return PRIORITY_HIGH;
218 else if (priority > 5 && priority <= 9)
219 return PRIORITY_LOW;
220 else
221 return PRIORITY_NORMAL;
222 }
223
224 static uint32_t
225 get_imp_prop_from_priority (gint priority)
226 {
227 if (priority > 0 && priority <= 4)
228 return IMPORTANCE_HIGH;
229 else if (priority > 5 && priority <= 9)
230 return IMPORTANCE_LOW;
231 else
232 return IMPORTANCE_NORMAL;
233 }
234
235 #define RECIP_SENDABLE 0x1
236 #define RECIP_ORGANIZER 0x2
237
238 static const uint8_t GID_START_SEQ[] = {
239 0x04, 0x00, 0x00, 0x00, 0x82, 0x00, 0xe0, 0x00,
240 0x74, 0xc5, 0xb7, 0x10, 0x1a, 0x82, 0xe0, 0x08
241 };
242
243 /* exception_replace_time is a value of PidLidExceptionReplaceTime; this is not used for 'clean' object ids.
244 creation_time is a value of PR_CREATION_TIME
245 */
246 void
247 e_mapi_cal_util_generate_globalobjectid (gboolean is_clean,
248 const gchar *uid,
249 const struct timeval *exception_replace_time,
250 const struct FILETIME *creation_time,
251 struct SBinary_short *sb)
252 {
253 GByteArray *ba;
254 guint32 val32;
255 guchar *buf = NULL;
256 gsize len;
257 d(guint32 i);
258
259 ba = g_byte_array_new ();
260
261 ba = g_byte_array_append (ba, GID_START_SEQ, (sizeof (GID_START_SEQ) / sizeof (GID_START_SEQ[0])));
262
263 val32 = 0;
264 if (!is_clean && exception_replace_time) {
265 ICalTime *itt = i_cal_time_new_from_timet_with_zone (exception_replace_time->tv_sec, 0, i_cal_timezone_get_utc_timezone ());
266
267 val32 |= (i_cal_time_get_year (itt) & 0xFF00) << 16;
268 val32 |= (i_cal_time_get_year (itt) & 0xFF) << 16;
269 val32 |= (i_cal_time_get_month (itt) & 0xFF) << 8;
270 val32 |= (i_cal_time_get_day (itt) & 0xFF);
271
272 g_clear_object (&itt);
273 }
274
275 ba = g_byte_array_append (ba, (const guint8 *) &val32, sizeof (guint32));
276
277 /* creation time */
278 val32 = creation_time ? creation_time->dwLowDateTime : 0;
279 ba = g_byte_array_append (ba, (const guint8 *) &val32, sizeof (guint32));
280 val32 = creation_time ? creation_time->dwHighDateTime : 0;
281 ba = g_byte_array_append (ba, (const guint8 *) &val32, sizeof (guint32));
282
283 /* RESERVED - should be all 0's */
284 val32 = 0;
285 ba = g_byte_array_append (ba, (const guint8 *) &val32, sizeof (guint32));
286 val32 = 0;
287 ba = g_byte_array_append (ba, (const guint8 *) &val32, sizeof (guint32));
288
289 /* We put Evolution's UID in base64 here */
290 buf = g_base64_decode (uid, &len);
291 if (len % 2 != 0)
292 --len;
293 val32 = len;
294
295 /* Size in bytes of the following data */
296 ba = g_byte_array_append (ba, (const guint8 *) &val32, sizeof (guint32));
297 /* Data */
298 ba = g_byte_array_append (ba, (const guint8 *)buf, val32);
299 g_free (buf);
300
301 sb->lpb = ba->data;
302 sb->cb = ba->len;
303
304 d(g_message ("New GlobalObjectId.. Length: %d bytes.. Hex-data follows:", ba->len));
305 d(for (i = 0; i < ba->len; i++)
306 g_print("0x%02X ", ba->data[i]));
307
308 g_byte_array_free (ba, FALSE);
309 }
310
311 /* returns complete globalid as base64 encoded string */
312 static gchar *
313 globalid_to_string (const guint8 *lpb,
314 guint32 cb)
315 {
316 const guint8 *ptr;
317 guint32 i, j;
318
319 g_return_val_if_fail (lpb != NULL, NULL);
320
321 /* MSDN docs: the globalID must have an even number of bytes */
322 if ((cb) % 2 != 0)
323 return NULL;
324
325 ptr = lpb;
326
327 /* starting seq - len = 16 bytes */
328 for (i = 0, j = 0; i < cb && j < sizeof (GID_START_SEQ); i++, ptr++, j++) {
329 if (*ptr != GID_START_SEQ[j])
330 return NULL;
331 }
332
333 /* take complete global id */
334 return g_base64_encode (lpb, cb);
335 }
336
337 /* retrieves timezone location from a timezone ID */
338 static const gchar *
339 get_tzid_location (const gchar *tzid,
340 struct cal_cbdata *cbdata)
341 {
342 ICalTimezone *zone = NULL;
343
344 if (!tzid || !*tzid || g_str_equal (tzid, "UTC"))
345 return NULL;
346
347 /* ask backend first, if any */
348 if (cbdata && cbdata->get_timezone)
349 zone = cbdata->get_timezone (cbdata->get_tz_data, tzid);
350
351 if (!zone)
352 zone = i_cal_timezone_get_builtin_timezone_from_tzid (tzid);
353
354 /* the old TZID prefix used in previous versions of evolution-mapi */
355 #define OLD_TZID_PREFIX "/softwarestudio.org/Tzfile/"
356
357 if (!zone && g_str_has_prefix (tzid, OLD_TZID_PREFIX))
358 zone = i_cal_timezone_get_builtin_timezone (tzid + strlen (OLD_TZID_PREFIX));
359
360 #undef OLD_TZID_PREFIX
361
362 if (!zone)
363 return NULL;
364
365 return i_cal_timezone_get_location (zone);
366 }
367
368 #define MINUTES_IN_HOUR 60
369 #define SECS_IN_MINUTE 60
370
371 static gboolean
372 emcu_build_restriction (EMapiConnection *conn,
373 TALLOC_CTX *mem_ctx,
374 struct mapi_SRestriction **restrictions,
375 gpointer user_data,
376 GCancellable *cancellable,
377 GError **perror)
378 {
379 struct mapi_SRestriction *restriction;
380 struct SPropValue sprop;
381 uint32_t *id = user_data;
382
383 g_return_val_if_fail (conn != NULL, FALSE);
384 g_return_val_if_fail (mem_ctx != NULL, FALSE);
385 g_return_val_if_fail (restrictions != NULL, FALSE);
386 g_return_val_if_fail (id != NULL, FALSE);
387
388 restriction = talloc_zero (mem_ctx, struct mapi_SRestriction);
389 g_return_val_if_fail (restriction != NULL, FALSE);
390
391 restriction->rt = RES_PROPERTY;
392 restriction->res.resProperty.relop = RELOP_EQ;
393 restriction->res.resProperty.ulPropTag = PR_OWNER_APPT_ID;
394
395 set_SPropValue_proptag (&sprop, PR_OWNER_APPT_ID, id);
396 cast_mapi_SPropValue (mem_ctx, &(restriction->res.resProperty.lpProp), &sprop);
397
398 *restrictions = restriction;
399
400 return TRUE;
401 }
402
403 static gboolean
404 emcu_check_id_exists_cb (EMapiConnection *conn,
405 TALLOC_CTX *mem_ctx,
406 const ListObjectsData *object_data,
407 guint32 obj_index,
408 guint32 obj_total,
409 gpointer user_data,
410 GCancellable *cancellable,
411 GError **perror)
412 {
413 gboolean *unused = user_data;
414
415 g_return_val_if_fail (unused != NULL, FALSE);
416
417 *unused = FALSE;
418
419 return FALSE;
420 }
421
422 uint32_t
423 e_mapi_cal_util_get_new_appt_id (EMapiConnection *conn, mapi_id_t fid)
424 {
425 uint32_t id;
426 gboolean unused = FALSE;
427 mapi_object_t obj_folder;
428
429 if (!e_mapi_connection_open_personal_folder (conn, fid, &obj_folder, NULL, NULL))
430 return g_random_int ();
431
432 while (!unused) {
433 id = g_random_int ();
434 if (id) {
435 unused = TRUE;
436 if (!e_mapi_connection_list_objects (conn, &obj_folder, emcu_build_restriction, &id, emcu_check_id_exists_cb, &unused, NULL, NULL))
437 break;
438 }
439 }
440
441 e_mapi_connection_close_folder (conn, &obj_folder, NULL, NULL);
442
443 return id;
444 }
445
446 static time_t
447 mapi_get_date_from_string (const gchar *dtstring)
448 {
449 time_t t = 0;
450 GTimeVal t_val;
451
452 g_return_val_if_fail (dtstring != NULL, 0);
453
454 if (g_time_val_from_iso8601 (dtstring, &t_val)) {
455 t = (time_t) t_val.tv_sec;
456 } else if (strlen (dtstring) == 8) {
457 /* It might be a date value */
458 GDate date;
459 struct tm tt;
460 guint16 year;
461 guint month;
462 guint8 day;
463
464 g_date_clear (&date, 1);
465 #define digit_at(x,y) (x[y] - '0')
466 year = digit_at (dtstring, 0) * 1000
467 + digit_at (dtstring, 1) * 100
468 + digit_at (dtstring, 2) * 10
469 + digit_at (dtstring, 3);
470 month = digit_at (dtstring, 4) * 10 + digit_at (dtstring, 5);
471 day = digit_at (dtstring, 6) * 10 + digit_at (dtstring, 7);
472
473 g_date_set_year (&date, year);
474 g_date_set_month (&date, month);
475 g_date_set_day (&date, day);
476
477 g_date_to_struct_tm (&date, &tt);
478 t = mktime (&tt);
479
480 } else
481 g_warning ("Could not parse the string \n");
482
483 return t;
484 }
485
486 static void
487 populate_freebusy_data (struct Binary_r *bin,
488 uint32_t month,
489 uint32_t year,
490 GSList **freebusy,
491 const gchar *accept_type,
492 ECalComponent *comp)
493 {
494 uint16_t event_start;
495 uint16_t event_end;
496 uint32_t i;
497 uint32_t day;
498 const gchar *month_name;
499 uint32_t minutes;
500 uint32_t real_month;
501 gchar *date_string = NULL;
502 gchar *start = NULL, *end = NULL;
503 time_t start_date, end_date;
504 ICalComponent *icomp = NULL;
505
506 if (!bin)
507 return;
508 /* bin.cb must be a multiple of 4 */
509 if (bin->cb % 4)
510 return;
511
512 year = mapidump_freebusy_year(month, year);
513 month_name = mapidump_freebusy_month(month, year);
514 if (!month_name)
515 return;
516
517 for (i = 0; i < bin->cb; i+= 4) {
518 event_start = (bin->lpb[i + 1] << 8) | bin->lpb[i];
519 event_end = (bin->lpb[i + 3] << 8) | bin->lpb[i + 2];
520
521 if (event_start <= event_end) {
522 ICalPeriod *period;
523 ICalProperty *prop;
524 ICalTime *itt;
525
526 day = 1;
527 minutes = 0;
528 real_month = month - (year * 16);
529
530 date_string = g_strdup_printf ("%.2u-%.2u-%.2u", year, real_month, day);
531 start = g_strdup_printf ("%sT%.2u:%.2u:00Z", date_string, 0, minutes);
532 g_free (date_string);
533
534 date_string = g_strdup_printf ("%.2u-%.2u-%.2u", year, real_month, day);
535 end = g_strdup_printf ("%sT%.2u:%.2u:00Z", date_string, 0, minutes);
536 g_free (date_string);
537
538 start_date = mapi_get_date_from_string (start) + (60 * event_start);
539 end_date = mapi_get_date_from_string (end) + (60 * event_end);
540
541 period = i_cal_period_new_null_period ();
542
543 itt = i_cal_time_new_from_timet_with_zone (start_date, 0, i_cal_timezone_get_utc_timezone ());
544 i_cal_period_set_start (period, itt);
545 g_clear_object (&itt);
546
547 itt = i_cal_time_new_from_timet_with_zone (end_date, 0, i_cal_timezone_get_utc_timezone ());
548 i_cal_period_set_end (period, itt);
549 g_clear_object (&itt);
550
551 icomp = e_cal_component_get_icalcomponent (comp);
552 prop = i_cal_property_new_freebusy (period);
553
554 if (!strcmp (accept_type, "Busy"))
555 i_cal_property_set_parameter_from_string (prop, "FBTYPE", "BUSY");
556 else if (!strcmp (accept_type, "Tentative"))
557 i_cal_property_set_parameter_from_string (prop, "FBTYPE", "BUSY-TENTATIVE");
558 else if (!strcmp (accept_type, "OutOfOffice"))
559 i_cal_property_set_parameter_from_string (prop, "FBTYPE", "BUSY-UNAVAILABLE");
560
561 i_cal_component_take_property (icomp, prop);
562
563 g_clear_object (&period);
564 g_free (start);
565 g_free (end);
566 }
567 }
568 }
569
570 gboolean
571 e_mapi_cal_utils_get_free_busy_data (EMapiConnection *conn,
572 const GSList *users,
573 time_t start,
574 time_t end,
575 GSList **freebusy,
576 GCancellable *cancellable,
577 GError **mapi_error)
578 {
579 struct SRow aRow;
580 enum MAPISTATUS ms;
581 uint32_t i;
582 mapi_object_t obj_folder;
583 const GSList *link;
584
585 const uint32_t *publish_start;
586 const struct LongArray_r *busy_months;
587 const struct BinaryArray_r *busy_events;
588 const struct LongArray_r *tentative_months;
589 const struct BinaryArray_r *tentative_events;
590 const struct LongArray_r *oof_months;
591 const struct BinaryArray_r *oof_events;
592 uint32_t year;
593 uint32_t event_year;
594
595 ECalComponent *comp;
596 ECalComponentAttendee *attendee;
597 GSList *attendees;
598 ICalComponent *icomp = NULL;
599 ICalTime *starttt, *endtt;
600
601 *freebusy = NULL;
602
603 mapi_object_init (&obj_folder);
604
605 if (!e_mapi_connection_get_public_folder (conn, &obj_folder, cancellable, mapi_error)) {
606 mapi_object_release (&obj_folder);
607 return FALSE;
608 }
609
610 for (link = users; link; link = g_slist_next (link)) {
611 ms = GetUserFreeBusyData (&obj_folder, (const gchar *) link->data, &aRow);
612
613 if (ms != MAPI_E_SUCCESS) {
614 gchar *context = g_strconcat ("GetUserFreeBusyData for ", link->data, NULL);
615
616 make_mapi_error (mapi_error, context, ms);
617
618 g_free (context);
619
620 mapi_object_release (&obj_folder);
621
622 return FALSE;
623 }
624
625 /* Step 2. Dump properties */
626 publish_start = (const uint32_t *) find_SPropValue_data(&aRow, PR_FREEBUSY_START_RANGE);
627 busy_months = (const struct LongArray_r *) find_SPropValue_data(&aRow, PR_FREEBUSY_BUSY_MONTHS);
628 busy_events = (const struct BinaryArray_r *) find_SPropValue_data(&aRow, PR_FREEBUSY_BUSY_EVENTS);
629 tentative_months = (const struct LongArray_r *) find_SPropValue_data(&aRow, PR_FREEBUSY_TENTATIVE_MONTHS);
630 tentative_events = (const struct BinaryArray_r *) find_SPropValue_data(&aRow, PR_FREEBUSY_TENTATIVE_EVENTS);
631 oof_months = (const struct LongArray_r *) find_SPropValue_data(&aRow, PR_FREEBUSY_OOF_MONTHS);
632 oof_events = (const struct BinaryArray_r *) find_SPropValue_data(&aRow, PR_FREEBUSY_OOF_EVENTS);
633
634 year = GetFreeBusyYear(publish_start);
635
636 comp = e_cal_component_new ();
637 e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_FREEBUSY);
638 e_cal_component_commit_sequence (comp);
639 icomp = e_cal_component_get_icalcomponent (comp);
640
641 starttt = i_cal_time_new_from_timet_with_zone (start, 0, NULL);
642 endtt = i_cal_time_new_from_timet_with_zone (end, 0, NULL);
643 i_cal_component_set_dtstart (icomp, starttt);
644 i_cal_component_set_dtend (icomp, endtt);
645 g_clear_object (&starttt);
646 g_clear_object (&endtt);
647
648 attendee = e_cal_component_attendee_new ();
649 if (link->data) {
650 if (g_ascii_strncasecmp (link->data, "mailto:", 7) != 0) {
651 gchar *mailto;
652
653 mailto = g_strconcat ("mailto:", link->data, NULL);
654 e_cal_component_attendee_set_value (attendee, mailto);
655 g_free (mailto);
656 } else {
657 e_cal_component_attendee_set_value (attendee, link->data);
658 }
659 }
660
661 e_cal_component_attendee_set_cutype (attendee, I_CAL_CUTYPE_INDIVIDUAL);
662 e_cal_component_attendee_set_role (attendee, I_CAL_ROLE_REQPARTICIPANT);
663 e_cal_component_attendee_set_partstat (attendee, I_CAL_PARTSTAT_NEEDSACTION);
664
665 attendees = g_slist_append (NULL, attendee);
666
667 e_cal_component_set_attendees (comp, attendees);
668 g_slist_free_full (attendees, e_cal_component_attendee_free);
669
670 if (busy_months && ((*(const uint32_t *) busy_months) != MAPI_E_NOT_FOUND) &&
671 busy_events && ((*(const uint32_t *) busy_events) != MAPI_E_NOT_FOUND)) {
672 for (i = 0; i < busy_months->cValues; i++) {
673 event_year = mapidump_freebusy_year(busy_months->lpl[i], year);
674 populate_freebusy_data (&busy_events->lpbin[i], busy_months->lpl[i], event_year, freebusy, "Busy", comp);
675 }
676 }
677
678 if (tentative_months && ((*(const uint32_t *) tentative_months) != MAPI_E_NOT_FOUND) &&
679 tentative_events && ((*(const uint32_t *) tentative_events) != MAPI_E_NOT_FOUND)) {
680 for (i = 0; i < tentative_months->cValues; i++) {
681 event_year = mapidump_freebusy_year(tentative_months->lpl[i], year);
682 populate_freebusy_data (&tentative_events->lpbin[i], tentative_months->lpl[i], event_year, freebusy, "Tentative", comp);
683 }
684 }
685
686 if (oof_months && ((*(const uint32_t *) oof_months) != MAPI_E_NOT_FOUND) &&
687 oof_events && ((*(const uint32_t *) oof_events) != MAPI_E_NOT_FOUND)) {
688 for (i = 0; i < oof_months->cValues; i++) {
689 event_year = mapidump_freebusy_year(oof_months->lpl[i], year);
690 populate_freebusy_data (&oof_events->lpbin[i], oof_months->lpl[i], event_year, freebusy, "OutOfOffice", comp);
691 }
692 }
693
694 e_cal_component_commit_sequence (comp);
695 *freebusy = g_slist_append (*freebusy, e_cal_component_get_as_string (comp));
696 g_object_unref (comp);
697 talloc_free (aRow.lpProps);
698 }
699
700 mapi_object_release (&obj_folder);
701
702 return TRUE;
703 }
704
705 static void
706 populate_ical_attendees (EMapiConnection *conn,
707 EMapiRecipient *recipients,
708 ICalComponent *icomp,
709 gboolean rsvp)
710 {
711 const uint32_t name_proptags[] = {
712 PROP_TAG (PT_UNICODE, 0x6001), /* PidTagNickname for Recipients table */
713 PidTagNickname,
714 PidTagRecipientDisplayName,
715 PidTagDisplayName,
716 PidTagAddressBookDisplayNamePrintable
717 };
718
719 const uint32_t email_proptags[] = {
720 PidTagSmtpAddress
721 };
722
723 EMapiRecipient *recipient;
724
725 g_return_if_fail (conn != NULL);
726 g_return_if_fail (icomp != NULL);
727
728 for (recipient = recipients; recipient; recipient = recipient->next) {
729 gchar *name = NULL, *email = NULL, *icalemail;
730 ICalProperty *prop;
731 ICalParameter *param;
732 const uint32_t *ui32;
733 const uint32_t *flags;
734
735 e_mapi_mail_utils_decode_email_address (conn, &recipient->properties,
736 name_proptags, G_N_ELEMENTS (name_proptags),
737 email_proptags, G_N_ELEMENTS (email_proptags),
738 PidTagAddressType, PidTagEmailAddress,
739 &name, &email);
740
741 if (!email) {
742 g_free (name);
743 g_debug ("%s: Skipping event recipient without email", G_STRFUNC);
744 continue;
745 }
746
747 icalemail = g_strconcat ("mailto:", email, NULL);
748
749 flags = e_mapi_util_find_array_propval (&recipient->properties, PidTagRecipientFlags);
750
751 if (flags && (*flags & RECIP_ORGANIZER)) {
752 prop = i_cal_property_new_organizer (icalemail);
753
754 /* CN */
755 if (name && *name) {
756 param = i_cal_parameter_new_cn (name);
757 i_cal_property_take_parameter (prop, param);
758 }
759 } else {
760 prop = i_cal_property_new_attendee (icalemail);
761
762 /* CN */
763 if (name && *name) {
764 param = i_cal_parameter_new_cn (name);
765 i_cal_property_take_parameter (prop, param);
766 }
767
768 /* RSVP */
769 param = i_cal_parameter_new_rsvp (rsvp ? I_CAL_RSVP_TRUE : I_CAL_RSVP_FALSE);
770 i_cal_property_take_parameter (prop, param);
771
772 /* PARTSTAT */
773 ui32 = e_mapi_util_find_array_propval (&recipient->properties, PidTagRecipientTrackStatus);
774 param = i_cal_parameter_new_partstat (get_partstat_from_trackstatus (ui32 ? *ui32 : olResponseNone));
775 i_cal_property_take_parameter (prop, param);
776
777 /* ROLE */
778 ui32 = e_mapi_util_find_array_propval (&recipient->properties, PidTagRecipientType);
779 param = i_cal_parameter_new_role (get_role_from_type (ui32 ? *ui32 : olTo));
780 i_cal_property_take_parameter (prop, param);
781
782 /* CALENDAR USER TYPE */
783 param = NULL;
784 if (ui32 && *ui32 == 0x03)
785 param = i_cal_parameter_new_cutype (I_CAL_CUTYPE_RESOURCE);
786 if (!param)
787 param = i_cal_parameter_new_cutype (I_CAL_CUTYPE_INDIVIDUAL);
788
789 i_cal_property_take_parameter (prop, param);
790 }
791
792 i_cal_component_take_property (icomp, prop);
793
794 g_free (icalemail);
795 g_free (email);
796 g_free (name);
797 }
798 }
799
800 static void
801 set_attachments_to_comp (EMapiConnection *conn,
802 EMapiAttachment *attachments,
803 ECalComponent *comp)
804 {
805 EMapiAttachment *attach;
806 ICalComponent *icomp;
807
808 g_return_if_fail (comp != NULL);
809
810 if (!attachments)
811 return;
812
813 icomp = e_cal_component_get_icalcomponent (comp);
814 g_return_if_fail (icomp != NULL);
815
816 for (attach = attachments; attach; attach = attach->next) {
817 uint64_t data_cb = 0;
818 const uint8_t *data_lpb = NULL;
819 const gchar *filename;
820 ICalAttach *new_attach;
821 ICalParameter *param;
822 gchar *base64;
823 ICalProperty *prop;
824
825 if (!e_mapi_attachment_get_bin_prop (attach, PidTagAttachDataBinary, &data_cb, &data_lpb)) {
826 g_debug ("%s: Skipping calendar attachment without data", G_STRFUNC);
827 continue;
828 }
829
830 filename = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachLongFilename);
831 if (!filename || !*filename)
832 filename = e_mapi_util_find_array_propval (&attach->properties, PidTagAttachFilename);
833
834 base64 = g_base64_encode ((const guchar *) data_lpb, data_cb);
835 new_attach = i_cal_attach_new_from_data (base64, (GFunc) g_free, NULL);
836
837 prop = i_cal_property_new_attach (new_attach);
838 g_object_unref (new_attach);
839
840 param = i_cal_parameter_new_value (I_CAL_VALUE_BINARY);
841 i_cal_property_take_parameter (prop, param);
842
843 param = i_cal_parameter_new_encoding (I_CAL_ENCODING_BASE64);
844 i_cal_property_take_parameter (prop, param);
845
846 if (filename && *filename) {
847 param = i_cal_parameter_new_filename (filename);
848 i_cal_property_take_parameter (prop, param);
849 }
850
851 i_cal_component_take_property (icomp, prop);
852 }
853 }
854
855 ECalComponent *
856 e_mapi_cal_util_object_to_comp (EMapiConnection *conn,
857 EMapiObject *object,
858 ICalComponentKind kind,
859 gboolean is_reply,
860 const gchar *use_uid,
861 GSList **detached_components)
862 {
863 ECalComponent *comp = NULL;
864 struct timeval t;
865 const gchar *str;
866 const struct mapi_SLPSTRArrayW *categories_array;
867 const struct SBinary_short *bin;
868 const uint32_t *ui32;
869 const uint8_t *b;
870 ICalComponent *icomp;
871 ICalProperty *prop = NULL;
872 ICalParameter *param = NULL;
873 ICalTimezone *utc_zone;
874 ICalTime *itt;
875
876 g_return_val_if_fail (conn != NULL, NULL);
877 g_return_val_if_fail (object != NULL, NULL);
878 g_return_val_if_fail (use_uid != NULL, NULL);
879
880 if (e_mapi_debug_is_enabled ()) {
881 printf ("%s:\n", G_STRFUNC);
882 e_mapi_debug_dump_object (object, TRUE, 3);
883 }
884
885 switch (kind) {
886 case I_CAL_VEVENT_COMPONENT:
887 case I_CAL_VTODO_COMPONENT:
888 case I_CAL_VJOURNAL_COMPONENT:
889 icomp = i_cal_component_new (kind);
890 comp = e_cal_component_new_from_icalcomponent (icomp);
891 if (!comp) {
892 return NULL;
893 }
894 e_cal_component_set_uid (comp, use_uid);
895 break;
896 default:
897 return NULL;
898 }
899
900 utc_zone = i_cal_timezone_get_utc_timezone ();
901
902 str = e_mapi_util_find_array_propval (&object->properties, PidTagSubject);
903 str = str ? str : e_mapi_util_find_array_propval (&object->properties, PidTagNormalizedSubject);
904 str = str ? str : e_mapi_util_find_array_propval (&object->properties, PidTagConversationTopic);
905 str = str ? str : "";
906 i_cal_component_set_summary (icomp, str);
907
908 ui32 = e_mapi_util_find_array_propval (&object->properties, PidTagInternetCodepage);
909 if (e_mapi_object_contains_prop (object, PidTagBody)) {
910 uint64_t text_cb = 0;
911 const uint8_t *text_lpb = NULL;
912 gchar *utf8_str = NULL;
913 uint32_t proptag;
914
915 proptag = e_mapi_util_find_array_proptag (&object->properties, PidTagBody);
916 if (!proptag) {
917 EMapiStreamedProp *stream = e_mapi_object_get_streamed (object, PidTagBody);
918 if (stream)
919 proptag = stream->proptag;
920 else
921 proptag = PidTagBody;
922 }
923
924 if (e_mapi_object_get_bin_prop (object, proptag, &text_cb, &text_lpb)) {
925 if (e_mapi_utils_ensure_utf8_string (proptag, ui32, text_lpb, text_cb, &utf8_str))
926 str = utf8_str;
927 else if (text_lpb [text_cb] != 0) {
928 utf8_str = g_strndup ((const gchar *) text_lpb, text_cb);
929 str = utf8_str;
930 }
931 } else {
932 str = "";
933 }
934
935 i_cal_component_set_description (icomp, str);
936
937 g_free (utf8_str);
938 } else {
939 uint64_t html_cb = 0;
940 const uint8_t *html_lpb = NULL;
941
942 if (e_mapi_object_get_bin_prop (object, PidTagHtml, &html_cb, &html_lpb)) {
943 gchar *utf8_str = NULL;
944
945 if (e_mapi_utils_ensure_utf8_string (PidTagHtml, ui32, html_lpb, html_cb, &utf8_str))
946 i_cal_component_set_description (icomp, utf8_str);
947
948 g_free (utf8_str);
949 }
950 }
951
952 /* set dtstamp - in UTC */
953 if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidTagCreationTime) == MAPI_E_SUCCESS) {
954 itt = i_cal_time_new_from_timet_with_zone (t.tv_sec, 0, utc_zone);
955 i_cal_component_set_dtstamp (icomp, itt);
956
957 prop = i_cal_property_new_created (itt);
958 i_cal_component_take_property (icomp, prop);
959
960 g_clear_object (&itt);
961 } else {
962 /* created - in UTC */
963 itt = i_cal_time_new_current_with_zone (utc_zone);
964 prop = i_cal_property_new_created (itt);
965 i_cal_component_take_property (icomp, prop);
966 g_clear_object (&itt);
967 }
968
969 /* last modified - in UTC */
970 if (get_mapi_SPropValue_array_date_timeval (&t, &object->properties, PidTagLastModificationTime) == MAPI_E_SUCCESS) {
971 itt = i_cal_time_new_from_timet_with_zone (t.tv_sec, 0, utc_zone);
972 prop = i_cal_property_new_lastmodified (itt);
973 i_cal_component_take_property (icomp, prop);
974 g_clear_object (&itt);
975 }
976
977 categories_array = e_mapi_util_find_array_propval (&object->properties, PidNameKeywords);
978 if (categories_array) {
979 GSList *categories = NULL;
980 gint ii;
981
982 for (ii = 0; ii < categories_array->cValues; ii++) {
983 const gchar *category = categories_array->strings[ii].lppszW;
984
985 if (!category || !*category)
986 continue;
987
988 categories = g_slist_prepend (categories, (gpointer) category);
989 }
990
991 categories = g_slist_reverse (categories);
992
993 e_cal_component_set_categories_list (comp, categories);
994
995 g_slist_free (categories);
996 }
997
998 if (i_cal_component_isa (icomp) == I_CAL_VEVENT_COMPONENT) {
999 const gchar *location = NULL;
1000 const gchar *dtstart_tz_location = NULL, *dtend_tz_location = NULL;
1001 gboolean all_day;
1002
1003 /* GlobalObjectId */
1004 bin = e_mapi_util_find_array_propval (&object->properties, PidLidGlobalObjectId);
1005 if (bin) {
1006 gchar *value = globalid_to_string (bin->lpb, bin->cb);
1007 e_cal_util_component_set_x_property (icomp, "X-EVOLUTION-MAPI-GLOBALID", value);
1008 if (value && *value) {
1009 e_cal_component_set_uid (comp, value);
1010
1011 if (!g_str_equal (value, use_uid))
1012 e_cal_util_component_set_x_property (icomp, "X-EVOLUTION-MAPI-MID", use_uid);
1013 }
1014
1015 g_free (value);
1016 }
1017
1018 ui32 = e_mapi_util_find_array_propval (&object->properties, PidTagOwnerAppointmentId);
1019 if (ui32) {
1020 gchar *value = e_mapi_util_mapi_id_to_string ((mapi_id_t) (*ui32));
1021
1022 e_cal_util_component_set_x_property (icomp, "X-EVOLUTION-MAPI-OWNER-APPT-ID", value);
1023
1024 g_free (value);
1025 }
1026
1027 /* AppointmentSequence */
1028 ui32 = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentSequence);
1029 if (ui32) {
1030 gchar *value = g_strdup_printf ("%d", *ui32);
1031
1032 e_cal_util_component_set_x_property (icomp, "X-EVOLUTION-MAPI-APPTSEQ", value);
1033
1034 g_free (value);
1035 }
1036
1037 location = e_mapi_util_find_array_propval (&object->properties, PidLidLocation);
1038 if (location && *location)
1039 i_cal_component_set_location (icomp, location);
1040
1041 b = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentSubType);
1042 all_day = b && *b;
1043
1044 bin = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentTimeZoneDefinitionStartDisplay);
1045 if (bin) {
1046 gchar *buf = e_mapi_cal_util_bin_to_mapi_tz (bin->lpb, bin->cb);
1047 dtstart_tz_location = e_mapi_cal_tz_util_get_ical_equivalent (buf);
1048 g_free (buf);
1049 }
1050
1051 if (!dtstart_tz_location) {
1052 bin = e_mapi_util_find_array_propval (&object->properties, PidLidTimeZoneStruct);
1053 if (bin)
1054 dtstart_tz_location = e_mapi_cal_tz_util_ical_from_zone_struct (bin->lpb, bin->cb);
1055 }
1056
1057 if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidLidAppointmentStartWhole) == MAPI_E_SUCCESS) {
1058 ICalTimezone *zone = dtstart_tz_location ? i_cal_timezone_get_builtin_timezone (dtstart_tz_location) : utc_zone;
1059
1060 itt = i_cal_time_new_from_timet_with_zone (t.tv_sec, all_day, zone);
1061 i_cal_time_set_timezone (itt, zone);
1062 prop = i_cal_property_new_dtstart (itt);
1063 if (!all_day && zone && i_cal_timezone_get_tzid (zone)) {
1064 i_cal_property_take_parameter (prop, i_cal_parameter_new_tzid (i_cal_timezone_get_tzid (zone)));
1065 }
1066
1067 i_cal_component_take_property (icomp, prop);
1068
1069 g_clear_object (&itt);
1070 }
1071
1072 bin = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentTimeZoneDefinitionEndDisplay);
1073 if (bin) {
1074 gchar *buf = e_mapi_cal_util_bin_to_mapi_tz (bin->lpb, bin->cb);
1075 dtend_tz_location = e_mapi_cal_tz_util_get_ical_equivalent (buf);
1076 g_free (buf);
1077 }
1078
1079 if (!dtend_tz_location) {
1080 bin = e_mapi_util_find_array_propval (&object->properties, PidLidTimeZoneStruct);
1081 if (bin)
1082 dtend_tz_location = e_mapi_cal_tz_util_ical_from_zone_struct (bin->lpb, bin->cb);
1083 }
1084
1085 if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidLidAppointmentEndWhole) == MAPI_E_SUCCESS) {
1086 ICalTimezone *zone;
1087
1088 if (!dtend_tz_location)
1089 dtend_tz_location = dtstart_tz_location;
1090
1091 zone = dtend_tz_location ? i_cal_timezone_get_builtin_timezone (dtend_tz_location) : utc_zone;
1092 itt = i_cal_time_new_from_timet_with_zone (t.tv_sec, all_day, zone);
1093 i_cal_time_set_timezone (itt, zone);
1094 prop = i_cal_property_new_dtend (itt);
1095 if (!all_day && zone && i_cal_timezone_get_tzid (zone)) {
1096 i_cal_property_take_parameter (prop, i_cal_parameter_new_tzid (i_cal_timezone_get_tzid (zone)));
1097 }
1098
1099 i_cal_component_take_property (icomp, prop);
1100 }
1101
1102 ui32 = e_mapi_util_find_array_propval (&object->properties, PidLidBusyStatus);
1103 if (ui32) {
1104 prop = i_cal_property_new_transp (get_transp_from_prop (*ui32));
1105 i_cal_component_take_property (icomp, prop);
1106 }
1107
1108 if (object->recipients) {
1109 gchar *name = NULL, *email = NULL;
1110 gchar *val;
1111
1112 b = e_mapi_util_find_array_propval (&object->properties, PidTagResponseRequested);
1113 populate_ical_attendees (conn, object->recipients, icomp, (b && *b));
1114 if (is_reply) {
1115 if (!e_cal_util_component_has_property (icomp, I_CAL_ORGANIZER_PROPERTY)) {
1116 name = NULL;
1117 email = NULL;
1118
1119 e_mapi_mail_utils_decode_email_address1 (conn, &object->properties,
1120 PidTagReceivedRepresentingName,
1121 PidTagReceivedRepresentingEmailAddress,
1122 PidTagReceivedRepresentingAddressType,
1123 &name, &email);
1124
1125 if (email) {
1126 val = g_strdup_printf ("mailto:%s", email);
1127 prop = i_cal_property_new_organizer (val);
1128 g_free (val);
1129
1130 if (name && g_strcmp0 (name, email) != 0) {
1131 /* CN */
1132 param = i_cal_parameter_new_cn (name);
1133 i_cal_property_take_parameter (prop, param);
1134 }
1135
1136 i_cal_component_take_property (icomp, prop);
1137 }
1138
1139 g_free (name);
1140 g_free (email);
1141 }
1142
1143 if (!e_cal_util_component_has_property (icomp, I_CAL_ATTENDEE_PROPERTY)) {
1144 name = NULL;
1145 email = NULL;
1146
1147 e_mapi_mail_utils_decode_email_address1 (conn, &object->properties,
1148 PidTagSentRepresentingName,
1149 PidTagSentRepresentingEmailAddress,
1150 PidTagSentRepresentingAddressType,
1151 &name, &email);
1152
1153 if (email) {
1154 val = g_strdup_printf ("mailto:%s", email);
1155 prop = i_cal_property_new_attendee (val);
1156 g_free (val);
1157
1158 if (name && g_strcmp0 (name, email) != 0) {
1159 /* CN */
1160 param = i_cal_parameter_new_cn (name);
1161 i_cal_property_take_parameter (prop, param);
1162 }
1163
1164 ui32 = e_mapi_util_find_array_propval (&object->properties, PidLidResponseStatus);
1165 param = i_cal_parameter_new_partstat (get_partstat_from_trackstatus (ui32 ? *ui32 : olResponseNone));
1166 i_cal_property_take_parameter (prop, param);
1167
1168 i_cal_component_take_property (icomp, prop);
1169 }
1170
1171 g_free (name);
1172 g_free (email);
1173 }
1174 } else if (!e_cal_util_component_has_property (icomp, I_CAL_ORGANIZER_PROPERTY)) {
1175 gchar *sent_name = NULL, *sent_email = NULL;
1176
1177 name = NULL;
1178 email = NULL;
1179
1180 e_mapi_mail_utils_decode_email_address1 (conn, &object->properties,
1181 PidTagSenderName,
1182 PidTagSenderEmailAddress,
1183 PidTagSenderAddressType,
1184 &name, &email);
1185
1186 e_mapi_mail_utils_decode_email_address1 (conn, &object->properties,
1187 PidTagSentRepresentingName,
1188 PidTagSentRepresentingEmailAddress,
1189 PidTagSentRepresentingAddressType,
1190 &sent_name, &sent_email);
1191
1192 if (sent_email) {
1193 val = g_strdup_printf ("mailto:%s", sent_email);
1194 prop = i_cal_property_new_organizer (val);
1195 g_free (val);
1196
1197 if (sent_name && g_strcmp0 (sent_name, sent_email) != 0) {
1198 /* CN */
1199 param = i_cal_parameter_new_cn (sent_name);
1200 i_cal_property_take_parameter (prop, param);
1201 }
1202
1203 /* SENTBY */
1204 if (email && g_utf8_collate (sent_email, email)) {
1205 val = g_strdup_printf ("mailto:%s", email);
1206 param = i_cal_parameter_new_sentby (val);
1207 i_cal_property_take_parameter (prop, param);
1208 g_free (val);
1209 }
1210
1211 i_cal_component_take_property (icomp, prop);
1212 }
1213
1214
1215 g_free (name);
1216 g_free (email);
1217 g_free (sent_name);
1218 g_free (sent_email);
1219 }
1220 }
1221
1222 b = e_mapi_util_find_array_propval (&object->properties, PidLidRecurring);
1223 if (b && *b) {
1224 bin = e_mapi_util_find_array_propval (&object->properties, PidLidAppointmentRecur);
1225 if (bin) {
1226 ICalTimezone *recur_zone;
1227 const gchar *recur_tz_location;
1228
1229 recur_tz_location = e_mapi_util_find_array_propval (&object->properties, PidLidTimeZoneDescription);
1230 if (recur_tz_location)
1231 recur_tz_location = e_mapi_cal_tz_util_get_ical_equivalent (recur_tz_location);
1232 recur_zone = recur_tz_location ? i_cal_timezone_get_builtin_timezone (recur_tz_location) : utc_zone;
1233
1234 e_mapi_cal_util_bin_to_rrule (bin->lpb, bin->cb, comp, detached_components, recur_zone);
1235 }
1236 }
1237
1238 b = e_mapi_util_find_array_propval (&object->properties, PidLidReminderSet);
1239 if (b && *b) {
1240 struct timeval start, displaytime;
1241
1242 if ((e_mapi_util_find_array_datetime_propval (&start, &object->properties, PidLidReminderTime) == MAPI_E_SUCCESS)
1243 && (e_mapi_util_find_array_datetime_propval (&displaytime, &object->properties, PidLidReminderSignalTime) == MAPI_E_SUCCESS)) {
1244 ECalComponentAlarm *e_alarm = e_cal_component_alarm_new ();
1245 ECalComponentAlarmTrigger *trigger;
1246 ICalDuration *duration;
1247 ICalTime *itt1, *itt2;
1248
1249 itt1 = i_cal_time_new_from_timet_with_zone (displaytime.tv_sec, 0, NULL);
1250 itt2 = i_cal_time_new_from_timet_with_zone (start.tv_sec, 0, NULL);
1251 duration = i_cal_time_subtract (itt1, itt2);
1252 g_clear_object (&itt1);
1253 g_clear_object (&itt2);
1254
1255 trigger = e_cal_component_alarm_trigger_new_relative (E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START, duration);
1256
1257 e_cal_component_alarm_set_action (e_alarm, E_CAL_COMPONENT_ALARM_DISPLAY);
1258 e_cal_component_alarm_take_trigger (e_alarm, trigger);
1259
1260 e_cal_component_add_alarm (comp, e_alarm);
1261 e_cal_component_alarm_free (e_alarm);
1262 g_clear_object (&duration);
1263 }
1264 } else
1265 e_cal_component_remove_all_alarms (comp);
1266
1267 } else if (i_cal_component_isa (icomp) == I_CAL_VTODO_COMPONENT) {
1268 const double *complete = NULL;
1269 const uint64_t *status = NULL;
1270
1271 /* NOTE: Exchange tasks are DATE values, not DATE-TIME values, but maybe someday, we could expect Exchange to support it;) */
1272 if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidLidTaskStartDate) == MAPI_E_SUCCESS) {
1273 itt = i_cal_time_new_from_timet_with_zone (t.tv_sec, 1, utc_zone);
1274 i_cal_component_set_dtstart (icomp, itt);
1275 g_clear_object (&itt);
1276 }
1277
1278 if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidLidTaskDueDate) == MAPI_E_SUCCESS) {
1279 itt = i_cal_time_new_from_timet_with_zone (t.tv_sec, 1, utc_zone);
1280 i_cal_component_set_due (icomp, itt);
1281 g_clear_object (&itt);
1282 }
1283
1284 status = e_mapi_util_find_array_propval (&object->properties, PidLidTaskStatus);
1285 if (status) {
1286 i_cal_component_set_status (icomp, get_taskstatus_from_prop (*status));
1287 if (*status == olTaskComplete
1288 && e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidLidTaskDateCompleted) == MAPI_E_SUCCESS) {
1289 itt = i_cal_time_new_from_timet_with_zone (t.tv_sec, 0, utc_zone);
1290 prop = i_cal_property_new_completed (itt);
1291 i_cal_component_take_property (icomp, prop);
1292 g_clear_object (&itt);
1293 }
1294 }
1295
1296 complete = e_mapi_util_find_array_propval (&object->properties, PidLidPercentComplete);
1297 if (complete) {
1298 prop = i_cal_property_new_percentcomplete ((gint) ((*complete) * 100 + 1e-9));
1299 i_cal_component_take_property (icomp, prop);
1300 }
1301
1302 b = e_mapi_util_find_array_propval (&object->properties, PidLidTaskFRecurring);
1303 if (b && *b) {
1304 g_debug ("%s: Evolution does not support recurring tasks.", G_STRFUNC);
1305 }
1306
1307 b = e_mapi_util_find_array_propval (&object->properties, PidLidReminderSet);
1308 if (b && *b) {
1309 struct timeval abs;
1310
1311 if (e_mapi_util_find_array_datetime_propval (&abs, &object->properties, PidLidReminderTime) == MAPI_E_SUCCESS) {
1312 ECalComponentAlarm *e_alarm = e_cal_component_alarm_new ();
1313 ECalComponentAlarmTrigger *trigger;
1314 ICalTime *abs_time;
1315
1316 abs_time = i_cal_time_new_from_timet_with_zone (abs.tv_sec, 0, utc_zone);
1317 trigger = e_cal_component_alarm_trigger_new_absolute (abs_time);
1318 g_clear_object (&abs_time);
1319
1320 e_cal_component_alarm_set_action (e_alarm, E_CAL_COMPONENT_ALARM_DISPLAY);
1321 e_cal_component_alarm_take_trigger (e_alarm, trigger);
1322
1323 e_cal_component_add_alarm (comp, e_alarm);
1324 e_cal_component_alarm_free (e_alarm);
1325 }
1326 } else
1327 e_cal_component_remove_all_alarms (comp);
1328
1329 } else if (i_cal_component_isa (icomp) == I_CAL_VJOURNAL_COMPONENT) {
1330 if (e_mapi_util_find_array_datetime_propval (&t, &object->properties, PidTagLastModificationTime) == MAPI_E_SUCCESS) {
1331 itt = i_cal_time_new_from_timet_with_zone (t.tv_sec, 1, utc_zone);
1332 i_cal_component_set_dtstart (icomp, itt);
1333 g_clear_object (&itt);
1334 }
1335 }
1336
1337 if (i_cal_component_isa (icomp) == I_CAL_VEVENT_COMPONENT ||
1338 i_cal_component_isa (icomp) == I_CAL_VTODO_COMPONENT) {
1339 /* priority */
1340 ui32 = e_mapi_util_find_array_propval (&object->properties, PidTagPriority);
1341 if (ui32) {
1342 prop = i_cal_property_new_priority (get_priority_from_prop (*ui32));
1343 i_cal_component_take_property (icomp, prop);
1344 }
1345 }
1346
1347 /* classification */
1348 ui32 = e_mapi_util_find_array_propval (&object->properties, PidTagSensitivity);
1349 if (ui32) {
1350 prop = i_cal_property_new_class (get_class_from_prop (*ui32));
1351 i_cal_component_take_property (icomp, prop);
1352 }
1353
1354 set_attachments_to_comp (conn, object->attachments, comp);
1355
1356 return comp;
1357 }
1358
1359 static void
1360 e_mapi_cal_utils_add_organizer (EMapiObject *object,
1361 ECalComponent *comp)
1362 {
1363 ICalComponent *icomp;
1364 ICalProperty *org_prop = NULL;
1365 const gchar *org = NULL;
1366
1367 g_return_if_fail (object != NULL);
1368 g_return_if_fail (comp != NULL);
1369
1370 icomp = e_cal_component_get_icalcomponent (comp);
1371 org_prop = i_cal_component_get_first_property (icomp, I_CAL_ORGANIZER_PROPERTY);
1372 org = i_cal_property_get_organizer (org_prop);
1373 if (org && *org) {
1374 EMapiRecipient *recipient;
1375 uint32_t ui32 = 0;
1376 const gchar *str = NULL, *email;
1377 ICalParameter *param;
1378
1379 recipient = e_mapi_recipient_new (object);
1380 e_mapi_object_add_recipient (object, recipient);
1381
1382 #define set_value(pt,vl) { \
1383 if (!e_mapi_utils_add_property (&recipient->properties, pt, vl, recipient)) { \
1384 g_warning ("%s: Failed to set property 0x%x", G_STRFUNC, pt); \
1385 \
1386 return; \
1387 } \
1388 }
1389
1390 if (g_ascii_strncasecmp (org, "mailto:", 7) == 0)
1391 email = org + 7;
1392 else
1393 email = org;
1394
1395 set_value (PidTagAddressType, "SMTP");
1396 set_value (PidTagEmailAddress, email);
1397
1398 set_value (PidTagSmtpAddress, email);
1399
1400 ui32 = 0;
1401 set_value (PidTagSendInternetEncoding, &ui32);
1402
1403 ui32 = RECIP_SENDABLE | RECIP_ORGANIZER;
1404 set_value (PidTagRecipientFlags, &ui32);
1405
1406 ui32 = olResponseNone;
1407 set_value (PidTagRecipientTrackStatus, &ui32);
1408
1409 ui32 = olTo;
1410 set_value (PidTagRecipientType, &ui32);
1411
1412 param = i_cal_property_get_first_parameter (org_prop, I_CAL_CN_PARAMETER);
1413 str = param ? i_cal_parameter_get_cn (param) : NULL;
1414 str = (str && *str) ? str : email;
1415 set_value (PidTagRecipientDisplayName, str);
1416 set_value (PidTagDisplayName, str);
1417 g_clear_object (¶m);
1418
1419 ui32 = DT_MAILUSER;
1420 set_value (PidTagDisplayType, &ui32);
1421
1422 ui32 = MAPI_MAILUSER;
1423 set_value (PidTagObjectType, &ui32);
1424
1425 #undef set_value
1426 }
1427
1428 g_clear_object (&org_prop);
1429 }
1430
1431 static void
1432 e_mapi_cal_utils_add_recipients (EMapiObject *object,
1433 ECalComponent *comp)
1434 {
1435 ICalComponent *icomp;
1436 ICalProperty *org_prop = NULL, *att_prop = NULL;
1437 const gchar *org = NULL;
1438
1439 g_return_if_fail (object != NULL);
1440 g_return_if_fail (comp != NULL);
1441
1442 if (!e_cal_component_has_attendees (comp))
1443 return;
1444
1445 icomp = e_cal_component_get_icalcomponent (comp);
1446 org_prop = i_cal_component_get_first_property (icomp, I_CAL_ORGANIZER_PROPERTY);
1447 org = org_prop ? i_cal_property_get_organizer (org_prop) : NULL;
1448 if (!org)
1449 org = "";
1450
1451 for (att_prop = i_cal_component_get_first_property (icomp, I_CAL_ATTENDEE_PROPERTY);
1452 att_prop;
1453 g_object_unref (att_prop), att_prop = i_cal_component_get_next_property (icomp, I_CAL_ATTENDEE_PROPERTY)) {
1454 EMapiRecipient *recipient;
1455 uint32_t ui32 = 0;
1456 const gchar *str = NULL, *email;
1457 ICalParameter *param;
1458
1459 str = i_cal_property_get_attendee (att_prop);
1460 if (!str || g_ascii_strcasecmp (str, org) == 0)
1461 continue;
1462
1463 recipient = e_mapi_recipient_new (object);
1464 e_mapi_object_add_recipient (object, recipient);
1465
1466 #define set_value(pt,vl) { \
1467 if (!e_mapi_utils_add_property (&recipient->properties, pt, vl, recipient)) { \
1468 g_warning ("%s: Failed to set property 0x%x", G_STRFUNC, pt); \
1469 \
1470 return; \
1471 } \
1472 }
1473
1474 if (g_ascii_strncasecmp (str, "mailto:", 7) == 0)
1475 email = str + 7;
1476 else
1477 email = str;
1478
1479 set_value (PidTagAddressType, "SMTP");
1480 set_value (PidTagEmailAddress, email);
1481 set_value (PidTagSmtpAddress, email);
1482
1483 ui32 = 0;
1484 set_value (PidTagSendInternetEncoding, &ui32);
1485
1486 ui32 = RECIP_SENDABLE | (g_ascii_strcasecmp (str, org) == 0 ? RECIP_ORGANIZER : 0);
1487 set_value (PidTagRecipientFlags, &ui32);
1488
1489 param = i_cal_property_get_first_parameter (att_prop, I_CAL_PARTSTAT_PARAMETER);
1490 ui32 = get_trackstatus_from_partstat (param ? i_cal_parameter_get_partstat (param) : I_CAL_PARTSTAT_ACCEPTED);
1491 set_value (PidTagRecipientTrackStatus, &ui32);
1492 g_clear_object (¶m);
1493
1494 param = i_cal_property_get_first_parameter (att_prop, I_CAL_ROLE_PARAMETER);
1495 ui32 = get_type_from_role (param ? i_cal_parameter_get_role (param) : I_CAL_ROLE_NONE);
1496 set_value (PidTagRecipientType, &ui32);
1497 g_clear_object (¶m);
1498
1499 param = i_cal_property_get_first_parameter (att_prop, I_CAL_CN_PARAMETER);
1500 str = param ? i_cal_parameter_get_cn (param) : NULL;
1501 str = (str && *str) ? str : email;
1502 set_value (PidTagRecipientDisplayName, str);
1503 set_value (PidTagDisplayName, str);
1504 g_clear_object (¶m);
1505
1506 ui32 = DT_MAILUSER;
1507 set_value (PidTagDisplayType, &ui32);
1508
1509 ui32 = MAPI_MAILUSER;
1510 set_value (PidTagObjectType, &ui32);
1511
1512 #undef set_value
1513 }
1514
1515 g_clear_object (&org_prop);
1516 }
1517
1518 static void
1519 e_mapi_cal_utils_add_attachments (EMapiObject *object,
1520 ECalComponent *comp)
1521 {
1522 ICalComponent *icomp;
1523 ICalProperty *prop;
1524 const gchar *uid;
1525 gchar *safeuid;
1526
1527 g_return_if_fail (object != NULL);
1528 g_return_if_fail (comp != NULL);
1529
1530 if (!e_cal_component_has_attachments (comp))
1531 return;
1532
1533 uid = e_cal_component_get_uid (comp);
1534 icomp = e_cal_component_get_icalcomponent (comp);
1535
1536 safeuid = g_strdup (uid);
1537 e_filename_make_safe (safeuid);
1538 g_return_if_fail (safeuid != NULL);
1539
1540 for (prop = i_cal_component_get_first_property (icomp, I_CAL_ATTACH_PROPERTY);
1541 prop;
1542 g_object_unref (prop), prop = i_cal_component_get_next_property (icomp, I_CAL_ATTACH_PROPERTY)) {
1543 ICalAttach *attach = i_cal_property_get_attach (prop);
1544 ICalParameter *param;
1545 const gchar *sfname_uri, *stored_filename;
1546 gchar *sfname = NULL, *filename = NULL;
1547 GMappedFile *mapped_file;
1548 GError *error = NULL;
1549
1550 if (!I_CAL_IS_ATTACH (attach))
1551 continue;
1552
1553 #define set_value(pt,vl) { \
1554 if (!e_mapi_utils_add_property (&attachment->properties, pt, vl, attachment)) { \
1555 g_warning ("%s: Failed to set property 0x%x", G_STRFUNC, pt); \
1556 \
1557 return; \
1558 } \
1559 }
1560
1561 param = i_cal_property_get_first_parameter (prop, I_CAL_FILENAME_PARAMETER);
1562 stored_filename = param ? i_cal_parameter_get_filename (param) : NULL;
1563 if (stored_filename && !*stored_filename)
1564 stored_filename = NULL;
1565
1566 if (i_cal_attach_get_is_url (attach)) {
1567 sfname_uri = i_cal_attach_get_url (attach);
1568
1569 sfname = g_filename_from_uri (sfname_uri, NULL, NULL);
1570 mapped_file = g_mapped_file_new (sfname, FALSE, &error);
1571 filename = g_path_get_basename (sfname);
1572
1573 if (mapped_file) {
1574 EMapiAttachment *attachment;
1575 guint8 *attach = (guint8 *) g_mapped_file_get_contents (mapped_file);
1576 guint filelength = g_mapped_file_get_length (mapped_file);
1577 const gchar *split_name;
1578 uint32_t ui32;
1579 uint64_t data_cb;
1580 uint8_t *data_lpb;
1581
1582 if (g_str_has_prefix (filename, safeuid)) {
1583 split_name = (filename + strlen (safeuid) + strlen ("-"));
1584 } else {
1585 split_name = filename;
1586 }
1587
1588 attachment = e_mapi_attachment_new (object);
1589 e_mapi_object_add_attachment (object, attachment);
1590
1591 ui32 = ATTACH_BY_VALUE;
1592 set_value (PidTagAttachMethod, &ui32);
1593
1594 /* MSDN Documentation: When the supplied offset is -1 (0xFFFFFFFF), the
1595 * attachment is not rendered using the PR_RENDERING_POSITION property.
1596 * All values other than -1 indicate the position within PR_BODY at which
1597 * the attachment is to be rendered.
1598 */
1599 ui32 = -1;
1600 set_value (PidTagRenderingPosition, &ui32);
1601
1602 set_value (PidTagAttachFilename, stored_filename ? stored_filename : split_name);
1603 set_value (PidTagAttachLongFilename, stored_filename ? stored_filename : split_name);
1604
1605 data_cb = filelength;
1606 data_lpb = talloc_memdup (attachment, attach, data_cb);
1607 e_mapi_attachment_add_streamed (attachment, PidTagAttachDataBinary, data_cb, data_lpb);
1608
1609 #if GLIB_CHECK_VERSION(2,21,3)
1610 g_mapped_file_unref (mapped_file);
1611 #else
1612 g_mapped_file_free (mapped_file);
1613 #endif
1614 } else if (error) {
1615 e_mapi_debug_print ("Could not map %s: %s \n", sfname_uri, error->message);
1616 g_error_free (error);
1617 }
1618
1619 g_free (filename);
1620 } else {
1621 EMapiAttachment *attachment;
1622 gsize len = -1;
1623 guchar *decoded = NULL;
1624 const gchar *content;
1625 uint32_t ui32;
1626 uint64_t data_cb;
1627 uint8_t *data_lpb;
1628
1629 content = (const gchar *) i_cal_attach_get_data (attach);
1630 decoded = g_base64_decode (content, &len);
1631
1632 attachment = e_mapi_attachment_new (object);
1633 e_mapi_object_add_attachment (object, attachment);
1634
1635 ui32 = ATTACH_BY_VALUE;
1636 set_value (PidTagAttachMethod, &ui32);
1637
1638 /* MSDN Documentation: When the supplied offset is -1 (0xFFFFFFFF), the
1639 * attachment is not rendered using the PR_RENDERING_POSITION property.
1640 * All values other than -1 indicate the position within PR_BODY at which
1641 * the attachment is to be rendered.
1642 */
1643 ui32 = -1;
1644 set_value (PidTagRenderingPosition, &ui32);
1645
1646 if (stored_filename) {
1647 set_value (PidTagAttachFilename, stored_filename);
1648 set_value (PidTagAttachLongFilename, stored_filename);
1649 }
1650
1651 data_cb = len;
1652 data_lpb = talloc_memdup (attachment, decoded, data_cb);
1653 e_mapi_attachment_add_streamed (attachment, PidTagAttachDataBinary, data_cb, data_lpb);
1654
1655 g_free (decoded);
1656 }
1657
1658 #undef set_value
1659
1660 g_clear_object (¶m);
1661 }
1662
1663 g_free (safeuid);
1664 }
1665
1666 gboolean
1667 e_mapi_cal_utils_comp_to_object (EMapiConnection *conn,
1668 TALLOC_CTX *mem_ctx,
1669 EMapiObject **pobject, /* out */
1670 gpointer user_data,
1671 GCancellable *cancellable,
1672 GError **perror)
1673 {
1674 struct cal_cbdata *cbdata = (struct cal_cbdata *) user_data;
1675 ECalComponent *comp;
1676 ICalComponent *icomp;
1677 ICalComponentKind kind;
1678 uint32_t flag32;
1679 uint8_t b;
1680 ICalProperty *prop;
1681 ICalTime *dtstart, *dtend, *utc_dtstart, *utc_dtend, *all_day_dtstart = NULL, *all_day_dtend = NULL;
1682 ICalTimezone *utc_zone;
1683 const gchar *dtstart_tz_location, *dtend_tz_location, *text = NULL;
1684 time_t tt;
1685 gboolean is_all_day;
1686 GSList *categories = NULL;
1687 EMapiObject *object;
1688
1689 g_return_val_if_fail (conn != NULL, FALSE);
1690 g_return_val_if_fail (mem_ctx != NULL, FALSE);
1691 g_return_val_if_fail (cbdata != NULL, FALSE);
1692 g_return_val_if_fail (pobject != NULL, FALSE);
1693
1694 switch (cbdata->kind) {
1695 case I_CAL_VEVENT_COMPONENT:
1696 case I_CAL_VTODO_COMPONENT:
1697 case I_CAL_VJOURNAL_COMPONENT:
1698 break;
1699 default:
1700 return FALSE;
1701 }
1702
1703 comp = cbdata->comp;
1704 icomp = e_cal_component_get_icalcomponent (comp);
1705 kind = i_cal_component_isa (icomp);
1706 g_return_val_if_fail (kind == cbdata->kind, FALSE);
1707
1708 object = e_mapi_object_new (mem_ctx);
1709 *pobject = object;
1710
1711 #define set_value(hex, val) G_STMT_START { \
1712 if (!e_mapi_utils_add_property (&object->properties, hex, val, object)) \
1713 return FALSE; \
1714 } G_STMT_END
1715
1716 #define set_timet_value(hex, dtval) G_STMT_START { \
1717 struct FILETIME filetime; \
1718 \
1719 e_mapi_util_time_t_to_filetime (dtval, &filetime); \
1720 set_value (hex, &filetime); \
1721 } G_STMT_END
1722
1723 utc_zone = i_cal_timezone_get_utc_timezone ();
1724
1725 dtstart = i_cal_component_get_dtstart (icomp);
1726
1727 /* For VEVENTs */
1728 if (e_cal_util_component_has_property (icomp, I_CAL_DTEND_PROPERTY))
1729 dtend = i_cal_component_get_dtend (icomp);
1730 /* For VTODOs */
1731 else if (e_cal_util_component_has_property (icomp, I_CAL_DUE_PROPERTY) != 0)
1732 dtend = i_cal_component_get_due (icomp);
1733 else
1734 dtend = i_cal_component_get_dtstart (icomp);
1735
1736 dtstart_tz_location = get_tzid_location (i_cal_time_get_tzid (dtstart), cbdata);
1737 dtend_tz_location = get_tzid_location (i_cal_time_get_tzid (dtend), cbdata);
1738
1739 is_all_day = kind == I_CAL_VEVENT_COMPONENT && i_cal_time_is_date (dtstart) && i_cal_time_is_date (dtend);
1740 if (is_all_day) {
1741 const gchar *def_location;
1742 ICalTimezone *use_zone = NULL;
1743
1744 /* all-day events expect times not in UTC but in local time;
1745 if this differs from the server timezone, then the event
1746 is shown spread among (two) days */
1747 def_location = get_tzid_location ("*default-zone*", cbdata);
1748 if (def_location && *def_location)
1749 use_zone = i_cal_timezone_get_builtin_timezone (def_location);
1750
1751 if (!use_zone)
1752 use_zone = utc_zone;
1753
1754 i_cal_time_set_is_date (dtstart, FALSE);
1755 i_cal_time_set_time (dtstart, 0, 0, 0);
1756 all_day_dtstart = i_cal_time_convert_to_zone (dtstart, use_zone);
1757 i_cal_time_set_is_date (dtstart, TRUE);
1758 all_day_dtstart = i_cal_time_convert_to_zone (all_day_dtstart, utc_zone);
1759
1760 i_cal_time_set_is_date (dtend, FALSE);
1761 i_cal_time_set_time (dtend, 0, 0, 0);
1762 all_day_dtend = i_cal_time_convert_to_zone (dtend, use_zone);
1763 i_cal_time_set_is_date (dtend, TRUE);
1764 all_day_dtend = i_cal_time_convert_to_zone (all_day_dtend, utc_zone);
1765 }
1766
1767 utc_dtstart = i_cal_time_convert_to_zone (dtstart, utc_zone);
1768 utc_dtend = i_cal_time_convert_to_zone (dtend, utc_zone);
1769
1770 text = i_cal_component_get_summary (icomp);
1771 if (!(text && *text))
1772 text = "";
1773 set_value (PidTagSubject, text);
1774 set_value (PidTagNormalizedSubject, text);
1775 if (cbdata->appt_seq == 0)
1776 set_value (PidTagConversationTopic, text);
1777 text = NULL;
1778
1779 /* we don't support HTML event/task/memo editor */
1780 flag32 = olEditorText;
1781 set_value (PidTagMessageEditorFormat, &flag32);
1782
1783 /* it'd be better to convert, then set it in unicode */
1784 text = i_cal_component_get_description (icomp);
1785 if (!(text && *text) || !g_utf8_validate (text, -1, NULL))
1786 text = "";
1787 set_value (PidTagBody, text);
1788 text = NULL;
1789
1790 categories = e_cal_component_get_categories_list (comp);
1791 if (categories) {
1792 gint ii;
1793 GSList *c;
1794 struct StringArrayW_r categories_array;
1795
1796 categories_array.cValues = g_slist_length (categories);
1797 categories_array.lppszW = (const char **) talloc_zero_array (mem_ctx, gchar *, categories_array.cValues);
1798
1799 for (c = categories, ii = 0; c; c = c->next, ii++) {
1800 const gchar *category = c->data;
1801
1802 if (!category || !*category) {
1803 ii--;
1804 categories_array.cValues--;
1805 continue;
1806 }
1807
1808 categories_array.lppszW[ii] = talloc_strdup (mem_ctx, category);
1809 }
1810
1811 set_value (PidNameKeywords, &categories_array);
1812
1813 g_slist_free_full (categories, g_free);
1814 }
1815
1816 /* Priority and Importance */
1817 prop = i_cal_component_get_first_property (icomp, I_CAL_PRIORITY_PROPERTY);
1818 flag32 = prop ? get_prio_prop_from_priority (i_cal_property_get_priority (prop)) : PRIORITY_NORMAL;
1819 set_value (PidTagPriority, &flag32);
1820 flag32 = prop ? get_imp_prop_from_priority (i_cal_property_get_priority (prop)) : IMPORTANCE_NORMAL;
1821 set_value (PidTagImportance, &flag32);
1822 g_clear_object (&prop);
1823
1824 if (cbdata->ownername && cbdata->owneridtype && cbdata->ownerid) {
1825 set_value (PidTagSentRepresentingName, cbdata->ownername);
1826 set_value (PidTagSentRepresentingAddressType, cbdata->owneridtype);
1827 set_value (PidTagSentRepresentingEmailAddress, cbdata->ownerid);
1828 }
1829
1830 if (cbdata->username && cbdata->useridtype && cbdata->userid) {
1831 set_value (PidTagSenderName, cbdata->username);
1832 set_value (PidTagSenderAddressType, cbdata->useridtype);
1833 set_value (PidTagSenderEmailAddress, cbdata->userid);
1834 }
1835
1836 flag32 = cbdata->msgflags;
1837 set_value (PidTagMessageFlags, &flag32);
1838
1839 flag32 = 0x0;
1840 b = e_cal_component_has_alarms (comp);
1841 if (b) {
1842 /* We know there would be only a single alarm of type:DISPLAY [static properties of the backend] */
1843 GSList *alarm_uids = e_cal_component_get_alarm_uids (comp);
1844 ECalComponentAlarm *alarm = e_cal_component_get_alarm (comp, (const gchar *)(alarm_uids->data));
1845 ECalComponentAlarmAction action;
1846
1847 action = e_cal_component_alarm_get_action (alarm);
1848 if (action == E_CAL_COMPONENT_ALARM_DISPLAY) {
1849 ECalComponentAlarmTrigger *trigger;
1850 gint dur_int = 0;
1851
1852 trigger = e_cal_component_alarm_get_trigger (alarm);
1853 switch (e_cal_component_alarm_trigger_get_kind (trigger)) {
1854 case E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START:
1855 dur_int = (i_cal_duration_as_int (e_cal_component_alarm_trigger_get_duration (trigger))) / SECS_IN_MINUTE;
1856 /* we cannot set an alarm to popup after the start of an appointment on Exchange */
1857 flag32 = (dur_int < 0) ? -(dur_int) : 0;
1858 break;
1859 default :
1860 break;
1861 }
1862 }
1863 e_cal_component_alarm_free (alarm);
1864 g_slist_free_full (alarm_uids, g_free);
1865 }
1866 if (!flag32)
1867 switch (kind) {
1868 case I_CAL_VEVENT_COMPONENT:
1869 flag32 = DEFAULT_APPT_REMINDER_MINS;
1870 break;
1871 case I_CAL_VTODO_COMPONENT:
1872 flag32 = DEFAULT_TASK_REMINDER_MINS;
1873 break;
1874 default:
1875 break;
1876 }
1877 set_value (PidLidReminderSet, &b);
1878 set_value (PidLidReminderDelta, &flag32);
1879 tt = i_cal_time_as_timet (utc_dtstart);
1880 set_timet_value (PidLidReminderTime, tt);
1881 tt = i_cal_time_as_timet (utc_dtstart) - (flag32 * SECS_IN_MINUTE);
1882 /* ReminderNextTime: FIXME for recurrence */
1883 set_timet_value (PidLidReminderSignalTime, tt);
1884
1885 /* Sensitivity, Private */
1886 flag32 = olNormal; /* default */
1887 b = 0; /* default */
1888 prop = i_cal_component_get_first_property (icomp, I_CAL_CLASS_PROPERTY);
1889 if (prop)
1890 flag32 = get_prop_from_class (i_cal_property_get_class (prop));
1891 if (flag32 == olPrivate || flag32 == olConfidential)
1892 b = 1;
1893 set_value (PidTagSensitivity, &flag32);
1894 set_value (PidLidPrivate, &b);
1895 g_clear_object (&prop);
1896
1897 tt = i_cal_time_as_timet (is_all_day ? all_day_dtstart : utc_dtstart);
1898 set_timet_value (PidLidCommonStart, tt);
1899 set_timet_value (PidTagStartDate, tt);
1900
1901 tt = i_cal_time_as_timet (is_all_day ? all_day_dtend : utc_dtend);
1902 set_timet_value (PidLidCommonEnd, tt);
1903 set_timet_value (PidTagEndDate, tt);
1904
1905 b = 1;
1906 set_value (PidTagResponseRequested, &b);
1907
1908 /* PR_OWNER_APPT_ID needs to be set in certain cases only */
1909 /* PR_ICON_INDEX needs to be set appropriately */
1910
1911 b = 0;
1912 set_value (PidTagRtfInSync, &b);
1913
1914 if (kind == I_CAL_VEVENT_COMPONENT) {
1915 const gchar *mapi_tzid;
1916 struct SBinary_short start_tz, end_tz;
1917 ICalDuration *duration;
1918 ICalTime *itt;
1919
1920 set_value (PidLidAppointmentMessageClass, IPM_APPOINTMENT);
1921
1922 /* Busy Status */
1923 flag32 = olBusy;
1924 prop = i_cal_component_get_first_property (icomp, I_CAL_TRANSP_PROPERTY);
1925 if (prop)
1926 flag32 = get_prop_from_transp (i_cal_property_get_transp (prop));
1927 if (cbdata->meeting_type == MEETING_CANCEL)
1928 flag32 = olFree;
1929 set_value (PidLidIntendedBusyStatus, &flag32);
1930
1931 if (cbdata->meeting_type == MEETING_REQUEST || cbdata->meeting_type == MEETING_REQUEST_RCVD) {
1932 flag32 = olTentative;
1933 set_value (PidLidBusyStatus, &flag32);
1934 } else if (cbdata->meeting_type == MEETING_CANCEL) {
1935 flag32 = olFree;
1936 set_value (PidLidBusyStatus, &flag32);
1937 } else
1938 set_value (PidLidBusyStatus, &flag32);
1939 g_clear_object (&prop);
1940
1941 /* Location */
1942 text = i_cal_component_get_location (icomp);
1943 if (!(text && *text))
1944 text = "";
1945 set_value (PidLidLocation, text);
1946 set_value (PidLidWhere, text);
1947 text = NULL;
1948 /* Auto-Location is always FALSE - Evolution doesn't work that way */
1949 b = 0;
1950 set_value (PidLidAutoFillLocation, &b);
1951
1952 /* All-day event */
1953 b = is_all_day ? 1 : 0;
1954 set_value (PidLidAppointmentSubType, &b);
1955
1956 /* Start */
1957 tt = i_cal_time_as_timet (is_all_day ? all_day_dtstart : utc_dtstart);
1958 set_timet_value (PidLidAppointmentStartWhole, tt);
1959 /* FIXME: for recurrence */
1960 set_timet_value (PidLidClipStart, tt);
1961
1962 /* Start TZ */
1963 mapi_tzid = e_mapi_cal_tz_util_get_mapi_equivalent ((dtstart_tz_location && *dtstart_tz_location) ? dtstart_tz_location : "UTC");
1964 if (mapi_tzid && *mapi_tzid) {
1965 e_mapi_cal_util_mapi_tz_to_bin (mapi_tzid, &start_tz, object, FALSE);
1966 set_value (PidLidAppointmentTimeZoneDefinitionStartDisplay, &start_tz);
1967
1968 if (e_cal_component_has_recurrences (comp)) {
1969 struct SBinary_short recur_tz;
1970
1971 e_mapi_cal_util_mapi_tz_to_bin (mapi_tzid, &recur_tz, object, TRUE);
1972 set_value (PidLidAppointmentTimeZoneDefinitionRecur, &recur_tz);
1973 }
1974 }
1975 set_value (PidLidTimeZoneDescription, mapi_tzid ? mapi_tzid : "");
1976
1977 /* End */
1978 tt = i_cal_time_as_timet (is_all_day ? all_day_dtend : utc_dtend);
1979 set_timet_value (PidLidAppointmentEndWhole, tt);
1980 /* FIXME: for recurrence */
1981 set_timet_value (PidLidClipEnd, tt);
1982
1983 /* End TZ */
1984 mapi_tzid = e_mapi_cal_tz_util_get_mapi_equivalent ((dtend_tz_location && *dtend_tz_location) ? dtend_tz_location : "UTC");
1985 if (mapi_tzid && *mapi_tzid) {
1986 e_mapi_cal_util_mapi_tz_to_bin (mapi_tzid, &end_tz, object, FALSE);
1987 set_value (PidLidAppointmentTimeZoneDefinitionEndDisplay, &end_tz);
1988 }
1989
1990 /* Recurrences also need to have this rather arbitrary index set
1991 to properly determine SDT/DST and appear in OWA (Bug #629057). */
1992 if (e_cal_component_has_recurrences (comp)) {
1993 uint64_t pltz;
1994 ICalTimezone *ictz;
1995 const gchar *zone_location = dtstart_tz_location;
1996
1997 if (!zone_location)
1998 zone_location = get_tzid_location ("*default-zone*", cbdata);
1999
2000 ictz = i_cal_timezone_get_builtin_timezone (zone_location);
2001 pltz = e_mapi_cal_util_mapi_tz_pidlidtimezone (ictz);
2002 set_value (PidLidTimeZone, &pltz);
2003 }
2004
2005 /* Duration */
2006 duration = i_cal_time_subtract (dtend, dtstart);
2007 flag32 = i_cal_duration_as_int (duration);
2008 flag32 /= MINUTES_IN_HOUR;
2009 set_value (PidLidAppointmentDuration, &flag32);
2010 g_clear_object (&duration);
2011
2012 if (e_cal_component_has_recurrences (comp)) {
2013 GSList *rrule_list = NULL;
2014 ICalRecurrence *rt = NULL;
2015
2016 rrule_list = e_cal_component_get_rrules (comp);
2017 rt = rrule_list->data;
2018
2019 if (i_cal_recurrence_get_freq (rt) == I_CAL_DAILY_RECURRENCE)
2020 flag32 = rectypeDaily;
2021 else if (i_cal_recurrence_get_freq (rt) == I_CAL_WEEKLY_RECURRENCE)
2022 flag32 = rectypeWeekly;
2023 else if (i_cal_recurrence_get_freq (rt) == I_CAL_MONTHLY_RECURRENCE)
2024 flag32 = rectypeMonthly;
2025 else if (i_cal_recurrence_get_freq (rt) == I_CAL_YEARLY_RECURRENCE)
2026 flag32 = rectypeYearly;
2027 else
2028 flag32 = rectypeNone;
2029
2030 g_slist_free_full (rrule_list, g_object_unref);
2031 } else
2032 flag32 = rectypeNone;
2033 set_value (PidLidRecurrenceType, &flag32);
2034
2035 flag32 = cbdata->appt_id;
2036 if (!flag32) {
2037 gchar *propval;
2038
2039 propval = e_cal_util_component_dup_x_property (e_cal_component_get_icalcomponent (comp), "X-EVOLUTION-MAPI-OWNER-APPT-ID");
2040 if (propval && *propval) {
2041 mapi_id_t as_id = 0;
2042
2043 if (e_mapi_util_mapi_id_from_string (propval, &as_id))
2044 flag32 = (uint32_t) as_id;
2045 }
2046
2047 g_free (propval);
2048 }
2049 set_value (PidTagOwnerAppointmentId, &flag32);
2050
2051 flag32 = cbdata->appt_seq;
2052 set_value (PidLidAppointmentSequence, &flag32);
2053
2054 if (cbdata->cleanglobalid) {
2055 struct Binary_r bin;
2056 bin.cb = cbdata->cleanglobalid->cb;
2057 bin.lpb = cbdata->cleanglobalid->lpb;
2058
2059 set_value (PidLidCleanGlobalObjectId, &bin);
2060 }
2061
2062 if (cbdata->globalid) {
2063 struct Binary_r bin;
2064 bin.cb = cbdata->globalid->cb;
2065 bin.lpb = cbdata->globalid->lpb;
2066
2067 set_value (PidLidGlobalObjectId, &bin);
2068 }
2069
2070 flag32 = cbdata->resp;
2071 set_value (PidLidResponseStatus, &flag32);
2072
2073 switch (cbdata->meeting_type) {
2074 case MEETING_OBJECT :
2075 set_value (PidTagMessageClass, IPM_APPOINTMENT);
2076
2077 flag32 = e_cal_component_has_recurrences (comp) ? RecurMeet : SingleMeet;
2078 set_value (PidTagIconIndex, &flag32);
2079
2080 flag32 = 0x0171;
2081 set_value (PidLidSideEffects, &flag32);
2082
2083 flag32 = asfMeeting;
2084 set_value (PidLidAppointmentStateFlags, &flag32);
2085
2086 flag32 = mtgRequest;
2087 set_value (PidLidMeetingType, &flag32);
2088
2089 b = 1;
2090 set_value (PidLidFInvited, &b);
2091
2092 break;
2093 case MEETING_OBJECT_RCVD :
2094 set_value (PidTagMessageClass, IPM_APPOINTMENT);
2095
2096 flag32 = e_cal_component_has_recurrences (comp) ? RecurMeet : SingleMeet;
2097 set_value (PidTagIconIndex, (gconstpointer ) &flag32);
2098
2099 flag32 = 0x0171;
2100 set_value (PidLidSideEffects, &flag32);
2101
2102 flag32 = asfMeeting | asfReceived;
2103 set_value (PidLidAppointmentStateFlags, &flag32);
2104
2105 flag32 = mtgRequest;
2106 set_value (PidLidMeetingType, &flag32);
2107
2108 b = 1;
2109 set_value (PidLidFInvited, &b);
2110
2111 break;
2112 case MEETING_REQUEST :
2113 set_value (PidTagMessageClass, IPM_SCHEDULE_MEETING_REQUEST);
2114
2115 flag32 = 0xFFFFFFFF; /* no idea why this has to be -1, but that's what the docs say */
2116 set_value (PidTagIconIndex, &flag32);
2117
2118 flag32 = 0x1C61;
2119 set_value (PidLidSideEffects, &flag32);
2120
2121 flag32 = asfMeeting | asfReceived;
2122 set_value (PidLidAppointmentStateFlags, &flag32);
2123
2124 flag32 = (cbdata->appt_seq == 0) ? mtgRequest : mtgFull;
2125 set_value (PidLidMeetingType, &flag32);
2126
2127 b = 1;
2128 set_value (PidLidFInvited, &b);
2129
2130 itt = i_cal_time_new_current_with_zone (utc_zone);
2131 tt = i_cal_time_as_timet (itt);
2132 set_timet_value (PidLidAttendeeCriticalChange, tt);
2133 g_clear_object (&itt);
2134
2135 break;
2136 case MEETING_REQUEST_RCVD :
2137 set_value (PidTagMessageClass, IPM_APPOINTMENT);
2138
2139 flag32 = e_cal_component_has_recurrences (comp) ? RecurMeet : SingleMeet;
2140 set_value (PidTagIconIndex, &flag32);
2141
2142 flag32 = 0x0171;
2143 set_value (PidLidSideEffects, &flag32);
2144
2145 flag32 = asfMeeting | asfReceived;
2146 set_value (PidLidAppointmentStateFlags, &flag32);
2147
2148 flag32 = mtgRequest;
2149 set_value (PidLidMeetingType, &flag32);
2150
2151 b = 1;
2152 set_value (PidLidFInvited, &b);
2153
2154 break;
2155 case MEETING_CANCEL :
2156 set_value (PidTagMessageClass, IPM_SCHEDULE_MEETING_CANCELED);
2157
2158 flag32 = 0xFFFFFFFF; /* no idea why this has to be -1, but that's what the docs say */
2159 set_value (PidTagIconIndex, &flag32);
2160
2161 flag32 = 0x1C61;
2162 set_value (PidLidSideEffects, &flag32);
2163
2164 flag32 = asfMeeting | asfReceived | asfCanceled;
2165 set_value (PidLidAppointmentStateFlags, &flag32);
2166
2167 flag32 = mtgEmpty;
2168 set_value (PidLidMeetingType, &flag32);
2169
2170 b = 1;
2171 set_value (PidLidFInvited, &b);
2172
2173 break;
2174 case MEETING_RESPONSE :
2175 #define prefix_subject(prefix) { \
2176 const gchar *summary; \
2177 \
2178 summary = i_cal_component_get_summary (icomp); \
2179 if (!(summary && *summary)) \
2180 summary = ""; \
2181 \
2182 summary = talloc_asprintf (mem_ctx, "%s %s", prefix, summary); \
2183 \
2184 set_value (PidTagSubject, summary); \
2185 set_value (PidTagNormalizedSubject, summary); \
2186 if (cbdata->appt_seq == 0) \
2187 set_value (PidTagConversationTopic, summary); \
2188 }
2189 if (cbdata->resp == olResponseAccepted) {
2190 /* Translators: This is a meeting response prefix which will be shown in a message Subject */
2191 prefix_subject (C_("MeetingResp", "Accepted:"));
2192 text = IPM_SCHEDULE_MEETING_RESP_POS;
2193 flag32 = 1 << 5; /* ciRespondedAccept */
2194 } else if (cbdata->resp == olResponseTentative) {
2195 /* Translators: This is a meeting response prefix which will be shown in a message Subject */
2196 prefix_subject (C_("MeetingResp", "Tentative:"));
2197 text = IPM_SCHEDULE_MEETING_RESP_TENT;
2198 flag32 = 1 << 4; /* ciRespondedTentative */
2199 } else if (cbdata->resp == olResponseDeclined) {
2200 /* Translators: This is a meeting response prefix which will be shown in a message Subject */
2201 prefix_subject (C_("MeetingResp", "Declined:"));
2202 text = IPM_SCHEDULE_MEETING_RESP_NEG;
2203 flag32 = 1 << 6; /* ciRespondedDecline */
2204 } else {
2205 text = "";
2206 flag32 = 1 << 11; /* ciCanceled */
2207 }
2208 #undef prefix_subject
2209 set_value (PidTagMessageClass, text);
2210 text = NULL;
2211
2212 set_value (PidLidClientIntent, &flag32);
2213
2214 flag32 = 0xFFFFFFFF; /* no idea why this has to be -1, but that's what the docs say */
2215 set_value (PidTagIconIndex, &flag32);
2216
2217 flag32 = 0x1C61;
2218 set_value (PidLidSideEffects, &flag32);
2219
2220 flag32 = asfNone;
2221 set_value (PidLidAppointmentStateFlags, &flag32);
2222
2223 flag32 = mtgEmpty;
2224 set_value (PidLidMeetingType, &flag32);
2225
2226 itt = i_cal_time_new_current_with_zone (utc_zone);
2227 tt = i_cal_time_as_timet (itt);
2228 set_timet_value (PidLidAppointmentReplyTime, tt);
2229 g_clear_object (&itt);
2230
2231 break;
2232 case NOT_A_MEETING :
2233 default :
2234 set_value (PidTagMessageClass, IPM_APPOINTMENT);
2235
2236 flag32 = e_cal_component_has_recurrences (comp) ? RecurAppt : SingleAppt;
2237 set_value (PidTagIconIndex, &flag32);
2238
2239 flag32 = 0x0171;
2240 set_value (PidLidSideEffects, &flag32);
2241
2242 flag32 = 0;
2243 set_value (PidLidAppointmentStateFlags, &flag32);
2244
2245 b = 0;
2246 set_value (PidLidFInvited, &b);
2247
2248 break;
2249 }
2250
2251 b = e_cal_component_has_recurrences (comp);
2252 set_value (PidLidRecurring, &b);
2253 set_value (PidLidIsRecurring, &b);
2254
2255 if (b) {
2256 struct SBinary_short recur_bin;
2257
2258 if (e_mapi_cal_util_rrule_to_bin (comp, &recur_bin, object)) {
2259 set_value (PidLidAppointmentRecur, &recur_bin);
2260 }
2261 }
2262
2263 /* FIXME: Modified exceptions */
2264 b = e_cal_component_has_exceptions (comp) && FALSE; b = 0;
2265 set_value (PidLidIsException, &b);
2266
2267 /* Counter Proposal for appointments : not supported */
2268 b = 1;
2269 set_value (PidLidAppointmentNotAllowPropose, &b);
2270 b = 0;
2271 set_value (PidLidAppointmentCounterProposal, &b);
2272
2273 } else if (kind == I_CAL_VTODO_COMPONENT) {
2274 gdouble d;
2275
2276 set_value (PidTagMessageClass, IPM_TASK);
2277
2278 /* Context menu flags */ /* FIXME: for assigned tasks */
2279 flag32 = 0x0110;
2280 set_value (PidLidSideEffects, &flag32);
2281
2282 /* Status, Percent complete, IsComplete */
2283 flag32 = olTaskNotStarted; /* default */
2284 b = 0; /* default */
2285 d = 0.0;
2286 prop = i_cal_component_get_first_property (icomp, I_CAL_PERCENTCOMPLETE_PROPERTY);
2287 if (prop)
2288 d = 0.01 * i_cal_property_get_percentcomplete (prop);
2289 g_clear_object (&prop);
2290
2291 flag32 = get_prop_from_taskstatus (i_cal_component_get_status (icomp));
2292 if (flag32 == olTaskComplete) {
2293 b = 1;
2294 d = 1.0;
2295 }
2296
2297 set_value (PidLidTaskStatus, &flag32);
2298 set_value (PidLidPercentComplete, &d);
2299 set_value (PidLidTaskComplete, &b);
2300
2301 /* Date completed */
2302 if (b) {
2303 ICalTime *completed;
2304
2305 prop = i_cal_component_get_first_property (icomp, I_CAL_COMPLETED_PROPERTY);
2306 if (prop) {
2307 completed = i_cal_property_get_completed (prop);
2308
2309 i_cal_time_set_time (completed, 0, 0, 0);
2310 i_cal_time_set_is_date (completed, TRUE);
2311 i_cal_time_set_timezone (completed, utc_zone);
2312
2313 tt = i_cal_time_as_timet (completed);
2314 set_timet_value (PidLidTaskDateCompleted, tt);
2315 g_clear_object (&completed);
2316 }
2317 }
2318
2319 /* Start */
2320 i_cal_time_set_time (dtstart, 0, 0, 0);
2321 i_cal_time_set_is_date (dtstart, TRUE);
2322 i_cal_time_set_timezone (dtstart, utc_zone);
2323
2324 tt = i_cal_time_as_timet (dtstart);
2325 if (!i_cal_time_is_null_time (dtstart)) {
2326 set_timet_value (PidLidTaskStartDate, tt);
2327 }
2328
2329 /* Due */
2330 i_cal_time_set_time (dtend, 0, 0, 0);
2331 i_cal_time_set_is_date (dtend, TRUE);
2332 i_cal_time_set_timezone (dtend, utc_zone);
2333
2334 tt = i_cal_time_as_timet (dtend);
2335 if (!i_cal_time_is_null_time (dtend)) {
2336 set_timet_value (PidLidTaskDueDate, tt);
2337 }
2338
2339 /* FIXME: Evolution does not support recurring tasks */
2340 b = 0;
2341 set_value (PidLidTaskFRecurring, &b);
2342
2343 } else if (kind == I_CAL_VJOURNAL_COMPONENT) {
2344 uint32_t color = olYellow;
2345
2346 set_value (PidTagMessageClass, IPM_STICKYNOTE);
2347
2348 /* Context menu flags */
2349 flag32 = 0x0110;
2350 set_value (PidLidSideEffects, &flag32);
2351
2352 flag32 = 0x0300 + color;
2353 set_value (PidTagIconIndex, &flag32);
2354
2355 flag32 = color;
2356 set_value (PidLidNoteColor, &flag32);
2357
2358 /* some random value */
2359 flag32 = 0x00FF;
2360 set_value (PidLidNoteWidth, &flag32);
2361
2362 /* some random value */
2363 flag32 = 0x00FF;
2364 set_value (PidLidNoteHeight, &flag32);
2365 }
2366
2367 #undef set_value
2368 #undef set_timet_value
2369
2370 if (cbdata->meeting_type == MEETING_RESPONSE || cbdata->meeting_type == NOT_A_MEETING)
2371 e_mapi_cal_utils_add_organizer (object, comp);
2372 else
2373 e_mapi_cal_utils_add_recipients (object, comp);
2374
2375 e_mapi_cal_utils_add_attachments (object, comp);
2376
2377 if (e_mapi_debug_is_enabled ()) {
2378 printf ("%s:\n", G_STRFUNC);
2379 e_mapi_debug_dump_object (object, TRUE, 3);
2380 }
2381
2382 g_clear_object (&dtstart);
2383 g_clear_object (&dtend);
2384 g_clear_object (&utc_dtstart);
2385 g_clear_object (&utc_dtend);
2386 g_clear_object (&all_day_dtstart);
2387 g_clear_object (&all_day_dtend);
2388
2389 return TRUE;
2390 }