"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 (&param);
 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 (&param);
 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 (&param);
 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 (&param);
 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 (&param);
 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 }