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 %l and %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 <config.h> 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 <config.h> 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 <config.h> 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 <config.h> 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: "<account-name> : <parent>/<source>" where
2992 * the "<parent>/" 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