"Fossies" - the Fresh Open Source Software Archive

Member "evolution-mapi-3.46.1/src/libexchangemapi/e-mapi-utils.c" (2 Dec 2022, 43239 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-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.h>
   27 #include <glib/gi18n-lib.h>
   28 #include <gio/gio.h>
   29 
   30 #include <libedataserver/libedataserver.h>
   31 
   32 #include "e-mapi-utils.h"
   33 #include "e-mapi-mail-utils.h"
   34 #include "e-source-mapi-folder.h"
   35 
   36 #ifdef G_OS_WIN32
   37 /* Undef the similar macro from pthread.h, it doesn't check if
   38  * gmtime() returns NULL.
   39  */
   40 #undef gmtime_r
   41 
   42 /* The gmtime() in Microsoft's C library is MT-safe */
   43 #define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
   44 #endif
   45 
   46 #define DEFAULT_PROF_NAME "mapi-profiles.ldb"
   47 
   48 /* Used for callout to krb5-auth-dialog */
   49 #define KRB_DBUS_PATH               "/org/gnome/KrbAuthDialog"
   50 #define KRB_DBUS_INTERFACE          "org.gnome.KrbAuthDialog"
   51 
   52 void
   53 e_mapi_cancellable_rec_mutex_init (EMapiCancellableRecMutex *rec_mutex)
   54 {
   55     g_return_if_fail (rec_mutex != NULL);
   56 
   57     g_rec_mutex_init (&rec_mutex->rec_mutex);
   58     g_mutex_init (&rec_mutex->cond_mutex);
   59     g_cond_init (&rec_mutex->cond);
   60 }
   61 
   62 void
   63 e_mapi_cancellable_rec_mutex_clear (EMapiCancellableRecMutex *rec_mutex)
   64 {
   65     g_return_if_fail (rec_mutex != NULL);
   66 
   67     g_rec_mutex_clear (&rec_mutex->rec_mutex);
   68     g_mutex_clear (&rec_mutex->cond_mutex);
   69     g_cond_clear (&rec_mutex->cond);
   70 }
   71 
   72 static void
   73 cancellable_rec_mutex_cancelled_cb (GCancellable *cancellable,
   74                     EMapiCancellableRecMutex *rec_mutex)
   75 {
   76     g_return_if_fail (rec_mutex != NULL);
   77 
   78     /* wake-up any waiting threads */
   79     g_mutex_lock (&rec_mutex->cond_mutex);
   80     g_cond_broadcast (&rec_mutex->cond);
   81     g_mutex_unlock (&rec_mutex->cond_mutex);
   82 }
   83 
   84 /* returns FALSE if cancelled, in which case the lock is not held */
   85 gboolean
   86 e_mapi_cancellable_rec_mutex_lock (EMapiCancellableRecMutex *rec_mutex,
   87                    GCancellable *cancellable,
   88                    GError **error)
   89 {
   90     gulong handler_id;
   91     gboolean res = TRUE;
   92 
   93     g_return_val_if_fail (rec_mutex != NULL, FALSE);
   94 
   95     g_mutex_lock (&rec_mutex->cond_mutex);
   96     if (!cancellable) {
   97         g_mutex_unlock (&rec_mutex->cond_mutex);
   98         g_rec_mutex_lock (&rec_mutex->rec_mutex);
   99         return TRUE;
  100     }
  101 
  102     if (g_cancellable_is_cancelled (cancellable)) {
  103         if (error && !*error) {
  104             /* coverity[unchecked_value] */
  105             g_cancellable_set_error_if_cancelled (cancellable, error);
  106         }
  107         g_mutex_unlock (&rec_mutex->cond_mutex);
  108         return FALSE;
  109     }
  110 
  111     handler_id = g_signal_connect (cancellable, "cancelled",
  112         G_CALLBACK (cancellable_rec_mutex_cancelled_cb), rec_mutex);
  113 
  114     while (!g_rec_mutex_trylock (&rec_mutex->rec_mutex)) {
  115         /* recheck once per 10 seconds, just in case */
  116         g_cond_wait_until (&rec_mutex->cond, &rec_mutex->cond_mutex,
  117             g_get_monotonic_time () + (10 * G_TIME_SPAN_SECOND));
  118 
  119         if (g_cancellable_is_cancelled (cancellable)) {
  120             if (error && !*error)
  121                 g_cancellable_set_error_if_cancelled (cancellable, error);
  122             res = FALSE;
  123             break;
  124         }
  125     }
  126 
  127     g_signal_handler_disconnect (cancellable, handler_id);
  128 
  129     g_mutex_unlock (&rec_mutex->cond_mutex);
  130 
  131     return res;
  132 }
  133 
  134 void
  135 e_mapi_cancellable_rec_mutex_unlock (EMapiCancellableRecMutex *rec_mutex)
  136 {
  137     g_return_if_fail (rec_mutex != NULL);
  138 
  139     g_rec_mutex_unlock (&rec_mutex->rec_mutex);
  140 
  141     g_mutex_lock (&rec_mutex->cond_mutex);
  142     /* also wake-up any waiting threads */
  143     g_cond_broadcast (&rec_mutex->cond);
  144     g_mutex_unlock (&rec_mutex->cond_mutex);
  145 }
  146 
  147 static gboolean
  148 manage_global_lock (gboolean lock,
  149             GCancellable *cancellable,
  150             GError **error)
  151 {
  152     static EMapiCancellableRecMutex global_lock;
  153     gboolean res = TRUE;
  154 
  155     if (lock)
  156         res = e_mapi_cancellable_rec_mutex_lock (&global_lock, cancellable, error);
  157     else
  158         e_mapi_cancellable_rec_mutex_unlock (&global_lock);
  159 
  160     return res;
  161 }
  162 
  163 gboolean
  164 e_mapi_utils_global_lock (GCancellable *cancellable,
  165               GError **error)
  166 {
  167     return manage_global_lock (TRUE, cancellable, error);
  168 }
  169 
  170 void
  171 e_mapi_utils_global_unlock (void)
  172 {
  173     manage_global_lock (FALSE, NULL, NULL);
  174 }
  175 
  176 inline gchar *
  177 e_mapi_util_mapi_id_to_string (mapi_id_t id)
  178 {
  179     return g_strdup_printf ("%016" G_GINT64_MODIFIER "X", id);
  180 }
  181 
  182 inline gboolean
  183 e_mapi_util_mapi_id_from_string (const gchar *str, mapi_id_t *id)
  184 {
  185     gint n = 0;
  186 
  187     if (str && *str && strlen (str) <= 16)
  188         n = sscanf (str, "%016" G_GINT64_MODIFIER "X", id);
  189 
  190     return (n == 1);
  191 }
  192 
  193 /*
  194  * Retrieve the property value for a given SPropValue and property tag.
  195  *
  196  * If the property type is a string: fetch PT_STRING8 then PT_UNICODE
  197  * in case the desired property is not available in first choice.
  198  *
  199  * Fetch property normally for any others properties
  200  */
  201 /* NOTE: For now, since this function has special significance only for
  202  * 'string' type properties, callers should (preferably) use it for fetching
  203  * such properties alone. If callers are sure that proptag would, for instance,
  204  * return an 'int' or a 'systime', they should prefer get_SPropValue.
  205  */
  206 gconstpointer
  207 e_mapi_util_find_SPropVal_array_propval (struct SPropValue *values, uint32_t proptag)
  208 {
  209     if (((proptag & 0xFFFF) == PT_STRING8) ||
  210         ((proptag & 0xFFFF) == PT_UNICODE)) {
  211         const void  *str = NULL;
  212 
  213         proptag = (proptag & 0xFFFF0000) | PT_UNICODE;
  214         str = get_SPropValue(values, proptag);
  215         if (str)
  216             return str;
  217 
  218         proptag = (proptag & 0xFFFF0000) | PT_STRING8;
  219         str = get_SPropValue(values, proptag);
  220         if (str)
  221             return str;
  222 
  223         return NULL;
  224     }
  225 
  226     /* NOTE: Similar generalizations (if any) for other property types
  227      * can be made here.
  228      */
  229 
  230     return (get_SPropValue(values, proptag));
  231 }
  232 
  233 /*
  234  * Retrieve the property value for a given SRow and property tag.
  235  *
  236  * If the property type is a string: fetch PT_STRING8 then PT_UNICODE
  237  * in case the desired property is not available in first choice.
  238  *
  239  * Fetch property normally for any others properties
  240  */
  241 /* NOTE: For now, since this function has special significance only for
  242  * 'string' type properties, callers should (preferably) use it for fetching
  243  * such properties alone. If callers are sure that proptag would, for instance,
  244  * return an 'int' or a 'systime', they should prefer find_SPropValue_data.
  245  */
  246 gconstpointer
  247 e_mapi_util_find_row_propval (struct SRow *aRow, uint32_t proptag)
  248 {
  249     if (((proptag & 0xFFFF) == PT_STRING8) ||
  250         ((proptag & 0xFFFF) == PT_UNICODE)) {
  251         const void  *str = NULL;
  252 
  253         proptag = (proptag & 0xFFFF0000) | PT_UNICODE;
  254         str = find_SPropValue_data(aRow, proptag);
  255         if (str)
  256             return str;
  257 
  258         proptag = (proptag & 0xFFFF0000) | PT_STRING8;
  259         str = find_SPropValue_data(aRow, proptag);
  260         if (str)
  261             return str;
  262 
  263         return NULL;
  264     }
  265 
  266     /* NOTE: Similar generalizations (if any) for other property types
  267      * can be made here.
  268      */
  269 
  270     return (find_SPropValue_data(aRow, proptag));
  271 }
  272 
  273 gconstpointer
  274 e_mapi_util_find_propertyrow_propval (struct PropertyRow_r *rRow,
  275                       uint32_t proptag)
  276 {
  277     if (((proptag & 0xFFFF) == PT_STRING8) ||
  278         ((proptag & 0xFFFF) == PT_UNICODE)) {
  279         gconstpointer str = NULL;
  280 
  281         proptag = (proptag & 0xFFFF0000) | PT_UNICODE;
  282         str = find_PropertyValue_data (rRow, proptag);
  283         if (str)
  284             return str;
  285 
  286         proptag = (proptag & 0xFFFF0000) | PT_STRING8;
  287         str = find_PropertyValue_data (rRow, proptag);
  288         if (str)
  289             return str;
  290 
  291         return NULL;
  292     }
  293 
  294     return find_PropertyValue_data (rRow, proptag);
  295 }
  296 
  297 /*
  298  * Retrieve the property value for a given mapi_SPropValue_array and property tag.
  299  *
  300  * If the property type is a string: fetch PT_STRING8 then PT_UNICODE
  301  * in case the desired property is not available in first choice.
  302  *
  303  * Fetch property normally for any others properties
  304  */
  305 /* NOTE: For now, since this function has special significance only for
  306  * 'string' type properties, callers should (preferably) use it for fetching
  307  * such properties alone. If callers are sure that proptag would, for instance,
  308  * return an 'int' or a 'systime', they should prefer find_mapi_SPropValue_data.
  309  */
  310 gconstpointer
  311 e_mapi_util_find_array_propval (struct mapi_SPropValue_array *properties, uint32_t proptag)
  312 {
  313     if (((proptag & 0xFFFF) == PT_STRING8) ||
  314         ((proptag & 0xFFFF) == PT_UNICODE)) {
  315         const void  *str = NULL;
  316 
  317         proptag = (proptag & 0xFFFF0000) | PT_UNICODE;
  318         str = find_mapi_SPropValue_data(properties, proptag);
  319         if (str)
  320             return str;
  321 
  322         proptag = (proptag & 0xFFFF0000) | PT_STRING8;
  323         str = find_mapi_SPropValue_data(properties, proptag);
  324         if (str)
  325             return str;
  326 
  327         return NULL;
  328     }
  329 
  330     /* NOTE: Similar generalizations (if any) for other property types
  331      * can be made here.
  332      */
  333 
  334     return (find_mapi_SPropValue_data(properties, proptag));
  335 }
  336 
  337 uint32_t
  338 e_mapi_util_find_array_proptag (struct mapi_SPropValue_array *properties, uint32_t proptag)
  339 {
  340     g_return_val_if_fail (properties != NULL, proptag);
  341 
  342     if ((proptag & 0xFFFF) == PT_STRING8 ||
  343         (proptag & 0xFFFF) == PT_UNICODE) {
  344         gint ii;
  345         uint32_t tag1, tag2;
  346 
  347         tag1 = (proptag & 0xFFFF0000) | PT_STRING8;
  348         tag2 = (proptag & 0xFFFF0000) | PT_UNICODE;
  349 
  350         for (ii = 0; ii < properties->cValues; ii++) {
  351             uint32_t tag = properties->lpProps[ii].ulPropTag;
  352             if (tag == tag1 || tag == tag2) {
  353                 proptag = tag;
  354                 break;
  355             }
  356         }
  357     }
  358 
  359     return 0;
  360 }
  361 
  362 enum MAPISTATUS
  363 e_mapi_util_find_array_datetime_propval (struct timeval *tv, struct mapi_SPropValue_array *properties, uint32_t proptag)
  364 {
  365     g_return_val_if_fail (tv != NULL, MAPI_E_INVALID_PARAMETER);
  366     g_return_val_if_fail (properties != NULL, MAPI_E_INVALID_PARAMETER);
  367 
  368     return get_mapi_SPropValue_array_date_timeval (tv, properties, proptag);
  369 }
  370 
  371 static void
  372 e_mapi_util_bin_append_uint16 (TALLOC_CTX *mem_ctx, struct Binary_r *bin, const uint16_t val)
  373 {
  374     uint8_t *ptr = NULL;
  375 
  376     bin->lpb = talloc_realloc (mem_ctx, bin->lpb, uint8_t, bin->cb + 2);
  377     bin->cb += 2;
  378 
  379     ptr = bin->lpb + bin->cb - 2;
  380 
  381     *ptr++ = ( val        & 0xFF);
  382     *ptr++ = ((val >>  8) & 0xFF);
  383 }
  384 
  385 static void
  386 e_mapi_util_bin_append_uint32 (TALLOC_CTX *mem_ctx, struct Binary_r *bin, const uint32_t val)
  387 {
  388     uint8_t *ptr = NULL;
  389 
  390     bin->lpb = talloc_realloc (mem_ctx, bin->lpb, uint8_t, bin->cb + 4);
  391     bin->cb += 4;
  392 
  393     ptr = bin->lpb + bin->cb - 4;
  394 
  395     *ptr++ = ( val        & 0xFF);
  396     *ptr++ = ((val >>  8) & 0xFF);
  397     *ptr++ = ((val >> 16) & 0xFF);
  398     *ptr++ = ((val >> 24) & 0xFF);
  399 }
  400 
  401 /* returns how many bytes read, 0 means an error */
  402 static uint32_t
  403 bin_decode_uint16 (const uint8_t *ptr, uint32_t ptr_cb, uint16_t *res)
  404 {
  405     g_return_val_if_fail (res != NULL, 0);
  406     g_return_val_if_fail (ptr != NULL, 0);
  407 
  408     if (ptr_cb < 2)
  409         return 0;
  410 
  411     *res = ((ptr[0] & 0xFF)     ) |
  412            ((ptr[1] & 0xFF) << 8);
  413 
  414     return 2;
  415 }
  416 
  417 /* returns how many bytes read, 0 means an error */
  418 static uint32_t
  419 bin_decode_uint32 (const uint8_t *ptr, uint32_t ptr_cb, uint32_t *res)
  420 {
  421     g_return_val_if_fail (res != NULL, 0);
  422     g_return_val_if_fail (ptr != NULL, 0);
  423 
  424     if (ptr_cb < 4)
  425         return 0;
  426 
  427     *res = ((ptr[0] & 0xFF)      ) |
  428            ((ptr[1] & 0xFF) <<  8) |
  429            ((ptr[2] & 0xFF) << 16) |
  430            ((ptr[3] & 0xFF) << 24);
  431 
  432     return 4;
  433 }
  434 
  435 static uint32_t
  436 bin_decode_string (const uint8_t *ptr, uint32_t sz, gchar **str, gboolean is_unicode)
  437 {
  438     uint32_t len;
  439 
  440     g_return_val_if_fail (ptr != NULL, 0);
  441     g_return_val_if_fail (str != NULL, 0);
  442 
  443     for (len = 0; len < sz; len += (is_unicode ? 2 : 1)) {
  444         if (ptr[len] == 0x00 && (!is_unicode || (len + 1 < sz && ptr[len + 1] == 0x00)))
  445             break;
  446     }
  447 
  448     if (len >= sz || ptr[len] != 0x00 || (is_unicode && (len + 1 >= sz || ptr[len + 1] != 0x00)))
  449         return 0;
  450 
  451     if (is_unicode) {
  452         *str = g_utf16_to_utf8 ((const gunichar2 *) ptr, len / 2, NULL, NULL, NULL);
  453     } else {
  454         *str = g_malloc0 (sizeof(gchar) * (1 + len));
  455         strncpy (*str, (const gchar *) ptr, len);
  456     }
  457 
  458     return len + 1 + (is_unicode ? 1 : 0);
  459 }
  460 
  461 static void
  462 e_mapi_util_bin_append_string (TALLOC_CTX *mem_ctx, struct Binary_r *bin, const gchar *val)
  463 {
  464     gsize len = strlen (val);
  465     gchar *ptr = NULL;
  466 
  467     bin->lpb = talloc_realloc (mem_ctx, bin->lpb, uint8_t, bin->cb + (len + 1));
  468     bin->cb += (len + 1);
  469 
  470     ptr = (gchar *) bin->lpb + bin->cb - (len + 1);
  471 
  472     strcpy (ptr, val);
  473 }
  474 
  475 static void
  476 e_mapi_util_bin_append_val (TALLOC_CTX *mem_ctx, struct Binary_r *bin, const uint8_t *val, gsize len)
  477 {
  478     uint8_t *ptr = NULL;
  479 
  480     bin->lpb = talloc_realloc (mem_ctx, bin->lpb, uint8_t, bin->cb + len);
  481     bin->cb += len;
  482 
  483     ptr = bin->lpb + bin->cb - len;
  484 
  485     memcpy (ptr, val, len);
  486 }
  487 
  488 static void
  489 e_mapi_util_bin_append_unicode (TALLOC_CTX *mem_ctx, struct Binary_r *bin, const gchar *val)
  490 {
  491     gunichar2 *utf16;
  492     glong written = 0;
  493 
  494     utf16 = g_utf8_to_utf16 (val, -1, NULL, &written, NULL);
  495     g_return_if_fail (utf16 != NULL);
  496 
  497     e_mapi_util_bin_append_val (mem_ctx, bin, (uint8_t *)utf16, (written + 1) * 2);
  498 
  499     g_free (utf16);
  500 }
  501 
  502 static const uint8_t MAPI_ONE_OFF_UID[] = {
  503     0x81, 0x2b, 0x1f, 0xa4, 0xbe, 0xa3, 0x10, 0x19,
  504     0x9d, 0x6e, 0x00, 0xdd, 0x01, 0x0f, 0x54, 0x02
  505 };
  506 
  507 #define MAPI_ONE_OFF_UNICODE      0x8000
  508 #define MAPI_ONE_OFF_NO_RICH_INFO 0x0001
  509 #define MAPI_ONE_OFF_MYSTERY_FLAG 0x1000
  510 
  511 /**
  512  * e_mapi_util_recip_entryid_generate_smtp:
  513  * @entryid: entry ID to be filled
  514  * @display_name: the display name of the user
  515  * @email: the email address
  516  *
  517  * Constructs a "one-off" ENTRYID value that can be used as a MAPI
  518  * recipient (eg, for a message forwarding server-side rule),
  519  * corresponding to @display_name and @email.
  520  *
  521  * Return value: the recipient ENTRYID
  522  **/
  523 void
  524 e_mapi_util_recip_entryid_generate_smtp (TALLOC_CTX *mem_ctx, struct Binary_r *entryid, const gchar *display_name, const gchar *email)
  525 {
  526     g_return_if_fail (entryid != NULL);
  527 
  528     e_mapi_util_bin_append_uint32 (mem_ctx, entryid, 0);
  529     e_mapi_util_bin_append_val (mem_ctx, entryid, MAPI_ONE_OFF_UID, sizeof(MAPI_ONE_OFF_UID));
  530     e_mapi_util_bin_append_uint16 (mem_ctx, entryid, 0);
  531     e_mapi_util_bin_append_uint16 (mem_ctx, entryid, MAPI_ONE_OFF_NO_RICH_INFO | MAPI_ONE_OFF_MYSTERY_FLAG | MAPI_ONE_OFF_UNICODE);
  532     e_mapi_util_bin_append_unicode (mem_ctx, entryid, display_name);
  533     e_mapi_util_bin_append_unicode (mem_ctx, entryid, "SMTP");
  534     e_mapi_util_bin_append_unicode (mem_ctx, entryid, email);
  535 }
  536 
  537 static const uint8_t MAPI_LOCAL_UID[] = {
  538     0xdc, 0xa7, 0x40, 0xc8, 0xc0, 0x42, 0x10, 0x1a,
  539     0xb4, 0xb9, 0x08, 0x00, 0x2b, 0x2f, 0xe1, 0x82
  540 };
  541 
  542 /**
  543  * e_mapi_util_recip_entryid_generate_ex:
  544  * @exchange_dn: the Exchange 5.5-style DN of the local user
  545  *
  546  * Constructs an ENTRYID value that can be used as a MAPI
  547  * recipient (eg, for a message forwarding server-side rule),
  548  * corresponding to the local user identified by @exchange_dn.
  549  **/
  550 void
  551 e_mapi_util_recip_entryid_generate_ex (TALLOC_CTX *mem_ctx, struct Binary_r *entryid, const gchar *exchange_dn)
  552 {
  553     e_mapi_util_bin_append_uint32 (mem_ctx, entryid, 0);
  554     e_mapi_util_bin_append_val (mem_ctx, entryid, MAPI_LOCAL_UID, sizeof(MAPI_LOCAL_UID));
  555     e_mapi_util_bin_append_uint16 (mem_ctx, entryid, 1);
  556     e_mapi_util_bin_append_uint16 (mem_ctx, entryid, 0);
  557     e_mapi_util_bin_append_string (mem_ctx, entryid, exchange_dn);
  558 }
  559 
  560 static gboolean
  561 recip_entryid_decode_smtp (const struct Binary_r *entryid, gchar **display_name, gchar **email)
  562 {
  563     uint32_t u32, sz, r;
  564     uint16_t u16, flags;
  565     uint8_t *ptr;
  566     gchar *smtp;
  567 
  568     g_return_val_if_fail (entryid != NULL, FALSE);
  569     g_return_val_if_fail (entryid->lpb != NULL, FALSE);
  570     g_return_val_if_fail (display_name != NULL, FALSE);
  571     g_return_val_if_fail (email != NULL, FALSE);
  572 
  573     *display_name = NULL;
  574     *email = NULL;
  575 
  576     ptr = entryid->lpb;
  577     sz = entryid->cb;
  578 
  579     u32 = 1;
  580     r = bin_decode_uint32 (ptr, sz, &u32);
  581     if (!r || u32 != 0)
  582         return FALSE;
  583 
  584     ptr += r;
  585     sz -= r;
  586 
  587     for (r = 0; r < G_N_ELEMENTS (MAPI_ONE_OFF_UID) && r < sz; r++) {
  588         if (ptr[r] != MAPI_ONE_OFF_UID[r])
  589             return FALSE;
  590     }
  591 
  592     if (r != G_N_ELEMENTS (MAPI_ONE_OFF_UID))
  593         return FALSE;
  594 
  595     ptr += r;
  596     sz -= r;
  597 
  598     u16 = 1;
  599     r = bin_decode_uint16 (ptr, sz, &u16);
  600     if (!r || u16 != 0)
  601         return FALSE;
  602     ptr += r;
  603     sz -= r;
  604 
  605     flags = 0;
  606     r = bin_decode_uint16 (ptr, sz, &flags);
  607     if (!r)
  608         return FALSE;
  609     ptr += r;
  610     sz -= r;
  611 
  612     r = bin_decode_string (ptr, sz, display_name, (flags & MAPI_ONE_OFF_UNICODE) != 0);
  613     if (!r || !*display_name)
  614         return FALSE;
  615     ptr += r;
  616     sz -= r;
  617 
  618     smtp = NULL;
  619     r = bin_decode_string (ptr, sz, &smtp, (flags & MAPI_ONE_OFF_UNICODE) != 0);
  620     if (!r || !smtp || !g_str_equal (smtp, "SMTP")) {
  621         g_free (smtp);
  622         g_free (*display_name);
  623         *display_name = NULL;
  624 
  625         return FALSE;
  626     }
  627     g_free (smtp);
  628     ptr += r;
  629     sz -= r;
  630 
  631     r = bin_decode_string (ptr, sz, email, (flags & MAPI_ONE_OFF_UNICODE) != 0);
  632     if (!r || !*email) {
  633         g_free (*display_name);
  634         *display_name = NULL;
  635 
  636         return FALSE;
  637     }
  638 
  639     return TRUE;
  640 }
  641 
  642 static gboolean
  643 recip_entryid_decode_ex (const struct Binary_r *entryid, gchar **exchange_dn)
  644 {
  645     uint32_t u32, sz, r;
  646     uint8_t *ptr;
  647 
  648     g_return_val_if_fail (entryid != NULL, FALSE);
  649     g_return_val_if_fail (entryid->lpb != NULL, FALSE);
  650     g_return_val_if_fail (exchange_dn != NULL, FALSE);
  651 
  652     *exchange_dn = NULL;
  653 
  654     ptr = entryid->lpb;
  655     sz = entryid->cb;
  656 
  657     u32 = 1;
  658     r = bin_decode_uint32 (ptr, sz, &u32);
  659     if (!r || u32 != 0)
  660         return FALSE;
  661 
  662     ptr += r;
  663     sz -= r;
  664 
  665     for (r = 0; r < G_N_ELEMENTS (MAPI_LOCAL_UID) && r < sz; r++) {
  666         if (ptr[r] != MAPI_LOCAL_UID[r])
  667             return FALSE;
  668     }
  669 
  670     if (r != G_N_ELEMENTS (MAPI_LOCAL_UID))
  671         return FALSE;
  672 
  673     ptr += r;
  674     sz -= r;
  675 
  676     /* version */
  677     u32 = 0;
  678     r = bin_decode_uint32 (ptr, sz, &u32);
  679     if (!r)
  680         return FALSE;
  681     ptr += r;
  682     sz -= r;
  683 
  684     /* type */
  685     u32 = 0;
  686     r = bin_decode_uint32 (ptr, sz, &u32);
  687     if (!r)
  688         return FALSE;
  689     ptr += r;
  690     sz -= r;
  691 
  692     r = bin_decode_string (ptr, sz, exchange_dn, FALSE);
  693     if (!r || !*exchange_dn)
  694         return FALSE;
  695 
  696     return TRUE;
  697 }
  698 
  699 /**
  700  * e_mapi_util_recip_entryid_decode:
  701  * @conn: ExchangeMapiCOnnection to resolve names, if required
  702  * @entryid: recipient's ENTRYID to decode
  703  * @display_name: (out): stored display name, if any; can be NULL
  704  * @email: (out): email or exchange DN; cannot be NULL
  705  *
  706  * Returns: Whether was able to decode recipient information from the @entryid.
  707  **/
  708 gboolean
  709 e_mapi_util_recip_entryid_decode (EMapiConnection *conn, const struct Binary_r *entryid, gchar **display_name, gchar **email)
  710 {
  711     gchar *dispnm = NULL, *exchange_dn = NULL;
  712 
  713     g_return_val_if_fail (conn != NULL, FALSE);
  714     g_return_val_if_fail (entryid != NULL, FALSE);
  715     g_return_val_if_fail (email != NULL, FALSE);
  716 
  717     *email = NULL;
  718     if (display_name)
  719         *display_name = NULL;
  720 
  721     if (recip_entryid_decode_smtp (entryid, &dispnm, email)) {
  722         if (display_name)
  723             *display_name = dispnm;
  724         else
  725             g_free (dispnm);
  726 
  727         return TRUE;
  728     }
  729 
  730     if (recip_entryid_decode_ex (entryid, &exchange_dn)) {
  731         *email = e_mapi_connection_ex_to_smtp (conn, exchange_dn, display_name, NULL, NULL);
  732         g_free (exchange_dn);
  733 
  734         return *email != NULL;
  735     }
  736 
  737     return FALSE;
  738 }
  739 
  740 gboolean
  741 e_mapi_util_recip_entryid_decode_dn (const struct SBinary_short *entryid,
  742                      gchar **exchange_dn)
  743 {
  744     struct Binary_r ei;
  745 
  746     if (!entryid)
  747         return FALSE;
  748 
  749     ei.cb = entryid->cb;
  750     ei.lpb = entryid->lpb;
  751 
  752     return recip_entryid_decode_ex (&ei, exchange_dn);
  753 }
  754 
  755 gboolean
  756 e_mapi_util_recip_entryid_equal (const struct SBinary_short *entryid1,
  757                  const struct SBinary_short *entryid2)
  758 {
  759     gchar *dn1 = NULL, *dn2 = NULL;
  760     gboolean same = FALSE;
  761 
  762     if (!entryid1 && !entryid2)
  763         return TRUE;
  764 
  765     if (!entryid1 || !entryid2 || !entryid1->lpb || !entryid2->lpb || entryid1->cb != entryid2->cb)
  766         return FALSE;
  767 
  768     same = e_mapi_util_recip_entryid_decode_dn (entryid1, &dn1) &&
  769            e_mapi_util_recip_entryid_decode_dn (entryid2, &dn2) &&
  770            dn1 && dn2 && g_ascii_strcasecmp (dn1, dn2) == 0;
  771 
  772     g_free (dn1);
  773     g_free (dn2);
  774 
  775     return same;
  776 }
  777 
  778 /**
  779  * e_mapi_util_profiledata_from_settings:
  780  * @empd: destination for profile settings
  781  * @settings: a #CamelMapiSettings
  782  *
  783  * Sets the members of an EMapiProfileData instance to
  784  * reflect the account settings in @settings.
  785  *
  786  * @note: no allocation is done, so do not finalize @settings and the
  787  *        respective underlying pointers until you no longer need the
  788  *        profile data.
  789  **/
  790 void
  791 e_mapi_util_profiledata_from_settings (EMapiProfileData *empd, CamelMapiSettings *settings)
  792 {
  793     CamelNetworkSettings *network_settings;
  794     CamelNetworkSecurityMethod security_method;
  795 
  796     network_settings = CAMEL_NETWORK_SETTINGS (settings);
  797     security_method = camel_network_settings_get_security_method (network_settings);
  798 
  799     empd->use_ssl = (security_method != CAMEL_NETWORK_SECURITY_METHOD_NONE);
  800     empd->domain = camel_mapi_settings_get_domain (settings);
  801     empd->krb_sso = camel_mapi_settings_get_kerberos (settings);
  802     empd->krb_realm = camel_mapi_settings_get_realm (settings);
  803 }
  804 
  805 gboolean
  806 e_mapi_util_trigger_krb_auth (const EMapiProfileData *empd,
  807                   GError **error)
  808 {
  809     gint success = FALSE;
  810     GError *local_error = NULL;
  811     GDBusConnection *connection;
  812     GDBusMessage *message, *reply;
  813     gchar *name;
  814 
  815     connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &local_error);
  816     if (local_error) {
  817         g_warning ("could not get system bus: %s\n",
  818                local_error->message);
  819         g_propagate_error (error, local_error);
  820         return FALSE;
  821     }
  822 
  823     g_dbus_connection_set_exit_on_close (connection, FALSE);
  824     /* Create a new message on the KRB_DBUS_INTERFACE */
  825     message = g_dbus_message_new_method_call (KRB_DBUS_INTERFACE,
  826                           KRB_DBUS_PATH,
  827                           KRB_DBUS_INTERFACE,
  828                           "acquireTgt");
  829     if (!message) {
  830         g_object_unref (connection);
  831         return FALSE;
  832     }
  833 
  834     /* Appends the data as an argument to the message */
  835     name = g_strdup_printf ("%s@%s", empd->username, empd->krb_realm);
  836     g_dbus_message_set_body (message, g_variant_new ("(s)", name));
  837 
  838     /* Sends the message: Have a 300 sec wait timeout  */
  839     reply = g_dbus_connection_send_message_with_reply_sync (connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, 300 * 1000, NULL, NULL, &local_error);
  840     g_free (name);
  841 
  842     if (!local_error && reply) {
  843         if (g_dbus_message_to_gerror (reply, &local_error)) {
  844             g_object_unref (reply);
  845             reply = NULL;
  846         }
  847     }
  848 
  849     if (local_error) {
  850         g_dbus_error_strip_remote_error (local_error);
  851 
  852         if (g_error_matches (local_error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) {
  853             GError *new_error = g_error_new (G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
  854                 _("Cannot ask for Kerberos ticket. Obtain the ticket manually, like on command line with “kinit” or"
  855                   " open “Online Accounts” in “Settings” and add the Kerberos account there. Reported error was: %s"),
  856                 local_error->message);
  857 
  858             g_clear_error (&local_error);
  859             local_error = new_error;
  860         }
  861 
  862         g_propagate_error (error, local_error);
  863     }
  864 
  865     if (reply) {
  866         GVariant *body = g_dbus_message_get_body (reply);
  867         if (body) {
  868             g_variant_get (body, "(b)", &success);
  869         }
  870         g_object_unref (reply);
  871     }
  872 
  873     /* Free the message */
  874     g_object_unref (message);
  875     g_object_unref (connection);
  876 
  877     return success && !local_error;
  878 }
  879 
  880 gboolean
  881 e_mapi_util_trigger_krb_auth_from_settings (CamelMapiSettings *mapi_settings,
  882                         GError **error)
  883 {
  884     EMapiProfileData empd = { 0 };
  885     CamelNetworkSettings *network_settings;
  886 
  887     g_return_val_if_fail (CAMEL_IS_MAPI_SETTINGS (mapi_settings), FALSE);
  888 
  889     network_settings = CAMEL_NETWORK_SETTINGS (mapi_settings);
  890 
  891     empd.server = camel_network_settings_get_host (network_settings);
  892     empd.username = camel_network_settings_get_user (network_settings);
  893 
  894     e_mapi_util_profiledata_from_settings (&empd, mapi_settings);
  895 
  896     return e_mapi_util_trigger_krb_auth (&empd, error);
  897 }
  898 
  899 /**
  900  * e_mapi_util_profile_name:
  901  * @mapi_ctx: a mapi context; can be NULL if @migrate is FALSE
  902  * @empd: profile information used to construct the name
  903  * @migrate: whether migrate old profile name to a new one
  904  *
  905  * Constructs profile name from given parameters and
  906  * returns it as a newly allocated string. It can also
  907  * rename old profile name string to a new name, if requested.
  908  **/
  909 gchar *
  910 e_mapi_util_profile_name (struct mapi_context *mapi_ctx, const EMapiProfileData *empd, gboolean migrate)
  911 {
  912     gchar *res;
  913 
  914     res = g_strdup_printf ("%s@%s@%s", empd->username, empd->domain, empd->server);
  915     res = g_strcanon (res, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@.-", '_');
  916 
  917     if (migrate) {
  918         /* expects MAPIInitialize already called! */
  919         gchar *old_name;
  920 
  921         g_return_val_if_fail (mapi_ctx != NULL, res);
  922 
  923         old_name = g_strdup_printf ("%s@%s", empd->username, empd->domain);
  924         old_name = g_strcanon (old_name, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@", '_');
  925 
  926         e_mapi_rename_profile (mapi_ctx, old_name, res, NULL);
  927 
  928         g_free (old_name);
  929     }
  930 
  931     return res;
  932 }
  933 
  934 /**
  935  * Adds a new SPropValue at the end of values_array, allocating its memory in the mem_ctx.
  936  * *n_values holds number of items stored in the array, and will be increased by one.
  937  **/
  938 gboolean
  939 e_mapi_utils_add_spropvalue (TALLOC_CTX *mem_ctx,
  940                  struct SPropValue **values_array,
  941                  uint32_t *n_values,
  942                  uint32_t prop_tag,
  943                  gconstpointer prop_value)
  944 {
  945     g_return_val_if_fail (mem_ctx != NULL, FALSE);
  946     g_return_val_if_fail (values_array != NULL, FALSE);
  947     g_return_val_if_fail (n_values != NULL, FALSE);
  948 
  949     *values_array = add_SPropValue (mem_ctx, *values_array, n_values, prop_tag, prop_value);
  950 
  951     return TRUE;
  952 }
  953 
  954 gboolean
  955 e_mapi_utils_add_property (struct mapi_SPropValue_array *properties,
  956                uint32_t proptag,
  957                gconstpointer propvalue,
  958                TALLOC_CTX *mem_ctx)
  959 {
  960     uint32_t ii;
  961     struct SPropValue sprop = { 0 };
  962 
  963     g_return_val_if_fail (properties != NULL, FALSE);
  964     g_return_val_if_fail (proptag != 0, FALSE);
  965     g_return_val_if_fail (propvalue != NULL, FALSE);
  966     g_return_val_if_fail (mem_ctx != NULL, FALSE);
  967 
  968     /* make copy of string properties */
  969     if ((proptag & 0xFFFF) == PT_STRING8 ||
  970         (proptag & 0xFFFF) == PT_UNICODE)
  971         propvalue = talloc_strdup (mem_ctx, (const gchar *) propvalue);
  972 
  973     sprop.ulPropTag = proptag;
  974     g_return_val_if_fail (set_SPropValue (&sprop, propvalue), FALSE);
  975 
  976     for (ii = 0; ii < properties->cValues; ii++) {
  977         if (properties->lpProps[ii].ulPropTag == proptag) {
  978             cast_mapi_SPropValue (mem_ctx, &(properties->lpProps[ii]), &sprop);
  979             break;
  980         }
  981     }
  982 
  983     if (ii == properties->cValues) {
  984         properties->cValues++;
  985         properties->lpProps = talloc_realloc (mem_ctx,
  986             properties->lpProps,
  987             struct mapi_SPropValue,
  988             properties->cValues + 1);
  989         cast_mapi_SPropValue (mem_ctx, &(properties->lpProps[properties->cValues - 1]), &sprop);
  990         properties->lpProps[properties->cValues].ulPropTag = 0;
  991     }
  992 
  993     return TRUE;
  994 }
  995 
  996 /* the first call should be with crc32 set to 0 */
  997 uint32_t
  998 e_mapi_utils_push_crc32 (uint32_t crc32, uint8_t *bytes, uint32_t n_bytes)
  999 {
 1000     static uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
 1001         0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
 1002         0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
 1003         0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
 1004         0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
 1005         0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
 1006         0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
 1007         0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
 1008         0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
 1009         0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
 1010         0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
 1011         0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
 1012         0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
 1013         0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
 1014         0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
 1015         0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
 1016         0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
 1017         0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
 1018         0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
 1019         0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
 1020         0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
 1021         0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
 1022         0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
 1023         0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
 1024         0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
 1025         0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
 1026         0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
 1027         0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
 1028         0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
 1029         0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
 1030         0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
 1031         0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
 1032         0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
 1033         0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
 1034         0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
 1035         0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
 1036         0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
 1037         0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
 1038         0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
 1039         0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
 1040         0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
 1041         0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
 1042         0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
 1043         0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
 1044     };
 1045 
 1046     g_return_val_if_fail (bytes != NULL, crc32);
 1047 
 1048     while (n_bytes > 0) {
 1049         #define UPDC32(octet,crc) (crc_32_tab[((crc) ^ ((uint8_t)octet)) & 0xff] ^ ((crc) >> 8))
 1050 
 1051         crc32 = UPDC32 (*bytes, crc32);
 1052 
 1053         n_bytes--;
 1054         bytes++;
 1055     }
 1056 
 1057     return crc32;
 1058 }
 1059 
 1060 /* copies an SBinary_short, which should be freed with e_mapi_util_free_sbinary_short() */
 1061 struct SBinary_short *
 1062 e_mapi_util_copy_sbinary_short (const struct SBinary_short *bin)
 1063 {
 1064     struct SBinary_short *res;
 1065 
 1066     if (!bin || !bin->cb)
 1067         return NULL;
 1068 
 1069     res = g_new0 (struct SBinary_short, 1);
 1070     res->cb = bin->cb;
 1071     res->lpb = g_new (uint8_t, res->cb);
 1072     memcpy (res->lpb, bin->lpb, res->cb);
 1073 
 1074     return res;
 1075 }
 1076 
 1077 /* frees SBinary_short previously allocated by e_mapi_util_copy_sbinary_short() */
 1078 void
 1079 e_mapi_util_free_sbinary_short (struct SBinary_short *bin)
 1080 {
 1081     if (!bin)
 1082         return;
 1083 
 1084     g_free (bin->lpb);
 1085     g_free (bin);
 1086 }
 1087 
 1088 time_t
 1089 e_mapi_util_filetime_to_time_t (const struct FILETIME *filetime)
 1090 {
 1091     NTTIME nt;
 1092 
 1093     if (!filetime)
 1094         return (time_t) 0;
 1095 
 1096     nt = filetime->dwHighDateTime;
 1097     nt = nt << 32;
 1098     nt |= filetime->dwLowDateTime;
 1099 
 1100     nt /=  10 * 1000 * 1000;
 1101     nt -= 11644473600LL;
 1102 
 1103     return (time_t) nt;
 1104 }
 1105 
 1106 void
 1107 e_mapi_util_time_t_to_filetime (const time_t tt, struct FILETIME *filetime)
 1108 {
 1109     NTTIME nt;
 1110 
 1111     g_return_if_fail (filetime != NULL);
 1112 
 1113     nt = tt;
 1114     nt += 11644473600LL;
 1115     nt *=  10 * 1000 * 1000;
 1116 
 1117     filetime->dwLowDateTime = nt & 0xFFFFFFFF;
 1118     nt = nt >> 32;
 1119     filetime->dwHighDateTime = nt & 0xFFFFFFFF;
 1120 }
 1121 
 1122 gboolean
 1123 e_mapi_utils_propagate_cancelled_error (const GError *mapi_error,
 1124                     GError **error)
 1125 {
 1126     if (!g_error_matches (mapi_error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
 1127         !g_error_matches (mapi_error, E_MAPI_ERROR, MAPI_E_USER_CANCEL))
 1128         return FALSE;
 1129 
 1130     g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, mapi_error->message);
 1131 
 1132     return TRUE;
 1133 }
 1134 
 1135 gboolean
 1136 e_mapi_utils_create_mapi_context (struct mapi_context **mapi_ctx, GError **perror)
 1137 {
 1138     const gchar *user_data_dir;
 1139     gchar *profpath;
 1140     enum MAPISTATUS ms;
 1141 
 1142     g_return_val_if_fail (mapi_ctx != NULL, FALSE);
 1143 
 1144     if (!e_mapi_utils_global_lock (NULL, perror))
 1145         return FALSE;
 1146 
 1147     *mapi_ctx = NULL;
 1148     user_data_dir = e_get_user_data_dir ();
 1149     profpath = g_build_filename (user_data_dir, DEFAULT_PROF_NAME, NULL);
 1150 
 1151     if (!g_file_test (profpath, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
 1152         /* Create a ProfileStore */
 1153         ms = CreateProfileStore (profpath, LIBMAPI_LDIF_DIR);
 1154         if (ms != MAPI_E_SUCCESS && (ms != MAPI_E_NO_ACCESS || !g_file_test (profpath, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) {
 1155             make_mapi_error (perror, "CreateProfileStore", ms);
 1156             g_free (profpath);
 1157 
 1158             e_mapi_utils_global_unlock ();
 1159             return FALSE;
 1160         }
 1161     }
 1162 
 1163     ms = MAPIInitialize (mapi_ctx, profpath);
 1164     if (ms != MAPI_E_SUCCESS) {
 1165         make_mapi_error (perror, "MAPIInitialize", ms);
 1166         g_free (profpath);
 1167 
 1168         e_mapi_utils_global_unlock ();
 1169         return FALSE;
 1170     }
 1171 
 1172     g_free (profpath);
 1173 
 1174     /* Initialize libmapi logger */
 1175     if (*mapi_ctx && g_getenv ("LIBMAPI_DEBUG")) {
 1176         guint32 debug_log_level = atoi (g_getenv ("LIBMAPI_DEBUG"));
 1177         SetMAPIDumpData (*mapi_ctx, TRUE);
 1178         SetMAPIDebugLevel (*mapi_ctx, debug_log_level);
 1179     }
 1180 
 1181     e_mapi_utils_global_unlock ();
 1182 
 1183     return TRUE;
 1184 }
 1185 
 1186 void
 1187 e_mapi_utils_destroy_mapi_context (struct mapi_context *mapi_ctx)
 1188 {
 1189     if (!mapi_ctx)
 1190         return;
 1191 
 1192     if (!e_mapi_utils_global_lock (NULL, NULL))
 1193         return;
 1194 
 1195     MAPIUninitialize (mapi_ctx);
 1196     e_mapi_utils_global_unlock ();
 1197 }
 1198 
 1199 gboolean
 1200 e_mapi_utils_ensure_utf8_string (uint32_t proptag,
 1201                  const uint32_t *cpid,
 1202                  const guint8 *buf_data,
 1203                  guint32 buf_len,
 1204                  gchar **out_utf8)
 1205 {
 1206     g_return_val_if_fail (buf_data != NULL, FALSE);
 1207     g_return_val_if_fail (out_utf8 != NULL, FALSE);
 1208 
 1209     if (proptag != PidTagHtml && (proptag & 0xFFFF) != PT_UNICODE)
 1210         return FALSE;
 1211 
 1212     *out_utf8 = NULL;
 1213 
 1214     if ((cpid && (*cpid == 1200 || *cpid == 1201)) || (buf_len > 5 && buf_data[3] == '\0')) {
 1215         /* this is special, get the CPID and transform to utf8 when it's utf16 */
 1216         gsize written = 0;
 1217         gchar *in_utf8;
 1218 
 1219         /* skip Unicode marker, if there */
 1220         if (buf_len >= 2 && buf_data[0] == 0xFF && buf_data[1] == 0xFE)
 1221             in_utf8 = g_convert ((const gchar *) buf_data + 2, buf_len - 2, "UTF-8", "UTF-16", NULL, &written, NULL);
 1222         else
 1223             in_utf8 = g_convert ((const gchar *) buf_data, buf_len, "UTF-8", "UTF-16", NULL, &written, NULL);
 1224 
 1225         if (in_utf8 && written > 0) {
 1226             *out_utf8 = g_strndup (in_utf8, written);
 1227             g_free (in_utf8);
 1228         }
 1229     }
 1230 
 1231     if (!*out_utf8)
 1232         *out_utf8 = g_strndup ((const gchar *) buf_data, buf_len);
 1233 
 1234     return TRUE;
 1235 }
 1236 
 1237 /* takes pointer to a time_t and populates restrictions
 1238    with a restriction on PidTagLastModificationTime
 1239 */
 1240 gboolean
 1241 e_mapi_utils_build_last_modify_restriction (EMapiConnection *conn,
 1242                         TALLOC_CTX *mem_ctx,
 1243                         struct mapi_SRestriction **restrictions,
 1244                         gpointer user_data,
 1245                         GCancellable *cancellable,
 1246                         GError **perror)
 1247 {
 1248     const time_t *latest_last_modify = user_data;
 1249     struct mapi_SRestriction *restriction = NULL;
 1250 
 1251     g_return_val_if_fail (restrictions != NULL, FALSE);
 1252 
 1253     if (latest_last_modify && *latest_last_modify > 0) {
 1254         struct SPropValue sprop;
 1255         struct timeval t;
 1256 
 1257         restriction = talloc_zero (mem_ctx, struct mapi_SRestriction);
 1258         g_return_val_if_fail (restriction != NULL, FALSE);
 1259 
 1260         restriction->rt = RES_PROPERTY;
 1261         restriction->res.resProperty.relop = RELOP_GT;
 1262         restriction->res.resProperty.ulPropTag = PidTagLastModificationTime;
 1263 
 1264         t.tv_sec = *latest_last_modify;
 1265         t.tv_usec = 0;
 1266 
 1267         set_SPropValue_proptag_date_timeval (&sprop, PidTagLastModificationTime, &t);
 1268         cast_mapi_SPropValue (mem_ctx, &(restriction->res.resProperty.lpProp), &sprop);
 1269     }
 1270 
 1271     *restrictions = restriction;
 1272 
 1273     return TRUE;
 1274 }
 1275 
 1276 gboolean
 1277 e_mapi_utils_get_folder_basic_properties_cb (EMapiConnection *conn,
 1278                          TALLOC_CTX *mem_ctx,
 1279                          /* const */ struct mapi_SPropValue_array *properties,
 1280                          gpointer user_data,
 1281                          GCancellable *cancellable,
 1282                          GError **perror)
 1283 {
 1284     struct FolderBasicPropertiesData *fbp = user_data;
 1285     const mapi_id_t *pfid;
 1286     const struct FILETIME *plast_modified;
 1287     const uint32_t *pcontent_count;
 1288 
 1289     g_return_val_if_fail (properties != NULL, FALSE);
 1290     g_return_val_if_fail (user_data != NULL, FALSE);
 1291 
 1292     pfid = e_mapi_util_find_array_propval (properties, PidTagFolderId);
 1293     plast_modified = e_mapi_util_find_array_propval (properties, PidTagLastModificationTime);
 1294     pcontent_count = e_mapi_util_find_array_propval (properties, PidTagContentCount);
 1295 
 1296     if (pfid)
 1297         fbp->fid = *pfid;
 1298     else
 1299         fbp->fid = 0;
 1300 
 1301     if (pcontent_count)
 1302         fbp->obj_total = *pcontent_count;
 1303     else
 1304         fbp->obj_total = 0;
 1305 
 1306     if (plast_modified)
 1307         fbp->last_modified = e_mapi_util_filetime_to_time_t (plast_modified);
 1308     else
 1309         fbp->last_modified = 0;
 1310 
 1311     return TRUE;
 1312 }
 1313 
 1314 gboolean
 1315 e_mapi_utils_copy_to_mapi_SPropValue (TALLOC_CTX *mem_ctx,
 1316                       struct mapi_SPropValue *mapi_sprop, 
 1317                       struct SPropValue *sprop)
 1318 {
 1319     mapi_sprop->ulPropTag = sprop->ulPropTag;
 1320 
 1321     switch (sprop->ulPropTag & 0xFFFF) {
 1322     case PT_BOOLEAN:
 1323         mapi_sprop->value.b = sprop->value.b;
 1324         return TRUE;
 1325     case PT_I2:
 1326         mapi_sprop->value.i = sprop->value.i;
 1327         return TRUE;
 1328     case PT_LONG:
 1329         mapi_sprop->value.l = sprop->value.l;
 1330         return TRUE;
 1331     case PT_DOUBLE:
 1332         memcpy (&mapi_sprop->value.dbl, (uint8_t *) &sprop->value.dbl, 8);
 1333         return TRUE;
 1334     case PT_I8:
 1335         mapi_sprop->value.d = sprop->value.d;
 1336         return TRUE;
 1337     case PT_STRING8:
 1338         mapi_sprop->value.lpszA = talloc_strdup (mem_ctx, sprop->value.lpszA);
 1339         return TRUE;
 1340     case PT_UNICODE:
 1341         mapi_sprop->value.lpszW = talloc_strdup (mem_ctx, sprop->value.lpszW);
 1342         return TRUE;
 1343     case PT_SYSTIME:
 1344         mapi_sprop->value.ft.dwLowDateTime = sprop->value.ft.dwLowDateTime;
 1345         mapi_sprop->value.ft.dwHighDateTime = sprop->value.ft.dwHighDateTime;
 1346         return TRUE;
 1347     case PT_BINARY:
 1348         mapi_sprop->value.bin.cb = sprop->value.bin.cb;
 1349         mapi_sprop->value.bin.lpb = talloc_memdup (mem_ctx, sprop->value.bin.lpb, sprop->value.bin.cb);
 1350         return TRUE;
 1351         case PT_ERROR:
 1352                 mapi_sprop->value.err = sprop->value.err;
 1353                 return TRUE;
 1354     case PT_CLSID:
 1355     {
 1356         DATA_BLOB   b;
 1357 
 1358         b.data = sprop->value.lpguid->ab;
 1359         b.length = 16;
 1360 
 1361         GUID_from_ndr_blob (&b, &mapi_sprop->value.lpguid);
 1362 
 1363         return TRUE;
 1364     }
 1365     case PT_SVREID:
 1366         mapi_sprop->value.bin.cb = sprop->value.bin.cb;
 1367         mapi_sprop->value.bin.lpb = talloc_memdup (mem_ctx, sprop->value.bin.lpb, sprop->value.bin.cb);
 1368         return TRUE;
 1369     case PT_MV_STRING8:
 1370     {
 1371         uint32_t i;
 1372 
 1373         mapi_sprop->value.MVszA.cValues = sprop->value.MVszA.cValues;
 1374         mapi_sprop->value.MVszA.strings = talloc_array (mem_ctx, struct mapi_LPSTR, mapi_sprop->value.MVszA.cValues);
 1375         for (i = 0; i < mapi_sprop->value.MVszA.cValues; i++) {
 1376             mapi_sprop->value.MVszA.strings[i].lppszA = talloc_strdup (mem_ctx, sprop->value.MVszA.lppszA[i]);
 1377         }
 1378         return TRUE;
 1379     }
 1380     case PT_MV_UNICODE:
 1381     {
 1382         uint32_t i;
 1383 
 1384         mapi_sprop->value.MVszW.cValues = sprop->value.MVszW.cValues;
 1385         mapi_sprop->value.MVszW.strings = talloc_array (mem_ctx, struct mapi_LPWSTR, mapi_sprop->value.MVszW.cValues);
 1386         for (i = 0; i < mapi_sprop->value.MVszW.cValues; i++) {
 1387             mapi_sprop->value.MVszW.strings[i].lppszW = talloc_strdup (mem_ctx, sprop->value.MVszW.lppszW[i]);
 1388         }
 1389         return TRUE;
 1390     }
 1391     case PT_MV_BINARY:
 1392     {
 1393         uint32_t i;
 1394 
 1395         mapi_sprop->value.MVbin.cValues = sprop->value.MVbin.cValues;
 1396         mapi_sprop->value.MVbin.bin = talloc_array (mem_ctx, struct SBinary_short, mapi_sprop->value.MVbin.cValues);
 1397         for (i = 0; i < mapi_sprop->value.MVbin.cValues; i++) {
 1398             mapi_sprop->value.MVbin.bin[i].cb = sprop->value.MVbin.lpbin[i].cb;
 1399             mapi_sprop->value.MVbin.bin[i].lpb = talloc_memdup (mem_ctx, sprop->value.MVbin.lpbin[i].lpb, sprop->value.MVbin.lpbin[i].cb);
 1400         }
 1401         return TRUE;
 1402     }
 1403     case PT_MV_LONG:
 1404     {
 1405         uint32_t i;
 1406 
 1407         mapi_sprop->value.MVl.cValues = sprop->value.MVl.cValues;
 1408         mapi_sprop->value.MVl.lpl = talloc_array (mem_ctx, uint32_t, mapi_sprop->value.MVl.cValues);
 1409         for (i = 0; i < mapi_sprop->value.MVl.cValues; i++) {
 1410             mapi_sprop->value.MVl.lpl[i] = sprop->value.MVl.lpl[i];
 1411         }
 1412         return TRUE;
 1413     }
 1414         default:
 1415         break;
 1416     }
 1417 
 1418     return FALSE;
 1419 }
 1420 
 1421 static gpointer
 1422 unref_object_in_thread (gpointer ptr)
 1423 {
 1424     GObject *object = ptr;
 1425 
 1426     g_return_val_if_fail (object != NULL, NULL);
 1427 
 1428     g_object_unref (object);
 1429 
 1430     return NULL;
 1431 }
 1432 
 1433 void
 1434 e_mapi_utils_unref_in_thread (GObject *object)
 1435 {
 1436     GThread *thread;
 1437     GError *error = NULL;
 1438 
 1439     if (!object)
 1440         return;
 1441 
 1442     g_return_if_fail (G_IS_OBJECT (object));
 1443 
 1444     thread = g_thread_try_new (NULL, unref_object_in_thread, object, &error);
 1445     if (thread) {
 1446         g_thread_unref (thread);
 1447     } else {
 1448         g_warning ("%s: Failed to run thread: %s", G_STRFUNC, error ? error->message : "Unknown error");
 1449         g_object_unref (object);
 1450     }
 1451 }
 1452 
 1453 static gboolean
 1454 is_for_profile (ESource *source,
 1455         const gchar *profile)
 1456 {
 1457     ESourceCamel *extension;
 1458     CamelMapiSettings *settings;
 1459     const gchar *extension_name;
 1460 
 1461     if (!source)
 1462         return FALSE;
 1463 
 1464     if (!profile)
 1465         return TRUE;
 1466 
 1467     extension_name = e_source_camel_get_extension_name ("mapi");
 1468     if (!e_source_has_extension (source, extension_name))
 1469         return FALSE;
 1470 
 1471     extension = e_source_get_extension (source, extension_name);
 1472     settings = CAMEL_MAPI_SETTINGS (e_source_camel_get_settings (extension));
 1473 
 1474     return settings && g_strcmp0 (camel_mapi_settings_get_profile (settings), profile) == 0;
 1475 }
 1476 
 1477 /* filters @esources thus the resulting list will contain ESource-s only for @profile;
 1478    free returned list with g_list_free_full (list, g_object_unref); */
 1479 GList *
 1480 e_mapi_utils_filter_sources_for_profile (const GList *esources,
 1481                      const gchar *profile)
 1482 {
 1483     GList *found = NULL;
 1484     const GList *iter;
 1485     ESource *master_source;
 1486 
 1487     master_source = e_mapi_utils_get_master_source (esources, profile);
 1488     if (!master_source)
 1489         return NULL;
 1490 
 1491     for (iter = esources; iter; iter = iter->next) {
 1492         ESource *source = iter->data;
 1493 
 1494         if (is_for_profile (source, profile) ||
 1495             g_strcmp0 (e_source_get_uid (master_source), e_source_get_parent (source)) == 0)
 1496             found = g_list_prepend (found, g_object_ref (source));
 1497     }
 1498 
 1499     return g_list_reverse (found);
 1500 }
 1501 
 1502 /* returns (not-reffed) member of @esources, which is for @profile and @folder_id */
 1503 ESource *
 1504 e_mapi_utils_get_source_for_folder (const GList *esources,
 1505                     const gchar *profile,
 1506                     mapi_id_t folder_id)
 1507 {
 1508     ESource *master_source;
 1509     const GList *iter;
 1510     
 1511     master_source = e_mapi_utils_get_master_source (esources, profile);
 1512     if (!master_source)
 1513         return NULL;
 1514 
 1515     for (iter = esources; iter; iter = iter->next) {
 1516         ESource *source = iter->data;
 1517 
 1518         if ((is_for_profile (source, profile) ||
 1519             g_strcmp0 (e_source_get_uid (master_source), e_source_get_parent (source)) == 0) &&
 1520             e_source_has_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER)) {
 1521             ESourceMapiFolder *folder_ext = e_source_get_extension (source, E_SOURCE_EXTENSION_MAPI_FOLDER);
 1522 
 1523             g_return_val_if_fail (folder_ext != NULL, NULL);
 1524 
 1525             if (e_source_mapi_folder_get_id (folder_ext) == folder_id)
 1526                 return source;
 1527         }
 1528     }
 1529 
 1530     return NULL;
 1531 }
 1532 
 1533 /* returns (not-reffed) member of @esources, which is master (with no parent) source for @profile */
 1534 ESource *
 1535 e_mapi_utils_get_master_source (const GList *esources,
 1536                 const gchar *profile)
 1537 {
 1538     const GList *iter;
 1539 
 1540     for (iter = esources; iter; iter = iter->next) {
 1541         ESource *source = iter->data;
 1542 
 1543         if (!e_source_get_parent (source) &&
 1544             is_for_profile (source, profile))
 1545             return source;
 1546     }
 1547 
 1548     return NULL;
 1549 }