"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 }