1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4  * Copyright (C) 2012 Intel Corporation
5  *
6  * This library is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13  * for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Authors: Rodrigo Moya <rodrigo@ximian.com>
19  *          Tristan Van Berkom <tristanvb@openismus.com>
20  */
21 
22 #include "evolution-data-server-config.h"
23 
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <time.h>
27 #include <unistd.h>
28 
29 #ifdef G_OS_WIN32
30 #include <mbstring.h>
31 #endif
32 
33 #include <glib-object.h>
34 
35 #include "e-source.h"
36 #include "e-source-address-book.h"
37 #include "e-source-authentication.h"
38 #include "e-source-backend.h"
39 #include "e-source-calendar.h"
40 #include "e-source-collection.h"
41 #include "e-source-enumtypes.h"
42 #include "e-source-mail-identity.h"
43 #include "e-source-mail-submission.h"
44 #include "e-source-mail-transport.h"
45 #include "e-source-memo-list.h"
46 #include "e-source-registry.h"
47 #include "e-source-task-list.h"
48 #include "camel/camel.h"
49 
50 #include "e-data-server-util.h"
51 
52 /**
53  * e_get_user_cache_dir:
54  *
55  * Returns a base directory in which to store user-specific,
56  * non-essential cached data for Evolution or Evolution-Data-Server.
57  *
58  * The returned string is owned by libedataserver and must not be
59  * modified or freed.
60  *
61  * Returns: base directory for user-specific, non-essential data
62  *
63  * Since: 2.32
64  **/
65 const gchar *
e_get_user_cache_dir(void)66 e_get_user_cache_dir (void)
67 {
68 	static gchar *dirname = NULL;
69 
70 	if (G_UNLIKELY (dirname == NULL)) {
71 		const gchar *cache_dir = g_get_user_cache_dir ();
72 		dirname = g_build_filename (cache_dir, "evolution", NULL);
73 		g_mkdir_with_parents (dirname, 0700);
74 	}
75 
76 	return dirname;
77 }
78 
79 /**
80  * e_get_user_config_dir:
81  *
82  * Returns a base directory in which to store user-specific configuration
83  * information for Evolution or Evolution-Data-Server.
84  *
85  * The returned string is owned by libedataserver and must not be
86  * modified or freed.
87  *
88  * Returns: base directory for user-specific configuration information
89  *
90  * Since: 2.32
91  **/
92 const gchar *
e_get_user_config_dir(void)93 e_get_user_config_dir (void)
94 {
95 	static gchar *dirname = NULL;
96 
97 	if (G_UNLIKELY (dirname == NULL)) {
98 		const gchar *config_dir = g_get_user_config_dir ();
99 		dirname = g_build_filename (config_dir, "evolution", NULL);
100 		g_mkdir_with_parents (dirname, 0700);
101 	}
102 
103 	return dirname;
104 }
105 
106 /**
107  * e_get_user_data_dir:
108  *
109  * Returns a base directory in which to store user-specific data for
110  * Evolution or Evolution-Data-Server.
111  *
112  * The returned string is owned by libedataserver and must not be
113  * modified or freed.
114  *
115  * Returns: base directory for user-specific data
116  *
117  * Since: 2.32
118  **/
119 const gchar *
e_get_user_data_dir(void)120 e_get_user_data_dir (void)
121 {
122 	static gchar *dirname = NULL;
123 
124 	if (G_UNLIKELY (dirname == NULL)) {
125 		const gchar *data_dir = g_get_user_data_dir ();
126 		dirname = g_build_filename (data_dir, "evolution", NULL);
127 		g_mkdir_with_parents (dirname, 0700);
128 	}
129 
130 	return dirname;
131 }
132 
133 /**
134  * e_util_strv_equal:
135  * @v1: (array zero-terminated=1) (element-type utf8): a %NULL-terminated string array, or %NULL
136  * @v2: (array zero-terminated=1) (element-type utf8): another %NULL-terminated string array, or %NULL
137  *
138  * Compares @v1 and @v2 for equality, handling %NULL gracefully.
139  *
140  * The arguments types are generic for compatibility with #GEqualFunc.
141  *
142  * Returns: whether @v1 and @v2 are identical
143  *
144  * Since: 3.12
145  **/
146 gboolean
e_util_strv_equal(gconstpointer v1,gconstpointer v2)147 e_util_strv_equal (gconstpointer v1,
148                    gconstpointer v2)
149 {
150 	gchar **strv1 = (gchar **) v1;
151 	gchar **strv2 = (gchar **) v2;
152 	guint length1, length2, ii;
153 
154 	if (strv1 == strv2)
155 		return TRUE;
156 
157 	if (strv1 == NULL || strv2 == NULL)
158 		return FALSE;
159 
160 	length1 = g_strv_length (strv1);
161 	length2 = g_strv_length (strv2);
162 
163 	if (length1 != length2)
164 		return FALSE;
165 
166 	for (ii = 0; ii < length1; ii++) {
167 		if (!g_str_equal (strv1[ii], strv2[ii]))
168 			return FALSE;
169 	}
170 
171 	return TRUE;
172 }
173 
174 /**
175  * e_util_strdup_strip:
176  * @string: (nullable): a string value, or %NULL
177  *
178  * Duplicates @string and strips off any leading or trailing whitespace.
179  * The resulting string is returned unless it is empty or %NULL, in which
180  * case the function returns %NULL.
181  *
182  * Free the returned string with g_free().
183  *
184  * Returns: (nullable): a newly-allocated, stripped copy of @string, or %NULL
185  *
186  * Since: 3.6
187  **/
188 gchar *
e_util_strdup_strip(const gchar * string)189 e_util_strdup_strip (const gchar *string)
190 {
191 	gchar *duplicate;
192 
193 	duplicate = g_strdup (string);
194 	if (duplicate != NULL) {
195 		g_strstrip (duplicate);
196 		if (*duplicate == '\0') {
197 			g_free (duplicate);
198 			duplicate = NULL;
199 		}
200 	}
201 
202 	return duplicate;
203 }
204 
205 /**
206  * e_util_strcmp0:
207  * @str1: (nullable): a C string on %NULL
208  * @str2: (nullable): another C string or %NULL
209  *
210  * Compares @str1 and @str2 like g_strcmp0(), except it handles %NULL and
211  * empty strings as equal.
212  *
213  * Returns: an integer less than 0 when @str1 is before @str2; 0 when
214  *    the strings are equal and an integer greated than 0 when @str1 is after @str2.
215  *
216  * Since: 3.32
217  **/
218 gint
e_util_strcmp0(const gchar * str1,const gchar * str2)219 e_util_strcmp0 (const gchar *str1,
220 		const gchar *str2)
221 {
222 	if (str1 && !*str1)
223 		str1 = NULL;
224 
225 	if (str2 && !*str2)
226 		str2 = NULL;
227 
228 	return g_strcmp0 (str1, str2);
229 }
230 
231 /**
232  * e_util_strstrcase:
233  * @haystack: The string to search in.
234  * @needle: The string to search for.
235  *
236  * Find the first instance of @needle in @haystack, ignoring case for
237  * bytes that are ASCII characters.
238  *
239  * Returns: (nullable): A pointer to the start of @needle in @haystack, or NULL if
240  *          @needle is not found.
241  **/
242 gchar *
e_util_strstrcase(const gchar * haystack,const gchar * needle)243 e_util_strstrcase (const gchar *haystack,
244                    const gchar *needle)
245 {
246 	/* find the needle in the haystack neglecting case */
247 	const gchar *ptr;
248 	guint len;
249 
250 	g_return_val_if_fail (haystack != NULL, NULL);
251 	g_return_val_if_fail (needle != NULL, NULL);
252 
253 	len = strlen (needle);
254 	if (len > strlen (haystack))
255 		return NULL;
256 
257 	if (len == 0)
258 		return (gchar *) haystack;
259 
260 	for (ptr = haystack; *(ptr + len - 1) != '\0'; ptr++)
261 		if (!g_ascii_strncasecmp (ptr, needle, len))
262 			return (gchar *) ptr;
263 
264 	return NULL;
265 }
266 
267 /**
268  * e_util_unicode_get_utf8:
269  * @text: The string to take the UTF-8 character from.
270  * @out: The location to store the UTF-8 character in.
271  *
272  * Get a UTF-8 character from the beginning of @text.
273  *
274  * Returns: (nullable): A pointer to the next character in @text after @out.
275  **/
276 gchar *
e_util_unicode_get_utf8(const gchar * text,gunichar * out)277 e_util_unicode_get_utf8 (const gchar *text,
278                          gunichar *out)
279 {
280 	g_return_val_if_fail (text != NULL, NULL);
281 	g_return_val_if_fail (out != NULL, NULL);
282 
283 	*out = g_utf8_get_char (text);
284 	return (*out == (gunichar) -1) ? NULL : g_utf8_next_char (text);
285 }
286 
287 /**
288  * e_util_utf8_strstrcase:
289  * @haystack: (nullable): The string to search in.
290  * @needle: (nullable): The string to search for.
291  *
292  * Find the first instance of @needle in @haystack, ignoring case. (No
293  * proper case folding or decomposing is done.) Both @needle and
294  * @haystack are UTF-8 strings.
295  *
296  * Returns: (nullable): A pointer to the first instance of @needle in @haystack, or
297  *          %NULL if no match is found, or if either of the strings are
298  *          not legal UTF-8 strings.
299  **/
300 const gchar *
e_util_utf8_strstrcase(const gchar * haystack,const gchar * needle)301 e_util_utf8_strstrcase (const gchar *haystack,
302                         const gchar *needle)
303 {
304 	gunichar *nuni, unival;
305 	gint nlen;
306 	const gchar *o, *p;
307 
308 	if (haystack == NULL)
309 		return NULL;
310 
311 	if (needle == NULL)
312 		return NULL;
313 
314 	if (strlen (needle) == 0)
315 		return haystack;
316 
317 	if (strlen (haystack) == 0)
318 		return NULL;
319 
320 	nuni = g_alloca (sizeof (gunichar) * strlen (needle));
321 
322 	nlen = 0;
323 	for (p = e_util_unicode_get_utf8 (needle, &unival);
324 	     p && unival;
325 	     p = e_util_unicode_get_utf8 (p, &unival)) {
326 		nuni[nlen++] = g_unichar_tolower (unival);
327 	}
328 	/* NULL means there was illegal utf-8 sequence */
329 	if (!p || !nlen)
330 		return NULL;
331 
332 	o = haystack;
333 	for (p = e_util_unicode_get_utf8 (o, &unival);
334 	     p && unival;
335 	     p = e_util_unicode_get_utf8 (p, &unival)) {
336 		gunichar sc;
337 		sc = g_unichar_tolower (unival);
338 		/* We have valid stripped gchar */
339 		if (sc == nuni[0]) {
340 			const gchar *q = p;
341 			gint npos = 1;
342 			while (npos < nlen) {
343 				q = e_util_unicode_get_utf8 (q, &unival);
344 				if (!q || !unival) return NULL;
345 				sc = g_unichar_tolower (unival);
346 				if (sc != nuni[npos]) break;
347 				npos++;
348 			}
349 			if (npos == nlen) {
350 				return o;
351 			}
352 		}
353 		o = p;
354 	}
355 
356 	return NULL;
357 }
358 
359 static gunichar
stripped_char(gunichar ch)360 stripped_char (gunichar ch)
361 {
362 	gunichar decomp[4];
363 	gunichar retval;
364 	GUnicodeType utype;
365 	gsize dlen;
366 
367 	utype = g_unichar_type (ch);
368 
369 	switch (utype) {
370 	case G_UNICODE_CONTROL:
371 	case G_UNICODE_FORMAT:
372 	case G_UNICODE_UNASSIGNED:
373 	case G_UNICODE_SPACING_MARK:
374 		/* Ignore those */
375 		return 0;
376 	default:
377 		/* Convert to lowercase */
378 		ch = g_unichar_tolower (ch);
379 		/* falls through */
380 	case G_UNICODE_LOWERCASE_LETTER:
381 		if ((dlen = g_unichar_fully_decompose (ch, FALSE, decomp, 4))) {
382 			retval = decomp[0];
383 			return retval;
384 		}
385 		break;
386 	}
387 
388 	return 0;
389 }
390 
391 /**
392  * e_util_utf8_strstrcasedecomp:
393  * @haystack: The string to search in.
394  * @needle: The string to search for.
395  *
396  * Find the first instance of @needle in @haystack, where both @needle
397  * and @haystack are UTF-8 strings. Both strings are stripped and
398  * decomposed for comparison, and case is ignored.
399  *
400  * Returns: A pointer to the first instance of @needle in @haystack, or
401  *          %NULL if either of the strings are not legal UTF-8 strings.
402  **/
403 const gchar *
e_util_utf8_strstrcasedecomp(const gchar * haystack,const gchar * needle)404 e_util_utf8_strstrcasedecomp (const gchar *haystack,
405                               const gchar *needle)
406 {
407 	gunichar *nuni;
408 	gunichar unival;
409 	gint nlen;
410 	const gchar *o, *p;
411 
412 	if (haystack == NULL)
413 		return NULL;
414 
415 	if (needle == NULL)
416 		return NULL;
417 
418 	if (!*needle)
419 		return haystack;
420 
421 	if (!*haystack)
422 		return NULL;
423 
424 	nuni = g_alloca (sizeof (gunichar) * strlen (needle));
425 
426 	nlen = 0;
427 	for (p = e_util_unicode_get_utf8 (needle, &unival);
428 	     p && unival;
429 	     p = e_util_unicode_get_utf8 (p, &unival)) {
430 		gunichar sc;
431 		sc = stripped_char (unival);
432 		if (sc) {
433 		       nuni[nlen++] = sc;
434 		}
435 	}
436 	/* NULL means there was illegal utf-8 sequence */
437 	if (!p) return NULL;
438 	/* If everything is correct, we have decomposed,
439 	 * lowercase, stripped needle */
440 	if (nlen < 1)
441 		return haystack;
442 
443 	o = haystack;
444 	for (p = e_util_unicode_get_utf8 (o, &unival);
445 	     p && unival;
446 	     p = e_util_unicode_get_utf8 (p, &unival)) {
447 		gunichar sc;
448 		sc = stripped_char (unival);
449 		if (sc) {
450 			/* We have valid stripped gchar */
451 			if (sc == nuni[0]) {
452 				const gchar *q = p;
453 				gint npos = 1;
454 				while (npos < nlen) {
455 					q = e_util_unicode_get_utf8 (q, &unival);
456 					if (!q || !unival) return NULL;
457 					sc = stripped_char (unival);
458 					if ((!sc) || (sc != nuni[npos])) break;
459 					npos++;
460 				}
461 				if (npos == nlen) {
462 					return o;
463 				}
464 			}
465 		}
466 		o = p;
467 	}
468 
469 	return NULL;
470 }
471 
472 /**
473  * e_util_utf8_strcasecmp:
474  * @s1: a UTF-8 string
475  * @s2: another UTF-8 string
476  *
477  * Compares two UTF-8 strings using approximate case-insensitive ordering.
478  *
479  * Returns: < 0 if @s1 compares before @s2, 0 if they compare equal,
480  *          > 0 if @s1 compares after @s2
481  **/
482 gint
e_util_utf8_strcasecmp(const gchar * s1,const gchar * s2)483 e_util_utf8_strcasecmp (const gchar *s1,
484                         const gchar *s2)
485 {
486 	gchar *folded_s1, *folded_s2;
487 	gint retval;
488 
489 	g_return_val_if_fail (s1 != NULL && s2 != NULL, -1);
490 
491 	if (strcmp (s1, s2) == 0)
492 		return 0;
493 
494 	folded_s1 = g_utf8_casefold (s1, -1);
495 	folded_s2 = g_utf8_casefold (s2, -1);
496 
497 	retval = g_utf8_collate (folded_s1, folded_s2);
498 
499 	g_free (folded_s2);
500 	g_free (folded_s1);
501 
502 	return retval;
503 }
504 
505 /**
506  * e_util_utf8_remove_accents:
507  * @str: a UTF-8 string, or %NULL
508  *
509  * Returns a newly-allocated copy of @str with accents removed.
510  *
511  * Returns: a newly-allocated string
512  *
513  * Since: 2.28
514  **/
515 gchar *
e_util_utf8_remove_accents(const gchar * str)516 e_util_utf8_remove_accents (const gchar *str)
517 {
518 	gchar *res;
519 	gint i, j;
520 
521 	if (str == NULL)
522 		return NULL;
523 
524 	res = g_utf8_normalize (str, -1, G_NORMALIZE_NFD);
525 	if (!res)
526 		return g_strdup (str);
527 
528 	for (i = 0, j = 0; res[i]; i++) {
529 		if ((guchar) res[i] != 0xCC || res[i + 1] == 0) {
530 			res[j] = res[i];
531 			j++;
532 		} else {
533 			i++;
534 		}
535 	}
536 
537 	res[j] = 0;
538 
539 	return res;
540 }
541 
542 /**
543  * e_util_utf8_decompose:
544  * @text: a UTF-8 string
545  *
546  * Converts the @text into a decomposed variant and strips it, which
547  * allows also cheap case insensitive comparision afterwards. This
548  * produces an output as being used in e_util_utf8_strstrcasedecomp().
549  *
550  * Returns: (transfer full): A newly allocated string, a decomposed
551  *    variant of the @text. Free with g_free(), when no longer needed.
552  *
553  * Since: 3.26
554  **/
555 gchar *
e_util_utf8_decompose(const gchar * text)556 e_util_utf8_decompose (const gchar *text)
557 {
558 	gunichar unival;
559 	const gchar *p;
560 	gchar utf8[12];
561 	GString *decomp;
562 
563 	if (!text)
564 		return NULL;
565 
566 	decomp = g_string_sized_new (strlen (text) + 1);
567 
568 	for (p = e_util_unicode_get_utf8 (text, &unival);
569 	     p && unival;
570 	     p = e_util_unicode_get_utf8 (p, &unival)) {
571 		gunichar sc;
572 		sc = stripped_char (unival);
573 		if (sc) {
574 			gint ulen = g_unichar_to_utf8 (sc, utf8);
575 			g_string_append_len (decomp, utf8, ulen);
576 		}
577 	}
578 
579 	/* NULL means there was illegal utf-8 sequence */
580 	if (!p || !decomp->len) {
581 		g_string_free (decomp, TRUE);
582 		return NULL;
583 	}
584 
585 	return g_string_free (decomp, FALSE);
586 }
587 
588 /**
589  * e_util_utf8_make_valid:
590  * @str: a UTF-8 string
591  *
592  * Returns a newly-allocated copy of @str, with invalid characters
593  * replaced by Unicode replacement characters (U+FFFD).
594  * For %NULL @str returns newly allocated empty string ("").
595  *
596  * Returns: a newly-allocated string
597  *
598  * Since: 3.0
599  **/
600 gchar *
e_util_utf8_make_valid(const gchar * str)601 e_util_utf8_make_valid (const gchar *str)
602 {
603 	if (!str)
604 		return g_strdup ("");
605 
606 	return e_util_utf8_data_make_valid (str, strlen (str));
607 }
608 
609 /**
610  * e_util_utf8_data_make_valid:
611  * @data: UTF-8 binary data
612  * @data_bytes: length of the binary data
613  *
614  * Returns a newly-allocated NULL-terminated string with invalid characters
615  * replaced by Unicode replacement characters (U+FFFD).
616  * For %NULL @data returns newly allocated empty string ("").
617  *
618  * Returns: a newly-allocated string
619  *
620  * Since: 3.6
621  */
622 gchar *
e_util_utf8_data_make_valid(const gchar * data,gsize data_bytes)623 e_util_utf8_data_make_valid (const gchar *data,
624                              gsize data_bytes)
625 {
626 	/* almost identical copy of glib's _g_utf8_make_valid() */
627 	GString *string;
628 	const gchar *remainder, *invalid;
629 	gint remaining_bytes, valid_bytes;
630 
631 	if (!data)
632 		return g_strdup ("");
633 
634 	string = NULL;
635 	remainder = (gchar *) data,
636 	remaining_bytes = data_bytes;
637 
638 	while (remaining_bytes != 0) {
639 		if (g_utf8_validate (remainder, remaining_bytes, &invalid))
640 			break;
641 		valid_bytes = invalid - remainder;
642 
643 		if (string == NULL)
644 			string = g_string_sized_new (remaining_bytes);
645 
646 		g_string_append_len (string, remainder, valid_bytes);
647 		/* append U+FFFD REPLACEMENT CHARACTER */
648 		g_string_append (string, "\357\277\275");
649 
650 		remaining_bytes -= valid_bytes + 1;
651 		remainder = invalid + 1;
652 	}
653 
654 	if (string == NULL)
655 		return g_strndup ((gchar *) data, data_bytes);
656 
657 	if (remaining_bytes > 0)
658 		g_string_append_len (string, remainder, remaining_bytes);
659 
660 	g_warn_if_fail (g_utf8_validate (string->str, -1, NULL));
661 
662 	return g_string_free (string, FALSE);
663 }
664 
665 /**
666  * e_util_utf8_normalize:
667  * @str: (nullable): a UTF-8 string
668  *
669  * Normalizes @str by making it all lower case and removing any accents from it.
670  *
671  * Returns: (nullable): The normalized version of @str, or %NULL if @str was not valid UTF-8
672  *
673  * Since: 3.8
674  */
675 gchar *
e_util_utf8_normalize(const gchar * str)676 e_util_utf8_normalize (const gchar *str)
677 {
678 	gchar *valid = NULL;
679 	gchar *normal, *casefolded = NULL;
680 
681 	if (str == NULL)
682 		return NULL;
683 
684 	if (!g_utf8_validate (str, -1, NULL)) {
685 		valid = e_util_utf8_make_valid (str);
686 		str = valid;
687 	}
688 
689 	normal = e_util_utf8_remove_accents (str);
690 	if (normal)
691 		casefolded = g_utf8_casefold (normal, -1);
692 
693 	g_free (valid);
694 	g_free (normal);
695 
696 	return casefolded;
697 }
698 
699 /**
700  * e_util_ensure_gdbus_string:
701  * @str: a possibly invalid UTF-8 string, or %NULL
702  * @gdbus_str: return location for the corrected string
703  *
704  * If @str is a valid UTF-8 string, the function returns @str and does
705  * not set @gdbus_str.
706  *
707  * If @str is an invalid UTF-8 string, the function calls
708  * e_util_utf8_make_valid() and points @gdbus_str to the newly-allocated,
709  * valid UTF-8 string, and also returns it.  The caller should free the
710  * string pointed to by @gdbus_str with g_free().
711  *
712  * If @str is %NULL, the function returns an empty string and does not
713  * set @gdbus_str.
714  *
715  * Admittedly, the function semantics are a little awkward.  The example
716  * below illustrates the easiest way to cope with the @gdbus_str argument:
717  *
718  * |[
719  *     const gchar *trusted_utf8;
720  *     gchar *allocated = NULL;
721  *
722  *     trusted_utf8 = e_util_ensure_gdbus_string (untrusted_utf8, &allocated);
723  *
724  *     Do stuff with trusted_utf8, then clear it.
725  *
726  *     trusted_utf8 = NULL;
727  *
728  *     g_free (allocated);
729  *     allocated = NULL;
730  * ]|
731  *
732  * Returns: a valid UTF-8 string
733  *
734  * Since: 3.0
735  **/
736 const gchar *
e_util_ensure_gdbus_string(const gchar * str,gchar ** gdbus_str)737 e_util_ensure_gdbus_string (const gchar *str,
738                             gchar **gdbus_str)
739 {
740 	g_return_val_if_fail (gdbus_str != NULL, NULL);
741 
742 	*gdbus_str = NULL;
743 
744 	if (!str || !*str)
745 		return "";
746 
747 	if (g_utf8_validate (str, -1, NULL))
748 		return str;
749 
750 	*gdbus_str = e_util_utf8_make_valid (str);
751 
752 	return *gdbus_str;
753 }
754 
755 /**
756  * e_strftime:
757  * @string: The string array to store the result in.
758  * @max: The size of array @s.
759  * @fmt: The formatting to use on @tm.
760  * @tm: The time value to format.
761  *
762  * This function is a wrapper around the strftime (3) function, which
763  * converts the &percnt;l and &percnt;k (12h and 24h) format variables
764  * if necessary.
765  *
766  * Returns: The number of characters placed in @s.
767  **/
768 gsize
e_strftime(gchar * string,gsize max,const gchar * fmt,const struct tm * tm)769 e_strftime (gchar *string,
770             gsize max,
771             const gchar *fmt,
772             const struct tm *tm)
773 {
774 #ifndef HAVE_LKSTRFTIME
775 	gchar *c, *ffmt, *ff;
776 #endif
777 	gsize ret;
778 
779 	g_return_val_if_fail (string != NULL, 0);
780 	g_return_val_if_fail (fmt != NULL, 0);
781 	g_return_val_if_fail (tm != NULL, 0);
782 
783 #ifdef HAVE_LKSTRFTIME
784 	ret = strftime (string, max, fmt, tm);
785 #else
786 	ffmt = g_strdup (fmt);
787 	ff = ffmt;
788 	while ((c = strstr (ff, "%l")) != NULL) {
789 		c[1] = 'I';
790 		ff = c;
791 	}
792 
793 	ff = ffmt;
794 	while ((c = strstr (ff, "%k")) != NULL) {
795 		c[1] = 'H';
796 		ff = c;
797 	}
798 
799 #ifdef G_OS_WIN32
800 	/* The Microsoft strftime () doesn't have %e either */
801 	ff = ffmt;
802 	while ((c = strstr (ff, "%e")) != NULL) {
803 		c[1] = 'd';
804 		ff = c;
805 	}
806 #endif
807 
808 	ret = strftime (string, max, ffmt, tm);
809 	g_free (ffmt);
810 #endif
811 
812 	if (ret == 0 && max > 0)
813 		string[0] = '\0';
814 
815 	return ret;
816 }
817 
818 /**
819  * e_utf8_strftime:
820  * @string: The string array to store the result in.
821  * @max: The size of array @s.
822  * @fmt: The formatting to use on @tm.
823  * @tm: The time value to format.
824  *
825  * The UTF-8 equivalent of e_strftime ().
826  *
827  * Returns: The number of characters placed in @s.
828  **/
829 gsize
e_utf8_strftime(gchar * string,gsize max,const gchar * fmt,const struct tm * tm)830 e_utf8_strftime (gchar *string,
831                  gsize max,
832                  const gchar *fmt,
833                  const struct tm *tm)
834 {
835 	gsize sz, ret;
836 	gchar *locale_fmt, *buf;
837 
838 	g_return_val_if_fail (string != NULL, 0);
839 	g_return_val_if_fail (fmt != NULL, 0);
840 	g_return_val_if_fail (tm != NULL, 0);
841 
842 	locale_fmt = g_locale_from_utf8 (fmt, -1, NULL, &sz, NULL);
843 	if (!locale_fmt)
844 		return 0;
845 
846 	ret = e_strftime (string, max, locale_fmt, tm);
847 	if (!ret) {
848 		g_free (locale_fmt);
849 		return 0;
850 	}
851 
852 	buf = g_locale_to_utf8 (string, ret, NULL, &sz, NULL);
853 	if (!buf) {
854 		g_free (locale_fmt);
855 		return 0;
856 	}
857 
858 	if (sz >= max) {
859 		gchar *tmp = buf + max - 1;
860 		tmp = g_utf8_find_prev_char (buf, tmp);
861 		if (tmp)
862 			sz = tmp - buf;
863 		else
864 			sz = 0;
865 	}
866 
867 	memcpy (string, buf, sz);
868 	string[sz] = '\0';
869 
870 	g_free (locale_fmt);
871 	g_free (buf);
872 
873 	return sz;
874 }
875 
876 /**
877  * e_util_gthread_id:
878  * @thread: A #GThread pointer
879  *
880  * Returns a 64-bit integer hopefully uniquely identifying the
881  * thread. To be used in debugging output and logging only.
882  * The returned value is just a cast of a pointer to the 64-bit integer.
883  *
884  * There is no guarantee that calling e_util_gthread_id () on one
885  * thread first and later after that thread has dies on another won't
886  * return the same integer.
887  *
888  * On Linux and Win32, known to really return a unique id for each
889  * thread existing at a certain time. No guarantee that ids won't be
890  * reused after a thread has terminated, though.
891  *
892  * Returns: A 64-bit integer.
893  *
894  * Since: 2.32
895  */
896 guint64
e_util_gthread_id(GThread * thread)897 e_util_gthread_id (GThread *thread)
898 {
899 #if GLIB_SIZEOF_VOID_P == 8
900 	/* 64-bit Windows */
901 	return (guint64) thread;
902 #else
903 	return (gint) thread;
904 #endif
905 }
906 
907 /* This only makes a filename safe for usage as a filename.
908  * It still may have shell meta-characters in it. */
909 
910 /* This code is rather misguided and mostly pointless, but can't be
911  * changed because of backward compatibility, I guess.
912  *
913  * It replaces some perfectly safe characters like '%' with an
914  * underscore. (Recall that on Unix, the only bytes not allowed in a
915  * file name component are '\0' and '/'.) On the other hand, the UTF-8
916  * for a printable non-ASCII Unicode character (that thus consists of
917  * several very nonprintable non-ASCII bytes) is let through as
918  * such. But those bytes are of course also allowed in filenames, so
919  * it doesn't matter as such...
920  */
921 void
e_filename_make_safe(gchar * string)922 e_filename_make_safe (gchar *string)
923 {
924 	gchar *p, *ts;
925 	gunichar c;
926 #ifdef G_OS_WIN32
927 	const gchar *unsafe_chars = " /'\"`&();|<>$%{}!\\:*?#";
928 #else
929 	const gchar *unsafe_chars = " /'\"`&();|<>$%{}!#";
930 #endif
931 
932 	g_return_if_fail (string != NULL);
933 
934 	p = string;
935 
936 	while (p && *p) {
937 		c = g_utf8_get_char (p);
938 		ts = p;
939 		p = g_utf8_next_char (p);
940 		/* I wonder what this code is supposed to actually
941 		 * achieve, and whether it does that as currently
942 		 * written?
943 		 */
944 		if (!g_unichar_isprint (c) ||
945 			(c < 0xff && strchr (unsafe_chars, c & 0xff))) {
946 			while (ts < p)
947 				*ts++ = '_';
948 		}
949 	}
950 }
951 
952 /**
953  * e_filename_mkdir_encoded:
954  * @basepath: base path of a file name; this is left unchanged
955  * @fileprefix: prefix for the filename; this is encoded
956  * @filename: file name to use; this is encoded; can be %NULL
957  * @fileindex: used when @filename is NULL, then the filename
958  *        is generated as "file" + fileindex
959  *
960  * Creates a local path constructed from @basepath / @fileprefix + "-" + @filename,
961  * and makes sure the path @basepath exists. If creation of
962  * the path fails, then NULL is returned.
963  *
964  * Returns: Full local path like g_build_filename() except that @fileprefix
965  * and @filename are encoded to create a proper file elements for
966  * a file system. Free returned pointer with g_free().
967  *
968  * Since: 3.4
969  **/
970 gchar *
e_filename_mkdir_encoded(const gchar * basepath,const gchar * fileprefix,const gchar * filename,gint fileindex)971 e_filename_mkdir_encoded (const gchar *basepath,
972                           const gchar *fileprefix,
973                           const gchar *filename,
974                           gint fileindex)
975 {
976 	gchar *elem1, *elem2, *res, *fn;
977 
978 	g_return_val_if_fail (basepath != NULL, NULL);
979 	g_return_val_if_fail (*basepath != 0, NULL);
980 	g_return_val_if_fail (fileprefix != NULL, NULL);
981 	g_return_val_if_fail (*fileprefix != 0, NULL);
982 	g_return_val_if_fail (!filename || *filename, NULL);
983 
984 	if (g_mkdir_with_parents (basepath, 0700) < 0)
985 		return NULL;
986 
987 	elem1 = g_strdup (fileprefix);
988 	if (filename)
989 		elem2 = g_strdup (filename);
990 	else
991 		elem2 = g_strdup_printf ("file%d", fileindex);
992 
993 	e_filename_make_safe (elem1);
994 	e_filename_make_safe (elem2);
995 
996 	fn = g_strconcat (elem1, "-", elem2, NULL);
997 
998 	res = g_build_filename (basepath, fn, NULL);
999 
1000 	g_free (fn);
1001 	g_free (elem1);
1002 	g_free (elem2);
1003 
1004 	return res;
1005 }
1006 
1007 /**
1008  * e_util_slist_to_strv:
1009  * @strings: (element-type utf8): a #GSList of strings (const gchar *)
1010  *
1011  * Convert list of strings into NULL-terminates array of strings.
1012  *
1013  * Returns: (transfer full): Newly allocated %NULL-terminated array of strings.
1014  * Returned pointer should be freed with g_strfreev().
1015  *
1016  * Note: Pair function for this is e_util_strv_to_slist().
1017  *
1018  * Since: 3.4
1019  **/
1020 gchar **
e_util_slist_to_strv(const GSList * strings)1021 e_util_slist_to_strv (const GSList *strings)
1022 {
1023 	const GSList *iter;
1024 	GPtrArray *array;
1025 
1026 	array = g_ptr_array_sized_new (g_slist_length ((GSList *) strings) + 1);
1027 
1028 	for (iter = strings; iter; iter = iter->next) {
1029 		const gchar *str = iter->data;
1030 
1031 		if (str)
1032 			g_ptr_array_add (array, g_strdup (str));
1033 	}
1034 
1035 	/* NULL-terminated */
1036 	g_ptr_array_add (array, NULL);
1037 
1038 	return (gchar **) g_ptr_array_free (array, FALSE);
1039 }
1040 
1041 /**
1042  * e_util_strv_to_slist:
1043  * @strv: a NULL-terminated array of strings (const gchar *)
1044  *
1045  * Convert NULL-terminated array of strings to a list of strings.
1046  *
1047  * Returns: (transfer full) (element-type utf8): Newly allocated #GSList of
1048  * newly allocated strings. The returned pointer should be freed with
1049  * e_util_free_string_slist().
1050  *
1051  * Note: Pair function for this is e_util_slist_to_strv().
1052  *
1053  * Since: 3.4
1054  **/
1055 GSList *
e_util_strv_to_slist(const gchar * const * strv)1056 e_util_strv_to_slist (const gchar * const *strv)
1057 {
1058 	GSList *slist = NULL;
1059 	gint ii;
1060 
1061 	if (!strv)
1062 		return NULL;
1063 
1064 	for (ii = 0; strv[ii]; ii++) {
1065 		slist = g_slist_prepend (slist, g_strdup (strv[ii]));
1066 	}
1067 
1068 	return g_slist_reverse (slist);
1069 }
1070 
1071 /**
1072  * e_util_copy_string_slist:
1073  * @copy_to: (element-type utf8) (nullable) (transfer full): Where to copy; can be %NULL
1074  * @strings: (element-type utf8): #GSList of strings to be copied
1075  *
1076  * Copies #GSList of strings at the end of @copy_to.
1077  *
1078  * Returns: (transfer full) (element-type utf8): New head of @copy_to.
1079  * Returned pointer can be freed with e_util_free_string_slist().
1080  *
1081  * Since: 3.4
1082  *
1083  * Deprecated: 3.8: Use g_slist_copy_deep() instead, and optionally
1084  *                  g_slist_concat() to concatenate the copied list
1085  *                  to another #GSList.
1086  **/
1087 GSList *
e_util_copy_string_slist(GSList * copy_to,const GSList * strings)1088 e_util_copy_string_slist (GSList *copy_to,
1089                           const GSList *strings)
1090 {
1091 	GSList *copied_list;
1092 
1093 	copied_list = g_slist_copy_deep (
1094 		(GSList *) strings, (GCopyFunc) g_strdup, NULL);
1095 
1096 	return g_slist_concat (copy_to, copied_list);
1097 }
1098 
1099 /**
1100  * e_util_copy_object_slist:
1101  * @copy_to: (element-type GObject) (nullable) (transfer full): Where to copy; can be %NULL
1102  * @objects: (element-type GObject): #GSList of #GObject<!-- -->s to be copied
1103  *
1104  * Copies #GSList of #GObject<!-- -->s at the end of @copy_to.
1105  *
1106  * Returns: (transfer full) (element-type GObject): New head of @copy_to.
1107  * Returned pointer can be freed with e_util_free_object_slist().
1108  *
1109  * Since: 3.4
1110  *
1111  * Deprecated: 3.8: Use g_slist_copy_deep() instead, and optionally
1112  *                  g_slist_concat() to concatenate the copied list
1113  *                  to another #GSList.
1114  **/
1115 GSList *
e_util_copy_object_slist(GSList * copy_to,const GSList * objects)1116 e_util_copy_object_slist (GSList *copy_to,
1117                           const GSList *objects)
1118 {
1119 	GSList *copied_list;
1120 
1121 	copied_list = g_slist_copy_deep (
1122 		(GSList *) objects, (GCopyFunc) g_object_ref, NULL);
1123 
1124 	return g_slist_concat (copy_to, copied_list);
1125 }
1126 
1127 /**
1128  * e_util_free_string_slist:
1129  * @strings: (element-type utf8): a #GSList of strings (gchar *)
1130  *
1131  * Frees memory previously allocated by e_util_strv_to_slist().
1132  *
1133  * Since: 3.4
1134  *
1135  * Deprecated: 3.8: Use g_slist_free_full() instead.
1136  **/
1137 void
e_util_free_string_slist(GSList * strings)1138 e_util_free_string_slist (GSList *strings)
1139 {
1140 	g_slist_free_full (strings, (GDestroyNotify) g_free);
1141 }
1142 
1143 /**
1144  * e_util_free_object_slist:
1145  * @objects: (element-type GObject): a #GSList of #GObject<!-- -->s
1146  *
1147  * Calls g_object_unref() on each member of @objects and then frees
1148  * also @objects itself.
1149  *
1150  * Since: 3.4
1151  *
1152  * Deprecated: 3.8: Use g_slist_free_full() instead.
1153  **/
1154 void
e_util_free_object_slist(GSList * objects)1155 e_util_free_object_slist (GSList *objects)
1156 {
1157 	g_slist_free_full (objects, (GDestroyNotify) g_object_unref);
1158 }
1159 
1160 /**
1161  * e_util_free_nullable_object_slist:
1162  * @objects: (element-type GObject): a #GSList of nullable #GObject<!-- -->s
1163  *
1164  * Calls g_object_unref() on each member of @objects if non-%NULL and then frees
1165  * also @objects itself.
1166  *
1167  * Since: 3.6
1168  **/
1169 void
e_util_free_nullable_object_slist(GSList * objects)1170 e_util_free_nullable_object_slist (GSList *objects)
1171 {
1172 	const GSList *l;
1173 	for (l = objects; l; l = l->next) {
1174 		if (l->data)
1175 			g_object_unref (l->data);
1176 	}
1177 	g_slist_free (objects);
1178 }
1179 
1180 /**
1181  * e_util_safe_free_string:
1182  * @str: a string to free
1183  *
1184  * Calls g_free() on @string, but before it rewrites its content with zeros.
1185  * This is suitable to free strings with passwords.
1186  *
1187  * Since: 3.16
1188  **/
1189 void
e_util_safe_free_string(gchar * str)1190 e_util_safe_free_string (gchar *str)
1191 {
1192 	if (!str)
1193 		return;
1194 
1195 	if (*str)
1196 		memset (str, 0, sizeof (gchar) * strlen (str));
1197 
1198 	g_free (str);
1199 }
1200 
1201 /**
1202  * e_queue_transfer:
1203  * @src_queue: a source #GQueue
1204  * @dst_queue: a destination #GQueue
1205  *
1206  * Transfers the contents of @src_queue to the tail of @dst_queue.
1207  * When the operation is complete, @src_queue will be empty.
1208  *
1209  * Since: 3.8
1210  **/
1211 void
e_queue_transfer(GQueue * src_queue,GQueue * dst_queue)1212 e_queue_transfer (GQueue *src_queue,
1213                   GQueue *dst_queue)
1214 {
1215 	g_return_if_fail (src_queue != NULL);
1216 	g_return_if_fail (dst_queue != NULL);
1217 
1218 	dst_queue->head = g_list_concat (dst_queue->head, src_queue->head);
1219 	dst_queue->tail = g_list_last (dst_queue->head);
1220 	dst_queue->length += src_queue->length;
1221 
1222 	src_queue->head = NULL;
1223 	src_queue->tail = NULL;
1224 	src_queue->length = 0;
1225 }
1226 
1227 /**
1228  * e_weak_ref_new: (skip)
1229  * @object: (nullable): a #GObject or %NULL
1230  *
1231  * Allocates a new #GWeakRef and calls g_weak_ref_set() with @object.
1232  *
1233  * Free the returned #GWeakRef with e_weak_ref_free().
1234  *
1235  * Returns: (transfer full): a new #GWeakRef
1236  *
1237  * Since: 3.10
1238  **/
1239 GWeakRef *
e_weak_ref_new(gpointer object)1240 e_weak_ref_new (gpointer object)
1241 {
1242 	GWeakRef *weak_ref;
1243 
1244 	weak_ref = g_slice_new0 (GWeakRef);
1245 	g_weak_ref_init (weak_ref, object);
1246 
1247 	return weak_ref;
1248 }
1249 
1250 /**
1251  * e_weak_ref_free: (skip)
1252  * @weak_ref: a #GWeakRef
1253  *
1254  * Frees a #GWeakRef created by e_weak_ref_new().
1255  *
1256  * Since: 3.10
1257  **/
1258 void
e_weak_ref_free(GWeakRef * weak_ref)1259 e_weak_ref_free (GWeakRef *weak_ref)
1260 {
1261 	g_return_if_fail (weak_ref != NULL);
1262 
1263 	g_weak_ref_clear (weak_ref);
1264 	g_slice_free (GWeakRef, weak_ref);
1265 }
1266 
1267 /* Helper for e_file_recursive_delete() */
1268 static void
file_recursive_delete_thread(GSimpleAsyncResult * simple,GObject * object,GCancellable * cancellable)1269 file_recursive_delete_thread (GSimpleAsyncResult *simple,
1270                               GObject *object,
1271                               GCancellable *cancellable)
1272 {
1273 	GError *error = NULL;
1274 
1275 	e_file_recursive_delete_sync (G_FILE (object), cancellable, &error);
1276 
1277 	if (error != NULL)
1278 		g_simple_async_result_take_error (simple, error);
1279 }
1280 
1281 /**
1282  * e_file_recursive_delete_sync:
1283  * @file: a #GFile to delete
1284  * @cancellable: optional #GCancellable object, or %NULL
1285  * @error: return location for a #GError, or %NULL
1286  *
1287  * Deletes @file.  If @file is a directory, its contents are deleted
1288  * recursively before @file itself is deleted.  The recursive delete
1289  * operation will stop on the first error.
1290  *
1291  * If @cancellable is not %NULL, then the operation can be cancelled
1292  * by triggering the cancellable object from another thread.  If the
1293  * operation was cancelled, the error #G_IO_ERROR_CANCELLED will be
1294  * returned.
1295  *
1296  * Returns: %TRUE if the file was deleted, %FALSE otherwise
1297  *
1298  * Since: 3.6
1299  **/
1300 gboolean
e_file_recursive_delete_sync(GFile * file,GCancellable * cancellable,GError ** error)1301 e_file_recursive_delete_sync (GFile *file,
1302                               GCancellable *cancellable,
1303                               GError **error)
1304 {
1305 	GFileEnumerator *file_enumerator;
1306 	GFileInfo *file_info;
1307 	GFileType file_type;
1308 	gboolean success = TRUE;
1309 	GError *local_error = NULL;
1310 
1311 	g_return_val_if_fail (G_IS_FILE (file), FALSE);
1312 
1313 	file_type = g_file_query_file_type (
1314 		file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable);
1315 
1316 	/* If this is not a directory, delete like normal. */
1317 	if (file_type != G_FILE_TYPE_DIRECTORY)
1318 		return g_file_delete (file, cancellable, error);
1319 
1320 	/* Note, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS is critical here
1321 	 * so we only delete files inside the directory being deleted. */
1322 	file_enumerator = g_file_enumerate_children (
1323 		file, G_FILE_ATTRIBUTE_STANDARD_NAME,
1324 		G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
1325 		cancellable, error);
1326 
1327 	if (file_enumerator == NULL)
1328 		return FALSE;
1329 
1330 	file_info = g_file_enumerator_next_file (
1331 		file_enumerator, cancellable, &local_error);
1332 
1333 	while (file_info != NULL) {
1334 		GFile *child;
1335 		const gchar *name;
1336 
1337 		name = g_file_info_get_name (file_info);
1338 
1339 		/* Here's the recursive part. */
1340 		child = g_file_get_child (file, name);
1341 		success = e_file_recursive_delete_sync (
1342 			child, cancellable, error);
1343 		g_object_unref (child);
1344 
1345 		g_object_unref (file_info);
1346 
1347 		if (!success)
1348 			break;
1349 
1350 		file_info = g_file_enumerator_next_file (
1351 			file_enumerator, cancellable, &local_error);
1352 	}
1353 
1354 	if (local_error != NULL) {
1355 		g_propagate_error (error, local_error);
1356 		success = FALSE;
1357 	}
1358 
1359 	g_object_unref (file_enumerator);
1360 
1361 	if (!success)
1362 		return FALSE;
1363 
1364 	/* The directory should be empty now. */
1365 	return g_file_delete (file, cancellable, error);
1366 }
1367 
1368 /**
1369  * e_file_recursive_delete:
1370  * @file: a #GFile to delete
1371  * @io_priority: the I/O priority of the request
1372  * @cancellable: optional #GCancellable object, or %NULL
1373  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1374  * @user_data: data to pass to the callback function
1375  *
1376  * Asynchronously deletes @file.  If @file is a directory, its contents
1377  * are deleted recursively before @file itself is deleted.  The recursive
1378  * delete operation will stop on the first error.
1379  *
1380  * If @cancellable is not %NULL, then the operation can be cancelled
1381  * by triggering the cancellable object before the operation finishes.
1382  *
1383  * When the operation is finished, @callback will be called.  You can then
1384  * call e_file_recursive_delete_finish() to get the result of the operation.
1385  *
1386  * Since: 3.6
1387  **/
1388 void
e_file_recursive_delete(GFile * file,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1389 e_file_recursive_delete (GFile *file,
1390                          gint io_priority,
1391                          GCancellable *cancellable,
1392                          GAsyncReadyCallback callback,
1393                          gpointer user_data)
1394 {
1395 	GSimpleAsyncResult *simple;
1396 
1397 	g_return_if_fail (G_IS_FILE (file));
1398 
1399 	simple = g_simple_async_result_new (
1400 		G_OBJECT (file), callback, user_data,
1401 		e_file_recursive_delete);
1402 
1403 	g_simple_async_result_set_check_cancellable (simple, cancellable);
1404 
1405 	g_simple_async_result_run_in_thread (
1406 		simple, file_recursive_delete_thread,
1407 		io_priority, cancellable);
1408 
1409 	g_object_unref (simple);
1410 }
1411 
1412 /**
1413  * e_file_recursive_delete_finish:
1414  * @file: a #GFile to delete
1415  * @result: a #GAsyncResult
1416  * @error: return location for a #GError, or %NULL
1417  *
1418  * Finishes the operation started with e_file_recursive_delete().
1419  *
1420  * If the operation was cancelled, the error #G_IO_ERROR_CANCELLED will be
1421  * returned.
1422  *
1423  * Returns: %TRUE if the file was deleted, %FALSE otherwise
1424  *
1425  * Since: 3.6
1426  **/
1427 gboolean
e_file_recursive_delete_finish(GFile * file,GAsyncResult * result,GError ** error)1428 e_file_recursive_delete_finish (GFile *file,
1429                                 GAsyncResult *result,
1430                                 GError **error)
1431 {
1432 	GSimpleAsyncResult *simple;
1433 
1434 	g_return_val_if_fail (
1435 		g_simple_async_result_is_valid (
1436 		result, G_OBJECT (file), e_file_recursive_delete), FALSE);
1437 
1438 	simple = G_SIMPLE_ASYNC_RESULT (result);
1439 
1440 	/* Assume success unless a GError is set. */
1441 	return !g_simple_async_result_propagate_error (simple, error);
1442 }
1443 
1444 /**
1445  * e_binding_bind_property:
1446  * @source: (type GObject.Object): the source #GObject
1447  * @source_property: the property on @source to bind
1448  * @target: (type GObject.Object): the target #GObject
1449  * @target_property: the property on @target to bind
1450  * @flags: flags to pass to #GBinding
1451  *
1452  * Thread safe variant of g_object_bind_property(). See its documentation
1453  * for more information on arguments and return value.
1454  *
1455  * Returns: (transfer none):
1456  *
1457  * Since: 3.16
1458  **/
1459 GBinding *
e_binding_bind_property(gpointer source,const gchar * source_property,gpointer target,const gchar * target_property,GBindingFlags flags)1460 e_binding_bind_property (gpointer source,
1461 			 const gchar *source_property,
1462 			 gpointer target,
1463 			 const gchar *target_property,
1464 			 GBindingFlags flags)
1465 {
1466 	return camel_binding_bind_property (source, source_property, target, target_property, flags);
1467 }
1468 
1469 /**
1470  * e_binding_bind_property_full:
1471  * @source: (type GObject.Object): the source #GObject
1472  * @source_property: the property on @source to bind
1473  * @target: (type GObject.Object): the target #GObject
1474  * @target_property: the property on @target to bind
1475  * @flags: flags to pass to #GBinding
1476  * @transform_to: (scope notified) (nullable): the transformation function
1477  *   from the @source to the @target, or %NULL to use the default
1478  * @transform_from: (scope notified) (nullable): the transformation function
1479  *   from the @target to the @source, or %NULL to use the default
1480  * @user_data: custom data to be passed to the transformation functions,
1481  *   or %NULL
1482  * @notify: function to be called when disposing the binding, to free the
1483  *   resources used by the transformation functions
1484  *
1485  * Thread safe variant of g_object_bind_property_full(). See its documentation
1486  * for more information on arguments and return value.
1487  *
1488  * Return value: (transfer none): the #GBinding instance representing the
1489  *   binding between the two #GObject instances. The binding is released
1490  *   whenever the #GBinding reference count reaches zero.
1491  *
1492  * Since: 3.16
1493  **/
1494 GBinding *
e_binding_bind_property_full(gpointer source,const gchar * source_property,gpointer target,const gchar * target_property,GBindingFlags flags,GBindingTransformFunc transform_to,GBindingTransformFunc transform_from,gpointer user_data,GDestroyNotify notify)1495 e_binding_bind_property_full (gpointer source,
1496 			      const gchar *source_property,
1497 			      gpointer target,
1498 			      const gchar *target_property,
1499 			      GBindingFlags flags,
1500 			      GBindingTransformFunc transform_to,
1501 			      GBindingTransformFunc transform_from,
1502 			      gpointer user_data,
1503 			      GDestroyNotify notify)
1504 {
1505 	return camel_binding_bind_property_full (source, source_property, target, target_property, flags,
1506 		transform_to, transform_from, user_data, notify);
1507 }
1508 
1509 /**
1510  * e_binding_bind_property_with_closures: (rename-to e_binding_bind_property_full)
1511  * @source: (type GObject.Object): the source #GObject
1512  * @source_property: the property on @source to bind
1513  * @target: (type GObject.Object): the target #GObject
1514  * @target_property: the property on @target to bind
1515  * @flags: flags to pass to #GBinding
1516  * @transform_to: (nullable): a #GClosure wrapping the transformation function
1517  *   from the @source to the @target, or %NULL to use the default
1518  * @transform_from: (nullable): a #GClosure wrapping the transformation function
1519  *   from the @target to the @source, or %NULL to use the default
1520  *
1521  * Thread safe variant of g_object_bind_property_with_closures(). See its
1522  * documentation for more information on arguments and return value.
1523  *
1524  * Return value: (transfer none): the #GBinding instance representing the
1525  *   binding between the two #GObject instances. The binding is released
1526  *   whenever the #GBinding reference count reaches zero.
1527  *
1528  * Since: 3.16
1529  **/
1530 GBinding *
e_binding_bind_property_with_closures(gpointer source,const gchar * source_property,gpointer target,const gchar * target_property,GBindingFlags flags,GClosure * transform_to,GClosure * transform_from)1531 e_binding_bind_property_with_closures (gpointer source,
1532 				       const gchar *source_property,
1533 				       gpointer target,
1534 				       const gchar *target_property,
1535 				       GBindingFlags flags,
1536 				       GClosure *transform_to,
1537 				       GClosure *transform_from)
1538 {
1539 	return camel_binding_bind_property_with_closures (source, source_property, target, target_property, flags,
1540 		transform_to, transform_from);
1541 }
1542 
1543 /**
1544  * e_binding_transform_enum_value_to_nick:
1545  * @binding: a #GBinding
1546  * @source_value: a #GValue whose type is derived from #G_TYPE_ENUM
1547  * @target_value: a #GValue of type #G_TYPE_STRING
1548  * @not_used: not used
1549  *
1550  * Transforms an enumeration value to its corresponding nickname.
1551  *
1552  * Returns: %TRUE if the enum value has a corresponding nickname
1553  *
1554  * Since: 3.4
1555  **/
1556 gboolean
e_binding_transform_enum_value_to_nick(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer not_used)1557 e_binding_transform_enum_value_to_nick (GBinding *binding,
1558                                         const GValue *source_value,
1559                                         GValue *target_value,
1560                                         gpointer not_used)
1561 {
1562 	GEnumClass *enum_class;
1563 	GEnumValue *enum_value;
1564 	gint value;
1565 	gboolean success = FALSE;
1566 
1567 	g_return_val_if_fail (G_IS_BINDING (binding), FALSE);
1568 
1569 	enum_class = g_type_class_peek (G_VALUE_TYPE (source_value));
1570 	g_return_val_if_fail (G_IS_ENUM_CLASS (enum_class), FALSE);
1571 
1572 	value = g_value_get_enum (source_value);
1573 	enum_value = g_enum_get_value (enum_class, value);
1574 	if (enum_value != NULL) {
1575 		g_value_set_string (target_value, enum_value->value_nick);
1576 		success = TRUE;
1577 	}
1578 
1579 	return success;
1580 }
1581 
1582 /**
1583  * e_binding_transform_enum_nick_to_value:
1584  * @binding: a #GBinding
1585  * @source_value: a #GValue of type #G_TYPE_STRING
1586  * @target_value: a #GValue whose type is derived from #G_TYPE_ENUM
1587  * @not_used: not used
1588  *
1589  * Transforms an enumeration nickname to its corresponding value.
1590  *
1591  * Returns: %TRUE if the enum nickname has a corresponding value
1592  *
1593  * Since: 3.4
1594  **/
1595 gboolean
e_binding_transform_enum_nick_to_value(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer not_used)1596 e_binding_transform_enum_nick_to_value (GBinding *binding,
1597                                         const GValue *source_value,
1598                                         GValue *target_value,
1599                                         gpointer not_used)
1600 {
1601 	GEnumClass *enum_class;
1602 	GEnumValue *enum_value;
1603 	const gchar *string;
1604 	gboolean success = FALSE;
1605 
1606 	g_return_val_if_fail (G_IS_BINDING (binding), FALSE);
1607 
1608 	enum_class = g_type_class_peek (G_VALUE_TYPE (target_value));
1609 	g_return_val_if_fail (G_IS_ENUM_CLASS (enum_class), FALSE);
1610 
1611 	string = g_value_get_string (source_value);
1612 	enum_value = g_enum_get_value_by_nick (enum_class, string);
1613 	if (enum_value != NULL) {
1614 		g_value_set_enum (target_value, enum_value->value);
1615 		success = TRUE;
1616 	}
1617 
1618 	return success;
1619 }
1620 
1621 /**
1622  * e_enum_from_string:
1623  * @enum_type: The enum type
1624  * @string: The string containing the enum value or nick
1625  * @enum_value: A return location to store the result
1626  *
1627  * Fetches the appropriate enumeration value for @string in the given
1628  * enum type @type and stores the result in @enum_value
1629  *
1630  * Returns: %TRUE if the string was a valid name or nick
1631  *        for the given @type, %FALSE if the conversion failed.
1632  *
1633  * Since: 3.8
1634  */
1635 gboolean
e_enum_from_string(GType enum_type,const gchar * string,gint * enum_value)1636 e_enum_from_string (GType enum_type,
1637                     const gchar *string,
1638                     gint *enum_value)
1639 {
1640 	GEnumClass *enum_class;
1641 	GEnumValue *ev;
1642 	gchar *endptr;
1643 	gint value;
1644 	gboolean retval = TRUE;
1645 
1646 	g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), FALSE);
1647 	g_return_val_if_fail (string != NULL, FALSE);
1648 
1649 	value = g_ascii_strtoull (string, &endptr, 0);
1650 	if (endptr != string)
1651 		/* parsed a number */
1652 		*enum_value = value;
1653 	else {
1654 		enum_class = g_type_class_ref (enum_type);
1655 		ev = g_enum_get_value_by_name (enum_class, string);
1656 		if (!ev)
1657 			ev = g_enum_get_value_by_nick (enum_class, string);
1658 
1659 		if (ev)
1660 			*enum_value = ev->value;
1661 		else
1662 			retval = FALSE;
1663 
1664 		g_type_class_unref (enum_class);
1665 	}
1666 
1667 	return retval;
1668 }
1669 
1670 /**
1671  * e_enum_to_string:
1672  * @enum_type: An enum type
1673  * @enum_value: The enum value to convert
1674  *
1675  * Converts an enum value to a string using strings from the GType system.
1676  *
1677  * Returns: the string representing @eval
1678  *
1679  * Since: 3.8
1680  */
1681 const gchar *
e_enum_to_string(GType enum_type,gint enum_value)1682 e_enum_to_string (GType enum_type,
1683                   gint enum_value)
1684 {
1685 	GEnumClass *enum_class;
1686 	const gchar *string = NULL;
1687 	guint i;
1688 
1689 	enum_class = g_type_class_ref (enum_type);
1690 
1691 	g_return_val_if_fail (enum_class != NULL, NULL);
1692 
1693 	for (i = 0; i < enum_class->n_values; i++) {
1694 		if (enum_value == enum_class->values[i].value) {
1695 			string = enum_class->values[i].value_nick;
1696 			break;
1697 		}
1698 	}
1699 
1700 	g_type_class_unref (enum_class);
1701 
1702 	return string;
1703 }
1704 
1705 /**
1706  * EAsyncClosure:
1707  *
1708  * #EAsyncClosure provides a simple way to run an asynchronous function
1709  * synchronously without blocking a running #GMainLoop or using threads.
1710  *
1711  * 1) Create an #EAsyncClosure with e_async_closure_new().
1712  *
1713  * 2) Call the asynchronous function passing e_async_closure_callback() as
1714  *    the #GAsyncReadyCallback argument and the #EAsyncClosure as the data
1715  *    argument.
1716  *
1717  * 3) Call e_async_closure_wait() and collect the #GAsyncResult.
1718  *
1719  * 4) Call the corresponding asynchronous "finish" function, passing the
1720  *    #GAsyncResult returned by e_async_closure_wait().
1721  *
1722  * 5) If needed, repeat steps 2-4 for additional asynchronous functions
1723  *    using the same #EAsyncClosure.
1724  *
1725  * 6) Finally, free the #EAsyncClosure with e_async_closure_free().
1726  *
1727  * Since: 3.6
1728  **/
1729 struct _EAsyncClosure {
1730 	GMainLoop *loop;
1731 	GMainContext *context;
1732 	GAsyncResult *result;
1733 	gboolean finished;
1734 	gboolean pop_thread_default;
1735 	GMutex lock;
1736 };
1737 
1738 /**
1739  * e_async_closure_new: (skip)
1740  *
1741  * Creates a new #EAsyncClosure for use with asynchronous functions.
1742  *
1743  * Returns: a new #EAsyncClosure
1744  *
1745  * Since: 3.6
1746  **/
1747 EAsyncClosure *
e_async_closure_new(void)1748 e_async_closure_new (void)
1749 {
1750 	EAsyncClosure *closure;
1751 	GMainContext *context;
1752 
1753 	context = g_main_context_new ();
1754 	closure = e_async_closure_new_with_context (context);
1755 	g_main_context_unref (context);
1756 
1757 	return closure;
1758 }
1759 
1760 /**
1761  * e_async_closure_new_with_context: (skip)
1762  * @context: (nullable): a #GMainContext to use, or %NULL to use the default context
1763  *
1764  * Creates a new #EAsyncClosure for use with asynchronous functions
1765  * using the @context as the main context.
1766  *
1767  * Returns: a new #EAsyncClosure
1768  *
1769  * Since: 3.40
1770  **/
1771 EAsyncClosure *
e_async_closure_new_with_context(GMainContext * context)1772 e_async_closure_new_with_context (GMainContext *context)
1773 {
1774 	EAsyncClosure *closure;
1775 
1776 	if (!context)
1777 		context = g_main_context_get_thread_default ();
1778 	if (!context)
1779 		context = g_main_context_default ();
1780 
1781 	closure = g_slice_new0 (EAsyncClosure);
1782 	closure->context = g_main_context_ref (context);
1783 	closure->loop = g_main_loop_new (closure->context, FALSE);
1784 	closure->finished = FALSE;
1785 	closure->pop_thread_default = context != g_main_context_get_thread_default () && context != g_main_context_default ();
1786 	g_mutex_init (&closure->lock);
1787 
1788 	if (closure->pop_thread_default)
1789 		g_main_context_push_thread_default (closure->context);
1790 
1791 	return closure;
1792 }
1793 
1794 static gboolean
e_async_closure_unlock_mutex_cb(gpointer user_data)1795 e_async_closure_unlock_mutex_cb (gpointer user_data)
1796 {
1797 	EAsyncClosure *closure = user_data;
1798 
1799 	g_return_val_if_fail (closure != NULL, FALSE);
1800 
1801 	g_mutex_unlock (&closure->lock);
1802 
1803 	return FALSE;
1804 }
1805 
1806 /**
1807  * e_async_closure_wait: (skip)
1808  * @closure: an #EAsyncClosure
1809  *
1810  * Call this function immediately after starting an asynchronous operation.
1811  * The function waits for the asynchronous operation to complete and returns
1812  * its #GAsyncResult to be passed to the operation's "finish" function.
1813  *
1814  * This function can be called repeatedly on the same #EAsyncClosure to
1815  * easily string together multiple asynchronous operations.
1816  *
1817  * Returns: (transfer none): a #GAsyncResult which is owned by the closure
1818  *
1819  * Since: 3.6
1820  **/
1821 GAsyncResult *
e_async_closure_wait(EAsyncClosure * closure)1822 e_async_closure_wait (EAsyncClosure *closure)
1823 {
1824 	g_return_val_if_fail (closure != NULL, NULL);
1825 
1826 	g_mutex_lock (&closure->lock);
1827 	if (closure->finished) {
1828 		g_mutex_unlock (&closure->lock);
1829 	} else {
1830 		GSource *idle_source;
1831 
1832 		/* Unlock the closure->lock in the main loop, to ensure thread safety.
1833 		   It should be processed before anything else, otherwise deadlock happens. */
1834 		idle_source = g_idle_source_new ();
1835 		g_source_set_callback (idle_source, e_async_closure_unlock_mutex_cb, closure, NULL);
1836 		g_source_set_priority (idle_source, G_PRIORITY_HIGH * 2);
1837 		g_source_attach (idle_source, closure->context);
1838 		g_source_unref (idle_source);
1839 
1840 		g_main_loop_run (closure->loop);
1841 	}
1842 
1843 	return closure->result;
1844 }
1845 
1846 /**
1847  * e_async_closure_free: (skip)
1848  * @closure: an #EAsyncClosure
1849  *
1850  * Frees the @closure and the resources it holds.
1851  *
1852  * Since: 3.6
1853  **/
1854 void
e_async_closure_free(EAsyncClosure * closure)1855 e_async_closure_free (EAsyncClosure *closure)
1856 {
1857 	g_return_if_fail (closure != NULL);
1858 
1859 	if (closure->pop_thread_default)
1860 		g_main_context_pop_thread_default (closure->context);
1861 
1862 	g_main_loop_unref (closure->loop);
1863 	g_main_context_unref (closure->context);
1864 
1865 	g_mutex_lock (&closure->lock);
1866 	g_clear_object (&closure->result);
1867 	g_mutex_unlock (&closure->lock);
1868 	g_mutex_clear (&closure->lock);
1869 
1870 	g_slice_free (EAsyncClosure, closure);
1871 }
1872 
1873 /**
1874  * e_async_closure_callback: (skip)
1875  * @object: a #GObject or %NULL, it is not used by the function at all
1876  * @result: a #GAsyncResult
1877  * @closure: an #EAsyncClosure
1878  *
1879  * Pass this function as the #GAsyncReadyCallback argument of an asynchronous
1880  * function, and the #EAsyncClosure as the data argument.
1881  *
1882  * This causes e_async_closure_wait() to terminate and return @result.
1883  *
1884  * Since: 3.6
1885  **/
1886 void
e_async_closure_callback(GObject * object,GAsyncResult * result,gpointer closure)1887 e_async_closure_callback (GObject *object,
1888                           GAsyncResult *result,
1889                           gpointer closure)
1890 {
1891 	EAsyncClosure *real_closure;
1892 
1893 	g_return_if_fail (G_IS_ASYNC_RESULT (result));
1894 	g_return_if_fail (closure != NULL);
1895 
1896 	real_closure = closure;
1897 
1898 	g_mutex_lock (&real_closure->lock);
1899 
1900 	/* Replace any previous result. */
1901 	if (real_closure->result != NULL)
1902 		g_object_unref (real_closure->result);
1903 	real_closure->result = g_object_ref (result);
1904 	real_closure->finished = TRUE;
1905 
1906 	g_mutex_unlock (&real_closure->lock);
1907 
1908 	g_main_loop_quit (real_closure->loop);
1909 }
1910 
1911 #ifdef G_OS_WIN32
1912 
1913 #include <windows.h>
1914 #include <stdio.h>
1915 #include <conio.h>
1916 #include <io.h>
1917 
1918 #ifndef PROCESS_DEP_ENABLE
1919 #define PROCESS_DEP_ENABLE 0x00000001
1920 #endif
1921 #ifndef PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION
1922 #define PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION 0x00000002
1923 #endif
1924 
1925 static const gchar *prefix = NULL;
1926 static const gchar *cp_prefix;
1927 
1928 static const gchar *localedir;
1929 static const gchar *imagesdir;
1930 static const gchar *credentialmoduledir;
1931 static const gchar *uimoduledir;
1932 
1933 static HMODULE hmodule;
1934 G_LOCK_DEFINE_STATIC (mutex);
1935 
1936 /* Silence gcc with a prototype. Yes, this is silly. */
1937 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
1938 		     DWORD     fdwReason,
1939 		     LPVOID    lpvReserved);
1940 
1941 /* Minimal DllMain that just tucks away the DLL's HMODULE */
1942 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)1943 DllMain (HINSTANCE hinstDLL,
1944          DWORD fdwReason,
1945          LPVOID lpvReserved)
1946 {
1947 	switch (fdwReason) {
1948 	case DLL_PROCESS_ATTACH:
1949 		hmodule = hinstDLL;
1950 		break;
1951 	}
1952 	return TRUE;
1953 }
1954 
1955 gchar *
e_util_replace_prefix(const gchar * configure_time_prefix,const gchar * runtime_prefix,const gchar * configure_time_path)1956 e_util_replace_prefix (const gchar *configure_time_prefix,
1957                        const gchar *runtime_prefix,
1958                        const gchar *configure_time_path)
1959 {
1960 	gchar *c_t_prefix_slash;
1961 	gchar *retval;
1962 
1963 	c_t_prefix_slash = g_strconcat (configure_time_prefix, "/", NULL);
1964 
1965 	if (runtime_prefix &&
1966 	    !g_str_has_prefix (configure_time_path, c_t_prefix_slash)) {
1967 		gint ii;
1968 		gchar *path;
1969 
1970 		path = g_strdup (configure_time_path);
1971 
1972 		for (ii = 0; ii < 3; ii++) {
1973 			const gchar *pos;
1974 			gchar *last_slash;
1975 
1976 			last_slash = strrchr (path, '/');
1977 			if (!last_slash)
1978 				break;
1979 
1980 			*last_slash = '\0';
1981 
1982 			pos = strstr (configure_time_prefix, path);
1983 			if (pos && pos[strlen(path)] == '/') {
1984 				g_free (c_t_prefix_slash);
1985 				c_t_prefix_slash = g_strconcat (configure_time_prefix + (pos - configure_time_prefix), "/", NULL);
1986 				break;
1987 			}
1988 		}
1989 
1990 		g_free (path);
1991 	}
1992 
1993 	if (runtime_prefix &&
1994 	    g_str_has_prefix (configure_time_path, c_t_prefix_slash)) {
1995 		retval = g_strconcat (
1996 			runtime_prefix,
1997 			configure_time_path + strlen (c_t_prefix_slash) - 1,
1998 			NULL);
1999 	} else
2000 		retval = g_strdup (configure_time_path);
2001 
2002 	g_free (c_t_prefix_slash);
2003 
2004 	return retval;
2005 }
2006 
2007 static gchar *
replace_prefix(const gchar * runtime_prefix,const gchar * configure_time_path)2008 replace_prefix (const gchar *runtime_prefix,
2009                 const gchar *configure_time_path)
2010 {
2011 	return e_util_replace_prefix (
2012 		E_DATA_SERVER_PREFIX, runtime_prefix, configure_time_path);
2013 }
2014 
2015 static void
setup(void)2016 setup (void)
2017 {
2018 	gchar *full_pfx;
2019 	gchar *cp_pfx;
2020 
2021 	G_LOCK (mutex);
2022 	if (prefix != NULL) {
2023 		G_UNLOCK (mutex);
2024 		return;
2025 	}
2026 
2027 	/* This requires that the libedataserver DLL is installed in $bindir */
2028 	full_pfx = g_win32_get_package_installation_directory_of_module (hmodule);
2029 	cp_pfx = g_win32_locale_filename_from_utf8 (full_pfx);
2030 
2031 	prefix = g_strdup (full_pfx);
2032 	cp_prefix = g_strdup (cp_pfx);
2033 
2034 	g_free (full_pfx);
2035 	g_free (cp_pfx);
2036 
2037 	localedir = replace_prefix (cp_prefix, E_DATA_SERVER_LOCALEDIR);
2038 	imagesdir = replace_prefix (prefix, E_DATA_SERVER_IMAGESDIR);
2039 	credentialmoduledir = replace_prefix (prefix, E_DATA_SERVER_CREDENTIALMODULEDIR);
2040 	uimoduledir = replace_prefix (prefix, E_DATA_SERVER_UIMODULEDIR);
2041 
2042 	G_UNLOCK (mutex);
2043 }
2044 
2045 #include "libedataserver-private.h" /* For prototypes */
2046 
2047 #define GETTER_IMPL(varbl) \
2048 { \
2049 	setup (); \
2050 	return varbl; \
2051 }
2052 
2053 #define PRIVATE_GETTER(varbl) \
2054 const gchar * \
2055 _libedataserver_get_##varbl (void) \
2056 	GETTER_IMPL (varbl)
2057 
2058 #define PUBLIC_GETTER(varbl) \
2059 const gchar * \
2060 e_util_get_##varbl (void) \
2061 	GETTER_IMPL (varbl)
2062 
2063 PRIVATE_GETTER (imagesdir)
2064 PRIVATE_GETTER (credentialmoduledir);
2065 PRIVATE_GETTER (uimoduledir);
2066 
2067 PUBLIC_GETTER (prefix)
PUBLIC_GETTER(cp_prefix)2068 PUBLIC_GETTER (cp_prefix)
2069 PUBLIC_GETTER (localedir)
2070 
2071 /**
2072  * e_util_win32_initialize:
2073  *
2074  * Initializes win32 environment. This might be called in main().
2075  **/
2076 void
2077 e_util_win32_initialize (void)
2078 {
2079 	gchar module_filename[2048 + 1];
2080 	DWORD chars;
2081 
2082 	/* Reduce risks */
2083 	{
2084 		typedef BOOL (WINAPI *t_SetDllDirectoryA) (LPCSTR lpPathName);
2085 		t_SetDllDirectoryA p_SetDllDirectoryA;
2086 
2087 		p_SetDllDirectoryA = GetProcAddress (
2088 			GetModuleHandle ("kernel32.dll"),
2089 			"SetDllDirectoryA");
2090 
2091 		if (p_SetDllDirectoryA != NULL)
2092 			p_SetDllDirectoryA ("");
2093 	}
2094 #ifndef _WIN64
2095 	{
2096 		typedef BOOL (WINAPI *t_SetProcessDEPPolicy) (DWORD dwFlags);
2097 		t_SetProcessDEPPolicy p_SetProcessDEPPolicy;
2098 
2099 		p_SetProcessDEPPolicy = GetProcAddress (
2100 			GetModuleHandle ("kernel32.dll"),
2101 			"SetProcessDEPPolicy");
2102 
2103 		if (p_SetProcessDEPPolicy != NULL)
2104 			p_SetProcessDEPPolicy (
2105 				PROCESS_DEP_ENABLE |
2106 				PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION);
2107 	}
2108 #endif
2109 
2110 	if (fileno (stdout) != -1 && _get_osfhandle (fileno (stdout)) != -1) {
2111 		/* stdout is fine, presumably redirected to a file or pipe */
2112 	} else {
2113 		typedef BOOL (* WINAPI AttachConsole_t) (DWORD);
2114 
2115 		AttachConsole_t p_AttachConsole =
2116 			(AttachConsole_t) GetProcAddress (
2117 			GetModuleHandle ("kernel32.dll"), "AttachConsole");
2118 
2119 		if (p_AttachConsole && p_AttachConsole (ATTACH_PARENT_PROCESS)) {
2120 			freopen ("CONOUT$", "w", stdout);
2121 			dup2 (fileno (stdout), 1);
2122 			freopen ("CONOUT$", "w", stderr);
2123 			dup2 (fileno (stderr), 2);
2124 		}
2125 	}
2126 
2127 	chars = GetModuleFileNameA (hmodule, module_filename, 2048);
2128 	if (chars > 0) {
2129 		gchar *path;
2130 
2131 		module_filename[chars] = '\0';
2132 
2133 		path = strrchr (module_filename, '\\');
2134 		if (path)
2135 			path[1] = '\0';
2136 
2137 		path = g_build_path (";", module_filename, g_getenv ("PATH"), NULL);
2138 
2139 		if (!g_setenv ("PATH", path, TRUE))
2140 			g_warning ("Could not set PATH for Evolution and its child processes");
2141 
2142 		g_free (path);
2143 	}
2144 
2145 	/* Make sure D-Bus is running. The executable makes sure the daemon
2146 	   is not restarted, thus it's safe to be called witn D-Bus already
2147 	   running. */
2148 	if (system ("dbus-launch.exe") != 0) {
2149 		/* Ignore, just to mute compiler warning */;
2150 	}
2151 }
2152 
2153 #endif	/* G_OS_WIN32 */
2154 
2155 static gint default_dbus_timeout = -1;
2156 
2157 /**
2158  * e_data_server_util_set_dbus_call_timeout:
2159  * @timeout_msec: default timeout for D-Bus calls in miliseconds
2160  *
2161  * Sets default timeout, in milliseconds, for calls of g_dbus_proxy_call()
2162  * family functions.
2163  *
2164  * -1 means the default value as set by D-Bus itself.
2165  * G_MAXINT means no timeout at all.
2166  *
2167  * Default value is set also by configure option --with-dbus-call-timeout=ms
2168  * and -1 is used when not set.
2169  *
2170  * Since: 3.0
2171  *
2172  * Deprecated: 3.8: This value is not used anywhere.
2173  **/
2174 void
e_data_server_util_set_dbus_call_timeout(gint timeout_msec)2175 e_data_server_util_set_dbus_call_timeout (gint timeout_msec)
2176 {
2177 	default_dbus_timeout = timeout_msec;
2178 }
2179 
2180 /**
2181  * e_data_server_util_get_dbus_call_timeout:
2182  *
2183  * Returns the value set by e_data_server_util_set_dbus_call_timeout().
2184  *
2185  * Returns: the D-Bus call timeout in milliseconds
2186  *
2187  * Since: 3.0
2188  *
2189  * Deprecated: 3.8: This value is not used anywhere.
2190  **/
2191 gint
e_data_server_util_get_dbus_call_timeout(void)2192 e_data_server_util_get_dbus_call_timeout (void)
2193 {
2194 	return default_dbus_timeout;
2195 }
2196 
2197 /**
2198  * e_named_parameters_new:
2199  *
2200  * Creates a new instance of an #ENamedParameters. This should be freed
2201  * with e_named_parameters_free(), when no longer needed. Names are
2202  * compared case insensitively.
2203  *
2204  * The structure is not thread safe, if the caller requires thread safety,
2205  * then it should provide it on its own.
2206  *
2207  * Returns: newly allocated #ENamedParameters
2208  *
2209  * Since: 3.8
2210  **/
2211 ENamedParameters *
e_named_parameters_new(void)2212 e_named_parameters_new (void)
2213 {
2214 	return (ENamedParameters *) g_ptr_array_new_with_free_func ((GDestroyNotify) e_util_safe_free_string);
2215 }
2216 
2217 /**
2218  * e_named_parameters_new_strv:
2219  * @strv: NULL-terminated string array to be used as a content of a newly
2220  *     created #ENamedParameters
2221  *
2222  * Creates a new instance of an #ENamedParameters, with initial content
2223  * being taken from @strv. This should be freed with e_named_parameters_free(),
2224  * when no longer needed. Names are compared case insensitively.
2225  *
2226  * The structure is not thread safe, if the caller requires thread safety,
2227  * then it should provide it on its own.
2228  *
2229  * Returns: newly allocated #ENamedParameters
2230  *
2231  * Since: 3.8
2232  **/
2233 ENamedParameters *
e_named_parameters_new_strv(const gchar * const * strv)2234 e_named_parameters_new_strv (const gchar * const *strv)
2235 {
2236 	ENamedParameters *parameters;
2237 	gint ii;
2238 
2239 	g_return_val_if_fail (strv != NULL, NULL);
2240 
2241 	parameters = e_named_parameters_new ();
2242 	for (ii = 0; strv[ii]; ii++) {
2243 		g_ptr_array_add ((GPtrArray *) parameters, g_strdup (strv[ii]));
2244 	}
2245 
2246 	return parameters;
2247 }
2248 
2249 /**
2250  * e_named_parameters_new_string:
2251  * @str: a string to be used as a content of a newly created #ENamedParameters
2252  *
2253  * Creates a new instance of an #ENamedParameters, with initial content being
2254  * taken from @str. This should be freed with e_named_parameters_free(),
2255  * when no longer needed. Names are compared case insensitively.
2256  *
2257  * The @str should be created with e_named_parameters_to_string(), to be
2258  * properly encoded.
2259  *
2260  * The structure is not thread safe, if the caller requires thread safety,
2261  * then it should provide it on its own.
2262  *
2263  * Returns: (transfer full): newly allocated #ENamedParameters
2264  *
2265  * Since: 3.18
2266  **/
2267 ENamedParameters *
e_named_parameters_new_string(const gchar * str)2268 e_named_parameters_new_string (const gchar *str)
2269 {
2270 	ENamedParameters *parameters;
2271 	gchar **split;
2272 	gint ii;
2273 
2274 	g_return_val_if_fail (str != NULL, NULL);
2275 
2276 	split = g_strsplit (str, "\n", -1);
2277 
2278 	parameters = e_named_parameters_new ();
2279 	for (ii = 0; split && split[ii]; ii++) {
2280 		g_ptr_array_add ((GPtrArray *) parameters, g_strcompress (split[ii]));
2281 	}
2282 
2283 	g_strfreev (split);
2284 
2285 	return parameters;
2286 }
2287 
2288 /**
2289  * e_named_parameters_new_clone:
2290  * @parameters: an #ENamedParameters to be used as a content of a newly
2291  *    created #ENamedParameters
2292  *
2293  * Creates a new instance of an #ENamedParameters, with initial content
2294  * being taken from @parameters. This should be freed with e_named_parameters_free(),
2295  * when no longer needed. Names are compared case insensitively.
2296  *
2297  * The structure is not thread safe, if the caller requires thread safety,
2298  * then it should provide it on its own.
2299  *
2300  * Returns: newly allocated #ENamedParameters
2301  *
2302  * Since: 3.16
2303  **/
2304 ENamedParameters *
e_named_parameters_new_clone(const ENamedParameters * parameters)2305 e_named_parameters_new_clone (const ENamedParameters *parameters)
2306 {
2307 	ENamedParameters *clone;
2308 
2309 	clone = e_named_parameters_new ();
2310 	if (parameters)
2311 		e_named_parameters_assign (clone, parameters);
2312 
2313 	return clone;
2314 }
2315 
2316 /**
2317  * e_named_parameters_free:
2318  * @parameters: (nullable): an #ENamedParameters
2319  *
2320  * Frees an instance of #ENamedParameters, previously allocated
2321  * with e_named_parameters_new(). Function does nothing, if
2322  * @parameters is %NULL.
2323  *
2324  * Since: 3.8
2325  **/
2326 void
e_named_parameters_free(ENamedParameters * parameters)2327 e_named_parameters_free (ENamedParameters *parameters)
2328 {
2329 	if (!parameters)
2330 		return;
2331 
2332 	g_ptr_array_unref ((GPtrArray *) parameters);
2333 }
2334 
2335 /**
2336  * e_named_parameters_clear:
2337  * @parameters: an #ENamedParameters
2338  *
2339  * Removes all stored parameters from @parameters.
2340  *
2341  * Since: 3.8
2342  **/
2343 void
e_named_parameters_clear(ENamedParameters * parameters)2344 e_named_parameters_clear (ENamedParameters *parameters)
2345 {
2346 	GPtrArray *array;
2347 	g_return_if_fail (parameters != NULL);
2348 
2349 	array = (GPtrArray *) parameters;
2350 
2351 	if (array->len)
2352 		g_ptr_array_remove_range (array, 0, array->len);
2353 }
2354 
2355 /**
2356  * e_named_parameters_assign:
2357  * @parameters: an #ENamedParameters to assign values to
2358  * @from: (nullable): an #ENamedParameters to get values from, or %NULL
2359  *
2360  * Makes content of the @parameters the same as @from.
2361  * Functions clears content of @parameters if @from is %NULL.
2362  *
2363  * Since: 3.8
2364  **/
2365 void
e_named_parameters_assign(ENamedParameters * parameters,const ENamedParameters * from)2366 e_named_parameters_assign (ENamedParameters *parameters,
2367                            const ENamedParameters *from)
2368 {
2369 	g_return_if_fail (parameters != NULL);
2370 
2371 	e_named_parameters_clear (parameters);
2372 
2373 	if (from) {
2374 		gint ii;
2375 		GPtrArray *from_array = (GPtrArray *) from;
2376 
2377 		for (ii = 0; ii < from_array->len; ii++) {
2378 			g_ptr_array_add (
2379 				(GPtrArray *) parameters,
2380 				g_strdup (from_array->pdata[ii]));
2381 		}
2382 	}
2383 }
2384 
2385 static gint
get_parameter_index(const ENamedParameters * parameters,const gchar * name)2386 get_parameter_index (const ENamedParameters *parameters,
2387                      const gchar *name)
2388 {
2389 	GPtrArray *array;
2390 	gint ii, name_len;
2391 
2392 	g_return_val_if_fail (parameters != NULL, -1);
2393 	g_return_val_if_fail (name != NULL, -1);
2394 
2395 	name_len = strlen (name);
2396 
2397 	array = (GPtrArray *) parameters;
2398 
2399 	for (ii = 0; ii < array->len; ii++) {
2400 		const gchar *name_and_value = g_ptr_array_index (array, ii);
2401 
2402 		if (name_and_value == NULL || strlen (name_and_value) <= name_len)
2403 			continue;
2404 
2405 		if (name_and_value[name_len] != ':')
2406 			continue;
2407 
2408 		if (g_ascii_strncasecmp (name_and_value, name, name_len) == 0)
2409 			return ii;
2410 	}
2411 
2412 	return -1;
2413 }
2414 
2415 /**
2416  * e_named_parameters_set:
2417  * @parameters: an #ENamedParameters
2418  * @name: name of a parameter to set
2419  * @value: (nullable): value to set, or %NULL to unset
2420  *
2421  * Sets parameter named @name to value @value. If @value is NULL,
2422  * then the parameter is removed. @value can be an empty string.
2423  *
2424  * Note: There is a restriction on parameter names, it cannot be empty or
2425  * contain a colon character (':'), otherwise it can be pretty much anything.
2426  *
2427  * Since: 3.8
2428  **/
2429 void
e_named_parameters_set(ENamedParameters * parameters,const gchar * name,const gchar * value)2430 e_named_parameters_set (ENamedParameters *parameters,
2431                         const gchar *name,
2432                         const gchar *value)
2433 {
2434 	GPtrArray *array;
2435 	gint index;
2436 	gchar *name_and_value;
2437 
2438 	g_return_if_fail (parameters != NULL);
2439 	g_return_if_fail (name != NULL);
2440 	g_return_if_fail (strchr (name, ':') == NULL);
2441 	g_return_if_fail (*name != '\0');
2442 
2443 	array = (GPtrArray *) parameters;
2444 
2445 	index = get_parameter_index (parameters, name);
2446 	if (!value) {
2447 		if (index != -1)
2448 			g_ptr_array_remove_index (array, index);
2449 		return;
2450 	}
2451 
2452 	name_and_value = g_strconcat (name, ":", value, NULL);
2453 	if (index != -1) {
2454 		g_free (array->pdata[index]);
2455 		array->pdata[index] = name_and_value;
2456 	} else {
2457 		g_ptr_array_add (array, name_and_value);
2458 	}
2459 }
2460 
2461 /**
2462  * e_named_parameters_get:
2463  * @parameters: an #ENamedParameters
2464  * @name: name of a parameter to get
2465  *
2466  * Returns current value of a parameter with name @name. If not such
2467  * exists, then returns %NULL.
2468  *
2469  * Returns: (nullable): value of a parameter named @name, or %NULL.
2470  *
2471  * Since: 3.8
2472  **/
2473 const gchar *
e_named_parameters_get(const ENamedParameters * parameters,const gchar * name)2474 e_named_parameters_get (const ENamedParameters *parameters,
2475                         const gchar *name)
2476 {
2477 	gint index;
2478 	const gchar *name_and_value;
2479 
2480 	g_return_val_if_fail (parameters != NULL, NULL);
2481 	g_return_val_if_fail (name != NULL, NULL);
2482 
2483 	index = get_parameter_index (parameters, name);
2484 	if (index == -1)
2485 		return NULL;
2486 
2487 	name_and_value = g_ptr_array_index ((GPtrArray *) parameters, index);
2488 
2489 	return name_and_value + strlen (name) + 1;
2490 }
2491 
2492 /**
2493  * e_named_parameters_test:
2494  * @parameters: an #ENamedParameters
2495  * @name: name of a parameter to test
2496  * @value: value to test
2497  * @case_sensitively: whether to compare case sensitively
2498  *
2499  * Compares current value of parameter named @name with given @value
2500  * and returns whether they are equal, either case sensitively or
2501  * insensitively, based on @case_sensitively argument. Function
2502  * returns %FALSE, if no such parameter exists.
2503  *
2504  * Returns: Whether parameter of given name has stored value of given value.
2505  *
2506  * Since: 3.8
2507  **/
2508 gboolean
e_named_parameters_test(const ENamedParameters * parameters,const gchar * name,const gchar * value,gboolean case_sensitively)2509 e_named_parameters_test (const ENamedParameters *parameters,
2510                          const gchar *name,
2511                          const gchar *value,
2512                          gboolean case_sensitively)
2513 {
2514 	const gchar *stored_value;
2515 
2516 	g_return_val_if_fail (parameters != NULL, FALSE);
2517 	g_return_val_if_fail (name != NULL, FALSE);
2518 	g_return_val_if_fail (value != NULL, FALSE);
2519 
2520 	stored_value = e_named_parameters_get (parameters, name);
2521 	if (!stored_value)
2522 		return FALSE;
2523 
2524 	if (case_sensitively)
2525 		return strcmp (stored_value, value) == 0;
2526 
2527 	return g_ascii_strcasecmp (stored_value, value) == 0;
2528 }
2529 
2530 /**
2531  * e_named_parameters_to_strv:
2532  * @parameters: an #ENamedParameters
2533  *
2534  * Returns: (transfer full): Contents of @parameters as a null-terminated strv
2535  *
2536  * Since: 3.8
2537  */
2538 gchar **
e_named_parameters_to_strv(const ENamedParameters * parameters)2539 e_named_parameters_to_strv (const ENamedParameters *parameters)
2540 {
2541 	GPtrArray *array = (GPtrArray *) parameters;
2542 	GPtrArray *ret = g_ptr_array_new ();
2543 
2544 	if (array) {
2545 		guint i;
2546 		for (i = 0; i < array->len; i++) {
2547 			g_ptr_array_add (ret, g_strdup (array->pdata[i]));
2548 		}
2549 	}
2550 
2551 	g_ptr_array_add (ret, NULL);
2552 
2553 	return (gchar **) g_ptr_array_free (ret, FALSE);
2554 }
2555 
2556 /**
2557  * e_named_parameters_to_string:
2558  * @parameters: an #ENamedParameters
2559  *
2560  * Returns: (transfer full) (nullable): Contents of @parameters as a string
2561  *
2562  * Since: 3.18
2563  */
2564 gchar *
e_named_parameters_to_string(const ENamedParameters * parameters)2565 e_named_parameters_to_string (const ENamedParameters *parameters)
2566 {
2567 	gchar **strv, *str;
2568 	gint ii;
2569 
2570 	strv = e_named_parameters_to_strv (parameters);
2571 	if (!strv)
2572 		return NULL;
2573 
2574 	for (ii = 0; strv[ii]; ii++) {
2575 		gchar *name_and_value = strv[ii];
2576 
2577 		strv[ii] = g_strescape (name_and_value, "");
2578 		g_free (name_and_value);
2579 	}
2580 
2581 	str = g_strjoinv ("\n", strv);
2582 
2583 	g_strfreev (strv);
2584 
2585 	return str;
2586 }
2587 
2588 /**
2589  * e_named_parameters_exists:
2590  * @parameters: an #ENamedParameters
2591  * @name: name of the parameter whose existence to check
2592  *
2593  * Returns: Whether @parameters holds a parameter named @name
2594  *
2595  * Since: 3.18
2596  **/
2597 gboolean
e_named_parameters_exists(const ENamedParameters * parameters,const gchar * name)2598 e_named_parameters_exists (const ENamedParameters *parameters,
2599 			   const gchar *name)
2600 {
2601 	g_return_val_if_fail (parameters != NULL, FALSE);
2602 	g_return_val_if_fail (name != NULL, FALSE);
2603 
2604 	return get_parameter_index (parameters, name) != -1;
2605 }
2606 
2607 /**
2608  * e_named_parameters_count:
2609  * @parameters: an #ENamedParameters
2610  *
2611  * Returns: The number of stored named parameters in @parameters
2612  *
2613  * Since: 3.18
2614  **/
2615 guint
e_named_parameters_count(const ENamedParameters * parameters)2616 e_named_parameters_count (const ENamedParameters *parameters)
2617 {
2618 	g_return_val_if_fail (parameters != NULL, 0);
2619 
2620 	return ((GPtrArray *) parameters)->len;
2621 }
2622 
2623 /**
2624  * e_named_parameters_get_name:
2625  * @parameters: an #ENamedParameters
2626  * @index: an index of the parameter whose name to retrieve
2627  *
2628  * Returns: (transfer full) (nullable): The name of the parameters at index @index,
2629  *    or %NULL, of the @index is out of bounds or other error. The returned
2630  *    string should be freed with g_free() when done with it.
2631  *
2632  * Since: 3.18
2633  **/
2634 gchar *
e_named_parameters_get_name(const ENamedParameters * parameters,gint index)2635 e_named_parameters_get_name (const ENamedParameters *parameters,
2636 			     gint index)
2637 {
2638 	const gchar *name_and_value, *colon;
2639 
2640 	g_return_val_if_fail (parameters != NULL, NULL);
2641 	g_return_val_if_fail (index >= 0 && index < e_named_parameters_count (parameters), NULL);
2642 
2643 	name_and_value = g_ptr_array_index ((GPtrArray *) parameters, index);
2644 	colon = name_and_value ? strchr (name_and_value, ':') : NULL;
2645 
2646 	if (!colon || colon == name_and_value)
2647 		return NULL;
2648 
2649 	return g_strndup (name_and_value, colon - name_and_value);
2650 }
2651 
2652 static ENamedParameters *
e_named_parameters_ref(ENamedParameters * params)2653 e_named_parameters_ref (ENamedParameters *params)
2654 {
2655 	return (ENamedParameters *) g_ptr_array_ref ((GPtrArray *) params);
2656 }
2657 
2658 static void
e_named_parameters_unref(ENamedParameters * params)2659 e_named_parameters_unref (ENamedParameters *params)
2660 {
2661 	g_ptr_array_unref ((GPtrArray *) params);
2662 }
2663 
2664 G_DEFINE_BOXED_TYPE (
2665 	ENamedParameters,
2666 	e_named_parameters,
2667 	e_named_parameters_ref,
2668 	e_named_parameters_unref);
2669 
2670 /**
2671  * e_named_timeout_add:
2672  * @interval: the time between calls to the function, in milliseconds
2673  *            (1/1000ths of a second)
2674  * @function: function to call
2675  * @data: data to pass to @function
2676  *
2677  * Similar to g_timeout_add(), but also names the #GSource for use in
2678  * debugging and profiling.  The name is formed from @function and the
2679  * <literal>PACKAGE</literal> definintion from a &lt;config.h&gt; file.
2680  *
2681  * Returns: the ID (greater than 0) of the event source
2682  *
2683  * Since: 3.12
2684  **/
2685 
2686 /**
2687  * e_named_timeout_add_full:
2688  * @priority: the priority of the timeout source, typically in the
2689  *            range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH
2690  * @interval: the time between calls to the function, in milliseconds
2691  *            (1/1000ths of a second)
2692  * @function: function to call
2693  * @data: data to pass to @function
2694  * @notify: function to call when the timeout is removed, or %NULL
2695  *
2696  * Similar to g_timeout_add_full(), but also names the #GSource for use
2697  * in debugging and profiling.  The name is formed from @function and the
2698  * <literal>PACKAGE</literal> definition from a &lt;config.h&gt; file.
2699  *
2700  * Returns: the ID (greater than 0) of the event source
2701  *
2702  * Since: 3.12
2703  **/
2704 
2705 /**
2706  * e_named_timeout_add_seconds:
2707  * @interval: the time between calls to the function, in seconds
2708  * @function: function to call
2709  * @data: data to pass to @function
2710  *
2711  * Similar to g_timeout_add_seconds(), but also names the #GSource for use
2712  * in debugging and profiling.  The name is formed from @function and the
2713  * <literal>PACKAGE</literal> definition from a &lt;config.h&gt; file.
2714  *
2715  * Returns: the ID (greater than 0) of the event source
2716  *
2717  * Since: 3.12
2718  **/
2719 
2720 /**
2721  * e_named_timeout_add_seconds_full:
2722  * @priority: the priority of the timeout source, typically in the
2723  *            range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH
2724  * @interval: the time between calls to the function, in seconds
2725  * @function: function to call
2726  * @data: data to pass to @function
2727  * @notify: function to call when the timeout is removed, or %NULL
2728  *
2729  * Similar to g_timeout_add_seconds_full(), but also names the #GSource for
2730  * use in debugging and profiling.  The name is formed from @function and the
2731  * <literal>PACKAGE</literal> definition from a &lt;config.h&gt; file.
2732  *
2733  * Returns: the ID (greater than 0) of the event source
2734  *
2735  * Since: 3.12
2736  **/
2737 
2738 /**
2739  * e_timeout_add_with_name:
2740  * @priority: the priority of the timeout source, typically in the
2741  *            range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH
2742  * @interval: the time between calls to the function, in milliseconds
2743  *            (1/1000ths of a second)
2744  * @name: (nullable): debug name for the source
2745  * @function: function to call
2746  * @data: data to pass to @function
2747  * @notify: (nullable): function to call when the timeout is removed,
2748  *          or %NULL
2749  *
2750  * Similar to g_timeout_add_full(), but also names the #GSource as @name.
2751  *
2752  * You might find e_named_timeout_add() or e_named_timeout_add_full() more
2753  * convenient.  Those macros name the #GSource implicitly.
2754  *
2755  * Returns: the ID (greather than 0) of the event source
2756  *
2757  * Since: 3.12
2758  **/
2759 guint
e_timeout_add_with_name(gint priority,guint interval,const gchar * name,GSourceFunc function,gpointer data,GDestroyNotify notify)2760 e_timeout_add_with_name (gint priority,
2761                          guint interval,
2762                          const gchar *name,
2763                          GSourceFunc function,
2764                          gpointer data,
2765                          GDestroyNotify notify)
2766 {
2767 	guint tag;
2768 
2769 	g_return_val_if_fail (function != NULL, 0);
2770 
2771 	tag = g_timeout_add_full (
2772 		priority, interval, function, data, notify);
2773 	g_source_set_name_by_id (tag, name);
2774 
2775 	return tag;
2776 }
2777 
2778 /**
2779  * e_timeout_add_seconds_with_name:
2780  * @priority: the priority of the timeout source, typically in the
2781  *            range between #G_PRIORITY_DEFAULT and #G_PRIORITY_HIGH
2782  * @interval: the time between calls to the function, in seconds
2783  * @name: (nullable): debug name for the source
2784  * @function: function to call
2785  * @data: data to pass to @function
2786  * @notify: (nullable): function to call when the timeout is removed,
2787  *          or %NULL
2788  *
2789  * Similar to g_timeout_add_seconds_full(), but also names the #GSource as
2790  * @name.
2791  *
2792  * You might find e_named_timeout_add_seconds() or
2793  * e_named_timeout_add_seconds_full() more convenient.  Those macros name
2794  * the #GSource implicitly.
2795  *
2796  * Returns: the ID (greater than 0) of the event source
2797  *
2798  * Since: 3.12
2799  **/
2800 guint
e_timeout_add_seconds_with_name(gint priority,guint interval,const gchar * name,GSourceFunc function,gpointer data,GDestroyNotify notify)2801 e_timeout_add_seconds_with_name (gint priority,
2802                                  guint interval,
2803                                  const gchar *name,
2804                                  GSourceFunc function,
2805                                  gpointer data,
2806                                  GDestroyNotify notify)
2807 {
2808 	guint tag;
2809 
2810 	g_return_val_if_fail (function != NULL, 0);
2811 
2812 	tag = g_timeout_add_seconds_full (
2813 		priority, interval, function, data, notify);
2814 	g_source_set_name_by_id (tag, name);
2815 
2816 	return tag;
2817 }
2818 
2819 /**
2820  * e_source_registry_debug_enabled:
2821  *
2822  * Returns: Whether debugging is enabled, that is,
2823  * whether e_source_registry_debug_print() will produce any output.
2824  *
2825  * Since: 3.16
2826  **/
2827 gboolean
e_source_registry_debug_enabled(void)2828 e_source_registry_debug_enabled (void)
2829 {
2830 	static gint esr_debug = -1;
2831 
2832 	if (esr_debug == -1)
2833 		esr_debug = g_strcmp0 (g_getenv ("ESR_DEBUG"), "1") == 0 ? 1 : 0;
2834 
2835 	return esr_debug == 1;
2836 }
2837 
2838 /**
2839  * e_source_registry_debug_print:
2840  * @format: a format string to print
2841  * @...: other arguments for the format
2842  *
2843  * Prints the text only if a debugging is enabled with an environment
2844  * variable ESR_DEBUG=1.
2845  *
2846  * Since: 3.16
2847  **/
2848 void
e_source_registry_debug_print(const gchar * format,...)2849 e_source_registry_debug_print (const gchar *format,
2850 			       ...)
2851 {
2852 	va_list args;
2853 
2854 	if (!e_source_registry_debug_enabled ())
2855 		return;
2856 
2857 	va_start (args, format);
2858 	e_util_debug_printv ("ESR", format, args);
2859 	va_end (args);
2860 }
2861 
2862 /**
2863  * e_util_debug_print:
2864  * @domain: a debug domain
2865  * @format: a printf-like format
2866  * @...: arguments for the @format
2867  *
2868  * Prints a text according to @format and its arguments to stdout
2869  * prefixed with @domain in brackets [] and the current date and time.
2870  * This function doesn't check whether the logging is enabled, it's up
2871  * to the caller to determine it, the function only prints the information
2872  * in a consistent format:
2873  * [domain] YYYY-MM-DD hh:mm:ss.ms - format
2874  *
2875  * See: e_util_debug_printv()
2876  *
2877  * Since: 3.30
2878  **/
2879 void
e_util_debug_print(const gchar * domain,const gchar * format,...)2880 e_util_debug_print (const gchar *domain,
2881 		    const gchar *format,
2882 		    ...)
2883 {
2884 	va_list args;
2885 
2886 	va_start (args, format);
2887 	e_util_debug_printv (domain, format, args);
2888 	va_end (args);
2889 }
2890 
2891 /**
2892  * e_util_debug_printv:
2893  * @domain: a debug domain
2894  * @format: a printf-like format
2895  * @args: arguments for the @format
2896  *
2897  * Prints a text according to @format and its @args to stdout
2898  * prefixed with @domain in brackets [] and the current date and time.
2899  * This function doesn't check whether the logging is enabled, it's up
2900  * to the caller to determine it, the function only prints the information
2901  * in a consistent form:
2902  * [@domain] YYYY-MM-DD hh:mm:ss.ms - @format
2903  *
2904  * See: e_util_debug_print()
2905  *
2906  * Since: 3.30
2907  **/
2908 void
e_util_debug_printv(const gchar * domain,const gchar * format,va_list args)2909 e_util_debug_printv (const gchar *domain,
2910 		     const gchar *format,
2911 		     va_list args)
2912 {
2913 	GString *str;
2914 	GDateTime *dt;
2915 
2916 	if (!domain)
2917 		domain = "???";
2918 
2919 	str = g_string_new ("");
2920 	g_string_vprintf (str, format, args);
2921 	dt = g_date_time_new_now_local ();
2922 
2923 	if (dt) {
2924 		g_print ("[%s] %04d-%02d-%02d %02d:%02d:%02d.%03d - %s",
2925 			domain,
2926 			g_date_time_get_year (dt),
2927 			g_date_time_get_month (dt),
2928 			g_date_time_get_day_of_month (dt),
2929 			g_date_time_get_hour (dt),
2930 			g_date_time_get_minute (dt),
2931 			g_date_time_get_second (dt),
2932 			g_date_time_get_microsecond (dt) / 1000,
2933 			str->str);
2934 		g_date_time_unref (dt);
2935 	} else {
2936 		g_print ("[%s] %s", domain, str->str);
2937 	}
2938 
2939 	g_string_free (str, TRUE);
2940 }
2941 
2942 /**
2943  * e_type_traverse:
2944  * @parent_type: the root #GType to traverse from
2945  * @func: (scope call): the function to call for each visited #GType
2946  * @user_data: user data to pass to the function
2947  *
2948  * Calls @func for all instantiable subtypes of @parent_type.
2949  *
2950  * This is often useful for extending functionality by way of #EModule.
2951  * A module may register a subtype of @parent_type in its e_module_load()
2952  * function.  Then later on the application will call e_type_traverse()
2953  * to instantiate all registered subtypes of @parent_type.
2954  *
2955  * Since: 3.4
2956  **/
2957 void
e_type_traverse(GType parent_type,ETypeFunc func,gpointer user_data)2958 e_type_traverse (GType parent_type,
2959                  ETypeFunc func,
2960                  gpointer user_data)
2961 {
2962 	GType *children;
2963 	guint n_children, ii;
2964 
2965 	g_return_if_fail (func != NULL);
2966 
2967 	children = g_type_children (parent_type, &n_children);
2968 
2969 	for (ii = 0; ii < n_children; ii++) {
2970 		GType type = children[ii];
2971 
2972 		/* Recurse over the child's children. */
2973 		e_type_traverse (type, func, user_data);
2974 
2975 		/* Skip abstract types. */
2976 		if (G_TYPE_IS_ABSTRACT (type))
2977 			continue;
2978 
2979 		func (type, user_data);
2980 	}
2981 
2982 	g_free (children);
2983 }
2984 
2985 /**
2986  * e_util_get_source_full_name:
2987  * @registry: an #ESourceRegistry
2988  * @source: an #ESource
2989  *
2990  * Constructs a full name of the @source with all of its parents
2991  * of the form: "&lt;account-name&gt; : &lt;parent&gt;/&lt;source&gt;" where
2992  * the "&lt;parent&gt;/" part can be repeated zero or more times, depending
2993  * on the deep level of the @source.
2994  *
2995  * Returns: (transfer full): Full name of the @source as a newly allocated
2996  *    string, which should be freed with g_free() when done with it.
2997  *
2998  * Since 3.18
2999  **/
3000 gchar *
e_util_get_source_full_name(ESourceRegistry * registry,ESource * source)3001 e_util_get_source_full_name (ESourceRegistry *registry,
3002 			     ESource *source)
3003 {
3004 	GString *fullname;
3005 	GSList *parts, *link;
3006 
3007 	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
3008 
3009 	if (!registry)
3010 		return g_strdup (e_source_get_display_name (source));
3011 
3012 	parts = NULL;
3013 
3014 	parts = g_slist_prepend (parts, g_strdup (e_source_get_display_name (source)));
3015 
3016 	g_object_ref (source);
3017 	while (source) {
3018 		const gchar *parent_id;
3019 		ESource *parent;
3020 
3021 		parent_id = e_source_get_parent (source);
3022 		if (!parent_id || !*parent_id)
3023 			break;
3024 
3025 		parent = e_source_registry_ref_source (registry, parent_id);
3026 		g_object_unref (source);
3027 		source = parent;
3028 
3029 		if (source) {
3030 			const gchar *display_name = e_source_get_display_name (source);
3031 
3032 			if (!display_name || !*display_name)
3033 				break;
3034 
3035 			parts = g_slist_prepend (parts, g_strdup (display_name));
3036 		}
3037 	}
3038 
3039 	g_object_unref (source);
3040 
3041 	fullname = g_string_new ("");
3042 
3043 	for (link = parts; link; link = link->next) {
3044 		const gchar *part = link->data;
3045 
3046 		if (fullname->len) {
3047 			if (link == parts->next)
3048 				g_string_append (fullname, " : ");
3049 			else
3050 				g_string_append_c (fullname, '/');
3051 		}
3052 
3053 		g_string_append (fullname, part);
3054 	}
3055 
3056 	g_slist_free_full (parts, g_free);
3057 
3058 	return g_string_free (fullname, FALSE);
3059 }
3060 
3061 static gpointer
unref_object_in_thread(gpointer ptr)3062 unref_object_in_thread (gpointer ptr)
3063 {
3064 	GObject *object = ptr;
3065 
3066 	g_return_val_if_fail (object != NULL, NULL);
3067 
3068 	g_object_unref (object);
3069 
3070 	return NULL;
3071 }
3072 
3073 /**
3074  * e_util_unref_in_thread:
3075  * @object: a #GObject
3076  *
3077  * Unrefs the given @object in a dedicated thread. This is useful when unreffing
3078  * object deep in call stack when the caller might still use the object and
3079  * this being the last reference to it.
3080  *
3081  * Since: 3.26
3082  **/
3083 void
e_util_unref_in_thread(gpointer object)3084 e_util_unref_in_thread (gpointer object)
3085 {
3086 	GThread *thread;
3087 	GError *error = NULL;
3088 
3089 	if (!object)
3090 		return;
3091 
3092 	g_return_if_fail (G_IS_OBJECT (object));
3093 
3094 	thread = g_thread_try_new (NULL, unref_object_in_thread, object, &error);
3095 	if (thread) {
3096 		g_thread_unref (thread);
3097 	} else {
3098 		g_warning ("%s: Failed to run thread: %s", G_STRFUNC, error ? error->message : "Unknown error");
3099 		g_object_unref (object);
3100 	}
3101 
3102 	g_clear_error (&error);
3103 }
3104 
3105 /**
3106  * e_util_generate_uid:
3107  *
3108  * Generates a unique identificator, which can be used as part of
3109  * the Message-ID header, or iCalendar component UID, or vCard UID.
3110  * The resulting string doesn't contain any host name, it's
3111  * a hexa-decimal string with no particular meaning.
3112  *
3113  * Free the returned string with g_free(), when no longer needed.
3114  *
3115  * Returns: (transfer full): generated unique identificator as
3116  *    a newly allocated string
3117  *
3118  * Since: 3.26
3119  **/
3120 gchar *
e_util_generate_uid(void)3121 e_util_generate_uid (void)
3122 {
3123 	static volatile gint counter = 0;
3124 	gchar *uid;
3125 	GChecksum *checksum;
3126 
3127 	checksum = g_checksum_new (G_CHECKSUM_SHA1);
3128 
3129 	#define add_i64(_x) G_STMT_START { \
3130 		gint64 i64 = (_x); \
3131 		g_checksum_update (checksum, (const guchar *) &i64, sizeof (gint64)); \
3132 	} G_STMT_END
3133 
3134 	#define add_str(_x, _def) G_STMT_START { \
3135 		const gchar *str = (_x); \
3136 		if (!str) \
3137 			str = (_def); \
3138 		g_checksum_update (checksum, (const guchar *) str, strlen (str)); \
3139 	} G_STMT_END
3140 
3141 	add_i64 (g_get_monotonic_time ());
3142 	add_i64 (g_get_real_time ());
3143 	add_i64 (getpid ());
3144 	add_i64 (getgid ());
3145 	add_i64 (getppid ());
3146 	add_i64 (g_atomic_int_add (&counter, 1));
3147 
3148 	add_str (g_get_host_name (), "localhost");
3149 	add_str (g_get_user_name (), "user");
3150 	add_str (g_get_real_name (), "User");
3151 
3152 	#undef add_i64
3153 	#undef add_str
3154 
3155 	uid = g_strdup (g_checksum_get_string (checksum));
3156 
3157 	g_checksum_free (checksum);
3158 
3159 	return uid;
3160 }
3161 
3162 /**
3163  * e_util_identity_can_send:
3164  * @registry: an #ESourceRegistry
3165  * @identity_source: an #ESource with mail identity extension
3166  *
3167  * Checks whether the @identity_source can be used for sending, which means
3168  * whether it has configures send mail source.
3169  *
3170  * Returns: Whether @identity_source can be used to send messages
3171  *
3172  * Since: 3.26
3173  **/
3174 gboolean
e_util_identity_can_send(ESourceRegistry * registry,ESource * identity_source)3175 e_util_identity_can_send (ESourceRegistry *registry,
3176 			  ESource *identity_source)
3177 {
3178 	ESourceMailSubmission *mail_submission;
3179 	ESource *transport_source = NULL;
3180 	const gchar *transport_uid;
3181 	gboolean can_send = FALSE;
3182 
3183 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
3184 	g_return_val_if_fail (E_IS_SOURCE (identity_source), FALSE);
3185 
3186 	if (!e_source_has_extension (identity_source, E_SOURCE_EXTENSION_MAIL_IDENTITY) ||
3187 	    !e_source_has_extension (identity_source, E_SOURCE_EXTENSION_MAIL_SUBMISSION))
3188 		return FALSE;
3189 
3190 	mail_submission = e_source_get_extension (identity_source, E_SOURCE_EXTENSION_MAIL_SUBMISSION);
3191 
3192 	e_source_extension_property_lock (E_SOURCE_EXTENSION (mail_submission));
3193 
3194 	transport_uid = e_source_mail_submission_get_transport_uid (mail_submission);
3195 	if (transport_uid && *transport_uid)
3196 		transport_source = e_source_registry_ref_source (registry, transport_uid);
3197 
3198 	e_source_extension_property_unlock (E_SOURCE_EXTENSION (mail_submission));
3199 
3200 	if (!transport_source)
3201 		return FALSE;
3202 
3203 	if (e_source_has_extension (transport_source, E_SOURCE_EXTENSION_MAIL_TRANSPORT)) {
3204 		ESourceMailTransport *mail_transport;
3205 		const gchar *backend_name;
3206 
3207 		mail_transport = e_source_get_extension (transport_source, E_SOURCE_EXTENSION_MAIL_TRANSPORT);
3208 
3209 		e_source_extension_property_lock (E_SOURCE_EXTENSION (mail_transport));
3210 
3211 		backend_name = e_source_backend_get_backend_name (E_SOURCE_BACKEND (mail_transport));
3212 		can_send = backend_name && *backend_name && g_strcmp0 (backend_name, "none") != 0;
3213 
3214 		e_source_extension_property_unlock (E_SOURCE_EXTENSION (mail_transport));
3215 	}
3216 
3217 	g_object_unref (transport_source);
3218 
3219 	return can_send;
3220 }
3221 
3222 /**
3223  * e_util_can_use_collection_as_credential_source:
3224  * @collection_source: (nullable): a collection #ESource, or %NULL
3225  * @child_source: a children of @collection_source
3226  *
3227  * Checks whether the @collection_source can be used as a credential source
3228  * for the @child_source. The relationship is not tested in the function.
3229  * When the @collection_source is %NULL, then it simply returns %FALSE.
3230  *
3231  * Returns: whether @collection_source can be used as a credential source
3232  *    for @child_source, that is, whether they share credentials.
3233  *
3234  * Since: 3.28
3235  **/
3236 gboolean
e_util_can_use_collection_as_credential_source(ESource * collection_source,ESource * child_source)3237 e_util_can_use_collection_as_credential_source (ESource *collection_source,
3238 						ESource *child_source)
3239 {
3240 	gboolean can_use_collection = FALSE;
3241 
3242 	if (collection_source)
3243 		g_return_val_if_fail (E_IS_SOURCE (collection_source), FALSE);
3244 	g_return_val_if_fail (E_IS_SOURCE (child_source), FALSE);
3245 
3246 	if (collection_source && e_source_has_extension (collection_source, E_SOURCE_EXTENSION_COLLECTION)) {
3247 		/* Use the found parent collection source for credentials store only if
3248 		   the child source doesn't have any authentication information, or this
3249 		   information is not filled, or if either the host name or the user name
3250 		   are the same with the collection source.
3251 
3252 		   This allows to create a collection of sources which has one source
3253 		   (like message send) on a different server, thus this source uses
3254 		   its own credentials.
3255 		*/
3256 		if (!e_source_has_extension (child_source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
3257 			can_use_collection = TRUE;
3258 		} else if (e_source_has_extension (collection_source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
3259 			ESourceAuthentication *auth_source, *auth_collection;
3260 			gchar *host_source, *host_collection;
3261 
3262 			auth_source = e_source_get_extension (child_source, E_SOURCE_EXTENSION_AUTHENTICATION);
3263 			auth_collection = e_source_get_extension (collection_source, E_SOURCE_EXTENSION_AUTHENTICATION);
3264 
3265 			host_source = e_source_authentication_dup_host (auth_source);
3266 			host_collection = e_source_authentication_dup_host (auth_collection);
3267 
3268 			if (host_source && host_collection && g_ascii_strcasecmp (host_source, host_collection) == 0) {
3269 				can_use_collection = TRUE;
3270 			} else {
3271 				/* Only one of them is filled, then use the collection; otherwise
3272 				   both are filled and they do not match, thus do not use collection. */
3273 				can_use_collection = (host_collection && *host_collection && (!host_source || !*host_source)) ||
3274 						     (host_source && *host_source && (!host_collection || !*host_collection));
3275 			}
3276 
3277 			g_free (host_source);
3278 			g_free (host_collection);
3279 
3280 			if (can_use_collection) {
3281 				gchar *username_source, *username_collection;
3282 
3283 				username_source = e_source_authentication_dup_user (auth_source);
3284 				username_collection = e_source_authentication_dup_user (auth_collection);
3285 
3286 				/* Check user name similarly as host name */
3287 				if (username_source && username_collection && g_ascii_strcasecmp (username_source, username_collection) == 0) {
3288 					can_use_collection = TRUE;
3289 				} else {
3290 					can_use_collection = !username_source || !*username_source;
3291 				}
3292 
3293 				g_free (username_source);
3294 				g_free (username_collection);
3295 			}
3296 
3297 			if (can_use_collection) {
3298 				gchar *method_source, *method_collection;
3299 
3300 				/* Also check the method; if different, then rather not use the collection.
3301 				   Consider 'none' method on the child as the same as the collection method. */
3302 				method_source = e_source_authentication_dup_method (auth_source);
3303 				method_collection = e_source_authentication_dup_method (auth_collection);
3304 
3305 				can_use_collection = !method_source || !method_collection ||
3306 					g_ascii_strcasecmp (method_source, "none") == 0 ||
3307 					g_ascii_strcasecmp (method_source, method_collection) == 0;
3308 
3309 				g_free (method_source);
3310 				g_free (method_collection);
3311 			}
3312 		}
3313 	}
3314 
3315 	return can_use_collection;
3316 }
3317 
3318 static gboolean
e_util_source_compare_get_order(ESource * source,guint * out_order)3319 e_util_source_compare_get_order (ESource *source,
3320 				 guint *out_order)
3321 {
3322 	const gchar *extensions[] = {
3323 		E_SOURCE_EXTENSION_ADDRESS_BOOK, /* keep it as the first - see below */
3324 		E_SOURCE_EXTENSION_CALENDAR,
3325 		E_SOURCE_EXTENSION_MEMO_LIST,
3326 		E_SOURCE_EXTENSION_TASK_LIST
3327 	};
3328 	gint ii;
3329 
3330 	for (ii = 0; ii < G_N_ELEMENTS (extensions); ii++) {
3331 		if (e_source_has_extension (source, extensions[ii])) {
3332 			ESourceExtension *extension = e_source_get_extension (source, extensions[ii]);
3333 
3334 			if (ii == 0) /* E_SOURCE_EXTENSION_ADDRESS_BOOK */
3335 				*out_order = e_source_address_book_get_order (E_SOURCE_ADDRESS_BOOK (extension));
3336 			else
3337 				*out_order = e_source_selectable_get_order (E_SOURCE_SELECTABLE (extension));
3338 
3339 			if (*out_order == (guint) -1)
3340 				return FALSE;
3341 
3342 			return TRUE;
3343 		}
3344 	}
3345 
3346 	return FALSE;
3347 }
3348 
3349 /**
3350  * e_util_source_compare_for_sort:
3351  * @source_a: the first #ESource
3352  * @source_b: the second #ESource
3353  *
3354  * Compares two #ESource-s in a way suitable for user interface.
3355  * It can be used as a #GCompareFunc.
3356  *
3357  * This is also used by e_source_registry_build_display_tree().
3358  *
3359  * Returns: an integer less than, equal to, or greater than zero,
3360  *    if @source_a is <, == or > than @source_b.
3361  *
3362  * Since: 3.40
3363  **/
3364 gint
e_util_source_compare_for_sort(ESource * source_a,ESource * source_b)3365 e_util_source_compare_for_sort (ESource *source_a,
3366 				ESource *source_b)
3367 {
3368 	guint order_a = 0, order_b = 0;
3369 	const gchar *uid_a, *uid_b;
3370 
3371 	if (!source_a || !source_b)
3372 		return (source_a ? 1 : 0) - (source_b ? 1 : 0);
3373 
3374 	uid_a = e_source_get_uid (source_a);
3375 	uid_b = e_source_get_uid (source_b);
3376 
3377 	/* Sanity check, with runtime warnings. */
3378 	if (uid_a == NULL) {
3379 		g_warn_if_reached ();
3380 		uid_a = "";
3381 	}
3382 	if (uid_b == NULL) {
3383 		g_warn_if_reached ();
3384 		uid_b = "";
3385 	}
3386 
3387 	/* The built-in "local-stub" source comes first at depth 1. */
3388 
3389 	if (g_strcmp0 (uid_a, "local-stub") == 0)
3390 		return -1;
3391 
3392 	if (g_strcmp0 (uid_b, "local-stub") == 0)
3393 		return 1;
3394 
3395 	/* The built-in "system-*" sources come first at depth 2. */
3396 
3397 	if (g_str_has_prefix (uid_a, "system-"))
3398 		return -1;
3399 
3400 	if (g_str_has_prefix (uid_b, "system-"))
3401 		return 1;
3402 
3403 	if (e_util_source_compare_get_order (source_a, &order_a) &&
3404 	    e_util_source_compare_get_order (source_b, &order_b)) {
3405 		if (order_a != order_b)
3406 			return order_a < order_b ? -1 : 1;
3407 	}
3408 
3409 	return e_source_compare_by_display_name (source_a, source_b);
3410 }
3411 
3412 /**
3413  * e_util_get_directory_variants:
3414  * @main_path: the main path to work with
3415  * @replace_prefix: path prefix to replace
3416  * @with_modules_dir: whether to add also the modules directory
3417  *
3418  * The @main_path is a directory, which will be always used. It
3419  * should have as its prefix the @replace_prefix, otherwise
3420  * the function returns only the @main_path in the paths array.
3421  *
3422  * When there's exported an environment variable EDS_EXTRA_PREFIXES,
3423  * it is used as a list of alternative prefixes where to look for
3424  * the @main_path (rest after the @replace_prefix).
3425  *
3426  * When the @with_modules_dir is %TRUE, there's also added
3427  * g_get_user_data_dir() + "evolution/modules/", aka
3428  * ~/.local/share/evolution/modules/, into the resulting array.
3429  *
3430  * Returns: (element-type utf8) (transfer container): a %GPtrArray
3431  *    with paths to use, including the @main_path. Free it with
3432  *    g_ptr_array_unref(), when no longer needed.
3433  *
3434  * Since: 3.40
3435  **/
3436 GPtrArray *
e_util_get_directory_variants(const gchar * main_path,const gchar * replace_prefix,gboolean with_modules_dir)3437 e_util_get_directory_variants (const gchar *main_path,
3438 			       const gchar *replace_prefix,
3439 			       gboolean with_modules_dir)
3440 {
3441 	g_return_val_if_fail (main_path && *main_path, NULL);
3442 	g_return_val_if_fail (replace_prefix && *replace_prefix, NULL);
3443 
3444 	return camel_util_get_directory_variants (main_path, replace_prefix, with_modules_dir);
3445 }
3446