1 /*
2 * e-credentials.c
3 *
4 * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
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 */
19
20 #include "evolution-data-server-config.h"
21
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "e-data-server-util.h"
26
27 #include "e-credentials.h"
28
29 struct _ECredentialsPrivate
30 {
31 GHashTable *keys;
32 GHashTable *peek_keys;
33 };
34
35 static gboolean
key_equal(gconstpointer str1,gconstpointer str2)36 key_equal (gconstpointer str1,
37 gconstpointer str2)
38 {
39 g_return_val_if_fail (str1 != NULL, FALSE);
40 g_return_val_if_fail (str2 != NULL, FALSE);
41
42 if (str1 == str2)
43 return TRUE;
44
45 return g_ascii_strcasecmp (str1, str2) == 0;
46 }
47
48 /**
49 * e_credentials_new:
50 *
51 * Returns: (transfer full): a new empty #ECredentials. Free with e_credentials_free() when done with it.
52 *
53 * Since: 3.2
54 **/
55 ECredentials *
e_credentials_new(void)56 e_credentials_new (void)
57 {
58 ECredentials *credentials;
59
60 credentials = g_slice_new0 (ECredentials);
61 credentials->priv = g_slice_new0 (ECredentialsPrivate);
62 credentials->priv->keys = g_hash_table_new_full (g_str_hash, key_equal, g_free, (GDestroyNotify) e_credentials_util_safe_free_string);
63 credentials->priv->peek_keys = g_hash_table_new_full (g_str_hash, key_equal, g_free, (GDestroyNotify) e_credentials_util_safe_free_string);
64
65 return credentials;
66 }
67
68 /**
69 * e_credentials_new_strv:
70 * @strv: an array of key/value-s to prefill
71 *
72 * Creates a new #ECredentials with prefilled key/value-s from @strv. It expects
73 * the @strv as a NULL-terminated list of strings "key:encoded_value".
74 * The same can be returned from e_credentials_to_strv ().
75 *
76 * Returns: (transfer full): a new #ECredentials. Free with e_credentials_free() when done with it.
77 *
78 * Since: 3.2
79 **/
80 ECredentials *
e_credentials_new_strv(const gchar * const * strv)81 e_credentials_new_strv (const gchar * const *strv)
82 {
83 ECredentials *credentials;
84 gint ii;
85
86 g_return_val_if_fail (strv != NULL, NULL);
87
88 credentials = e_credentials_new ();
89
90 for (ii = 0; strv[ii]; ii++) {
91 const gchar *key = strv[ii], *sep;
92
93 sep = strchr (key, ':');
94
95 /* skip empty and invalid values */
96 if (sep)
97 g_hash_table_insert (credentials->priv->keys, g_strndup (key, sep - key), g_strdup (sep + 1));
98 }
99
100 return credentials;
101 }
102
103 /**
104 * e_credentials_new_args:
105 * @key: the first key name
106 * @...: value, followed by key,value pairs, terminated with %NULL
107 *
108 * Creates a new #ECredentials with prefilled keys. The arguments is
109 * a NULL-terminated list of string pairs <key, value>; value is in a clear form.
110 *
111 * Returns: (transfer full): a new #ECredentials. Free with e_credentials_free() when done with it.
112 *
113 * Since: 3.2
114 **/
115 ECredentials *
e_credentials_new_args(const gchar * key,...)116 e_credentials_new_args (const gchar *key,
117 ...)
118 {
119 ECredentials *credentials;
120 va_list va;
121
122 /* NULL-terminated list of string pairs <key, value>; value is
123 * in a clear form. */
124
125 g_return_val_if_fail (key != NULL, NULL);
126
127 credentials = e_credentials_new ();
128
129 va_start (va, key);
130
131 while (key) {
132 const gchar *value = va_arg (va, const gchar *);
133
134 if (key && *key && value && *value)
135 e_credentials_set (credentials, key, value);
136
137 key = va_arg (va, const gchar *);
138 }
139
140 va_end (va);
141
142 return credentials;
143 }
144
145 static void
copy_keys_cb(gpointer key,gpointer value,gpointer hash_table)146 copy_keys_cb (gpointer key,
147 gpointer value,
148 gpointer hash_table)
149 {
150 g_hash_table_insert (hash_table, g_strdup (key), g_strdup (value));
151 }
152
153 /**
154 * e_credentials_new_clone:
155 * @credentials: an #ECredentials
156 *
157 * Returns: (transfer full): Creates a clone (copy) of the given @credentials.
158 * Free with e_credentials_free() when done with it.
159 *
160 * Since: 3.2
161 **/
162 ECredentials *
e_credentials_new_clone(const ECredentials * credentials)163 e_credentials_new_clone (const ECredentials *credentials)
164 {
165 ECredentials *res;
166
167 g_return_val_if_fail (credentials != NULL, NULL);
168 g_return_val_if_fail (credentials->priv != NULL, NULL);
169 g_return_val_if_fail (credentials->priv->keys != NULL, NULL);
170
171 res = e_credentials_new ();
172
173 g_hash_table_foreach (credentials->priv->keys, copy_keys_cb, res->priv->keys);
174
175 return res;
176 }
177
178 /**
179 * e_credentials_free:
180 * @credentials: an #ECredentials
181 *
182 * Frees the @credentials. Any peek-ed values are invalidated
183 * by this call.
184 *
185 * Since: 3.2
186 **/
187 void
e_credentials_free(ECredentials * credentials)188 e_credentials_free (ECredentials *credentials)
189 {
190 if (!credentials)
191 return;
192
193 g_return_if_fail (credentials->priv != NULL);
194
195 g_hash_table_destroy (credentials->priv->keys);
196 g_hash_table_destroy (credentials->priv->peek_keys);
197 g_slice_free (ECredentialsPrivate, credentials->priv);
198 g_slice_free (ECredentials, credentials);
199 }
200
201 static void
add_to_array_cb(gpointer key,gpointer value,gpointer ptr_array)202 add_to_array_cb (gpointer key,
203 gpointer value,
204 gpointer ptr_array)
205 {
206 if (key && value && ptr_array) {
207 gchar *str = g_strconcat (key, ":", value, NULL);
208
209 g_ptr_array_add (ptr_array, e_util_utf8_make_valid (str));
210
211 g_free (str);
212 }
213 }
214
215 /**
216 * e_credentials_to_strv:
217 * @credentials: an #ECredentials
218 *
219 * Returns NULL-terminated array of strings with keys and encoded values;
220 * To read them back pass this pointer to e_credentials_new(). As it returns
221 * newly allocated string then this should be freed with g_strfreev() when no
222 * longer needed.
223 *
224 * Returns: (transfer full): a NULL-terminated array of key/value strings
225 *
226 * Since: 3.2
227 **/
228 gchar **
e_credentials_to_strv(const ECredentials * credentials)229 e_credentials_to_strv (const ECredentials *credentials)
230 {
231 GPtrArray *array;
232
233 g_return_val_if_fail (credentials != NULL, NULL);
234 g_return_val_if_fail (credentials->priv != NULL, NULL);
235 g_return_val_if_fail (credentials->priv->keys != NULL, NULL);
236
237 array = g_ptr_array_sized_new (g_hash_table_size (credentials->priv->keys) + 1);
238
239 g_hash_table_foreach (credentials->priv->keys, add_to_array_cb, array);
240
241 /* NULL-terminated */
242 g_ptr_array_add (array, NULL);
243
244 return (gchar **) g_ptr_array_free (array, FALSE);
245 }
246
247 static gchar *
encode_string(const gchar * decoded)248 encode_string (const gchar *decoded)
249 {
250 gsize len, ii;
251 guchar xval, *copy;
252 gchar *res;
253
254 if (!decoded || !*decoded)
255 return NULL;
256
257 copy = (guchar *) g_strdup (decoded);
258 len = strlen ((const gchar *) copy);
259
260 xval = 17;
261 for (ii = 0; ii < len; ii++) {
262 copy[ii] = copy[ii] ^ xval;
263 xval += 17;
264 }
265
266 res = g_base64_encode (copy, len);
267
268 g_free (copy);
269
270 return res;
271 }
272
273 static gchar *
decode_string(const gchar * encoded)274 decode_string (const gchar *encoded)
275 {
276 guchar *data, xval;
277 gsize len = 0, ii;
278 gchar *res;
279
280 g_return_val_if_fail (encoded != NULL, NULL);
281 g_return_val_if_fail (*encoded, NULL);
282
283 data = g_base64_decode (encoded, &len);
284 g_return_val_if_fail (data != NULL, NULL);
285 g_return_val_if_fail (len > 0, NULL);
286
287 xval = 17;
288 for (ii = 0; ii < len; ii++) {
289 data[ii] = data[ii] ^ xval;
290 xval += 17;
291 }
292
293 res = g_strndup ((const gchar *) data, len);
294
295 e_credentials_util_safe_free_string ((gchar *) data);
296
297 return res;
298 }
299
300 /**
301 * e_credentials_set:
302 * @credentials: an #ECredentials
303 * @key: a key string
304 * @value: a value string
305 *
306 * Sets value for @key, if @value is %NULL or an empty string then @key is
307 * removed. The value is supposed to be in a clear form (unencoded).
308 * @key cannot contain colon.
309 *
310 * Since: 3.2
311 **/
312 void
e_credentials_set(ECredentials * credentials,const gchar * key,const gchar * value)313 e_credentials_set (ECredentials *credentials,
314 const gchar *key,
315 const gchar *value)
316 {
317 g_return_if_fail (credentials != NULL);
318 g_return_if_fail (credentials->priv != NULL);
319 g_return_if_fail (credentials->priv->keys != NULL);
320 g_return_if_fail (credentials->priv->peek_keys != NULL);
321 g_return_if_fail (key != NULL);
322 g_return_if_fail (*key);
323 g_return_if_fail (strchr (key, ':') == NULL);
324
325 g_hash_table_remove (credentials->priv->peek_keys, key);
326
327 if (!value) {
328 g_hash_table_remove (credentials->priv->keys, key);
329 } else {
330 g_hash_table_insert (credentials->priv->keys, g_strdup (key), encode_string (value));
331 }
332 }
333
334 /**
335 * e_credentials_get:
336 * @credentials: an #ECredentials
337 * @key: a key name
338 *
339 * Returns: (transfer full) (nullable): A copy of the key's value, or %NULL,
340 * if no such key is stored in the @credentuals. Free returned string with
341 * e_credentials_util_safe_free_string(), when done with it.
342 *
343 * Since: 3.2
344 **/
345 gchar *
e_credentials_get(const ECredentials * credentials,const gchar * key)346 e_credentials_get (const ECredentials *credentials,
347 const gchar *key)
348 {
349 const gchar *stored;
350
351 /* Returned pointer should be freed with
352 * e_credentials_util_safe_free_string() when no longer needed. */
353
354 g_return_val_if_fail (credentials != NULL, NULL);
355 g_return_val_if_fail (credentials->priv != NULL, NULL);
356 g_return_val_if_fail (credentials->priv->keys != NULL, NULL);
357 g_return_val_if_fail (key != NULL, NULL);
358 g_return_val_if_fail (*key, NULL);
359
360 stored = g_hash_table_lookup (credentials->priv->keys, key);
361 if (!stored)
362 return NULL;
363
364 return decode_string (stored);
365 }
366
367 /**
368 * e_credentials_peek:
369 * @credentials: an #ECredentials
370 * @key: a key string
371 *
372 * Peeks at the value for @key, in a clear form. The returned value is valid
373 * until free of the @credentials structure or until the key value is rewritten
374 * by e_credentials_set().
375 *
376 * Returns: the value for @key
377 *
378 * Since: 3.2
379 **/
380 const gchar *
e_credentials_peek(ECredentials * credentials,const gchar * key)381 e_credentials_peek (ECredentials *credentials,
382 const gchar *key)
383 {
384 gchar *value;
385
386 g_return_val_if_fail (credentials != NULL, NULL);
387 g_return_val_if_fail (credentials->priv != NULL, NULL);
388 g_return_val_if_fail (credentials->priv->peek_keys != NULL, NULL);
389 g_return_val_if_fail (key != NULL, NULL);
390 g_return_val_if_fail (*key, NULL);
391
392 value = g_hash_table_lookup (credentials->priv->peek_keys, key);
393 if (value)
394 return value;
395
396 value = e_credentials_get (credentials, key);
397 if (value)
398 g_hash_table_insert (credentials->priv->peek_keys, g_strdup (key), value);
399
400 return value;
401 }
402
403 struct equal_data
404 {
405 gboolean equal;
406 GHashTable *keys;
407 };
408
409 static void
check_equal_cb(gpointer key,gpointer value,gpointer user_data)410 check_equal_cb (gpointer key,
411 gpointer value,
412 gpointer user_data)
413 {
414 struct equal_data *ed = user_data;
415
416 g_return_if_fail (ed != NULL);
417 g_return_if_fail (ed->keys != NULL);
418 g_return_if_fail (key != NULL);
419 g_return_if_fail (value != NULL);
420
421 ed->equal = ed->equal && g_strcmp0 (value, g_hash_table_lookup (ed->keys, key)) == 0;
422 }
423
424 /**
425 * e_credentials_equal:
426 * @credentials1: an #ECredentials
427 * @credentials2: another #ECredentials
428 *
429 * Returns whether two #ECredentials structures contain the same keys with
430 * same values.
431 *
432 * Returns: %TRUE if they are equal, %FALSE otherwise
433 *
434 * Since: 3.2
435 **/
436 gboolean
e_credentials_equal(const ECredentials * credentials1,const ECredentials * credentials2)437 e_credentials_equal (const ECredentials *credentials1,
438 const ECredentials *credentials2)
439 {
440 struct equal_data ed;
441
442 if (!credentials1 && !credentials2)
443 return TRUE;
444
445 if (credentials1 == credentials2)
446 return TRUE;
447
448 if (!credentials1 || !credentials2)
449 return FALSE;
450
451 g_return_val_if_fail (credentials1->priv != NULL, FALSE);
452 g_return_val_if_fail (credentials1->priv->keys != NULL, FALSE);
453 g_return_val_if_fail (credentials2->priv != NULL, FALSE);
454 g_return_val_if_fail (credentials2->priv->keys != NULL, FALSE);
455
456 if (g_hash_table_size (credentials1->priv->keys) != g_hash_table_size (credentials2->priv->keys))
457 return FALSE;
458
459 ed.equal = TRUE;
460 ed.keys = credentials2->priv->keys;
461
462 g_hash_table_foreach (credentials1->priv->keys, check_equal_cb, &ed);
463
464 return ed.equal;
465 }
466
467 /**
468 * e_credentials_equal_keys:
469 * @credentials1: an #ECredentials
470 * @credentials2: another #ECredentials
471 * @key1: the first key name
472 * @...: other key names, terminated with %NULL
473 *
474 * Returns whether two #ECredentials structures have the same keys. Key names
475 * are NULL-terminated.
476 *
477 * Returns: %TRUE if the key sets match, %FALSE otherwise
478 *
479 * Since: 3.2
480 **/
481 gboolean
e_credentials_equal_keys(const ECredentials * credentials1,const ECredentials * credentials2,const gchar * key1,...)482 e_credentials_equal_keys (const ECredentials *credentials1,
483 const ECredentials *credentials2,
484 const gchar *key1,
485 ...)
486 {
487 va_list va;
488 gboolean equal = TRUE;
489
490 g_return_val_if_fail (credentials1 != NULL, FALSE);
491 g_return_val_if_fail (credentials1->priv != NULL, FALSE);
492 g_return_val_if_fail (credentials1->priv->keys != NULL, FALSE);
493 g_return_val_if_fail (credentials2 != NULL, FALSE);
494 g_return_val_if_fail (credentials2->priv != NULL, FALSE);
495 g_return_val_if_fail (credentials2->priv->keys != NULL, FALSE);
496 g_return_val_if_fail (key1 != NULL, FALSE);
497
498 va_start (va, key1);
499
500 while (key1 && equal) {
501 equal = g_strcmp0 (g_hash_table_lookup (credentials1->priv->keys, key1), g_hash_table_lookup (credentials2->priv->keys, key1)) == 0;
502
503 key1 = va_arg (va, const gchar *);
504 }
505
506 va_end (va);
507
508 return equal;
509 }
510
511 /**
512 * e_credentials_has_key:
513 * @credentials: an #ECredentials
514 * @key: a key string
515 *
516 * Returns whether @credentials contains @key.
517 *
518 * Returns: %TRUE if @credentials contains @key, %FALSE otherwise
519 *
520 * Since: 3.2
521 **/
522 gboolean
e_credentials_has_key(const ECredentials * credentials,const gchar * key)523 e_credentials_has_key (const ECredentials *credentials,
524 const gchar *key)
525 {
526 g_return_val_if_fail (credentials != NULL, FALSE);
527 g_return_val_if_fail (credentials->priv != NULL, FALSE);
528 g_return_val_if_fail (credentials->priv->keys != NULL, FALSE);
529 g_return_val_if_fail (key != NULL, FALSE);
530 g_return_val_if_fail (*key, FALSE);
531
532 return g_hash_table_lookup (credentials->priv->keys, key) != NULL;
533 }
534
535 /**
536 * e_credentials_keys_size:
537 * @credentials: an #ECredentials
538 *
539 * Returns the number of keys in @credentials.
540 *
541 * Returns: the number of keys in @credentials
542 *
543 * Since: 3.2
544 **/
545 guint
e_credentials_keys_size(const ECredentials * credentials)546 e_credentials_keys_size (const ECredentials *credentials)
547 {
548 g_return_val_if_fail (credentials != NULL, 0);
549 g_return_val_if_fail (credentials->priv != NULL, 0);
550 g_return_val_if_fail (credentials->priv->keys != NULL, 0);
551
552 return g_hash_table_size (credentials->priv->keys);
553 }
554
555 static void
gather_key_names(gpointer key,gpointer value,gpointer pslist)556 gather_key_names (gpointer key,
557 gpointer value,
558 gpointer pslist)
559 {
560 GSList **slist = pslist;
561
562 g_return_if_fail (pslist != NULL);
563 g_return_if_fail (key != NULL);
564
565 *slist = g_slist_prepend (*slist, key);
566 }
567
568 /**
569 * e_credentials_list_keys:
570 * @credentials: an #ECredentials
571 *
572 * Returns a newly-allocated #GSList of key names stored in @credentials.
573 * The key names are internal credentials values and should not be modified
574 * or freed. Free the list with g_slist_free() when no longer needed.
575 *
576 * Returns: (transfer container) (element-type utf8): a newly-allocated #GSList
577 * of key names
578 *
579 * Since: 3.2
580 **/
581 GSList *
e_credentials_list_keys(const ECredentials * credentials)582 e_credentials_list_keys (const ECredentials *credentials)
583 {
584 GSList *keys = NULL;
585
586 g_return_val_if_fail (credentials != NULL, NULL);
587 g_return_val_if_fail (credentials->priv != NULL, NULL);
588 g_return_val_if_fail (credentials->priv->keys != NULL, NULL);
589
590 /* XXX g_hash_table_get_keys() would have been
591 * easier had we used #GList instead. */
592 g_hash_table_foreach (credentials->priv->keys, gather_key_names, &keys);
593
594 return g_slist_reverse (keys);
595 }
596
597 /**
598 * e_credentials_clear:
599 * @credentials: an #ECredentials
600 *
601 * Clears all the stored keys (and their peek-ed values).
602 *
603 * Since: 3.2
604 **/
605 void
e_credentials_clear(ECredentials * credentials)606 e_credentials_clear (ECredentials *credentials)
607 {
608 g_return_if_fail (credentials != NULL);
609 g_return_if_fail (credentials->priv != NULL);
610 g_return_if_fail (credentials->priv->keys != NULL);
611 g_return_if_fail (credentials->priv->peek_keys != NULL);
612
613 g_hash_table_remove_all (credentials->priv->peek_keys);
614 g_hash_table_remove_all (credentials->priv->keys);
615 }
616
617 /**
618 * e_credentials_clear_peek:
619 * @credentials: an #ECredentials
620 *
621 * Clears cache of peek-ed values.
622 *
623 * Since: 3.2
624 **/
625 void
e_credentials_clear_peek(ECredentials * credentials)626 e_credentials_clear_peek (ECredentials *credentials)
627 {
628 g_return_if_fail (credentials != NULL);
629 g_return_if_fail (credentials->priv != NULL);
630 g_return_if_fail (credentials->priv->peek_keys != NULL);
631
632 g_hash_table_remove_all (credentials->priv->peek_keys);
633 }
634
635 /**
636 * e_credentials_util_safe_free_string:
637 * @str: (nullable): a string to safely free
638 *
639 * Frees a nul-terminated string safely, which means it
640 * overwrites the content first and only then calls g_free()
641 * on it. If @str is %NULL, then does nothing.
642 *
643 * Since: 3.2
644 **/
645 void
e_credentials_util_safe_free_string(gchar * str)646 e_credentials_util_safe_free_string (gchar *str)
647 {
648 if (!str)
649 return;
650
651 if (*str)
652 memset (str, 0, sizeof (gchar) * strlen (str));
653
654 g_free (str);
655 }
656
657 static struct _PromptFlags {
658 ECredentialsPromptFlags flag_uint;
659 const gchar *flag_string;
660 gboolean is_bit_flag; /* if false, then checked against E_CREDENTIALS_PROMPT_FLAG_REMEMBER_MASK */
661 } PromptFlags[] = {
662 { E_CREDENTIALS_PROMPT_FLAG_REMEMBER_NEVER, "remember-never", FALSE },
663 { E_CREDENTIALS_PROMPT_FLAG_REMEMBER_SESSION, "remember-session", FALSE },
664 { E_CREDENTIALS_PROMPT_FLAG_REMEMBER_FOREVER, "remember-forever", FALSE },
665
666 { E_CREDENTIALS_PROMPT_FLAG_SECRET, "secret", TRUE },
667 { E_CREDENTIALS_PROMPT_FLAG_REPROMPT, "reprompt", TRUE },
668 { E_CREDENTIALS_PROMPT_FLAG_ONLINE, "online", TRUE },
669 { E_CREDENTIALS_PROMPT_FLAG_DISABLE_REMEMBER, "disable-remember", TRUE },
670 { E_CREDENTIALS_PROMPT_FLAG_PASSPHRASE, "passphrase", TRUE }
671 };
672
673 /**
674 * e_credentials_util_prompt_flags_to_string:
675 * @prompt_flags: bit-or of #ECredentialsPromptFlags
676 *
677 * Converts bit-or of # to a string representation. Use
678 * e_credentials_util_string_to_prompt_flags() to convert
679 * the string back to the numeric representation.
680 *
681 * Returns: (transfer full): text representation of the @prompt_flags
682 *
683 * Since: 3.2
684 **/
685 gchar *
e_credentials_util_prompt_flags_to_string(guint prompt_flags)686 e_credentials_util_prompt_flags_to_string (guint prompt_flags)
687 {
688 gint ii;
689 guint masked = prompt_flags & E_CREDENTIALS_PROMPT_FLAG_REMEMBER_MASK;
690 GString *str = g_string_new ("");
691
692 /* Returned pointer can be passed to
693 * e_credentials_util_string_to prompt_flags() to decode
694 * it back to flags. Free returned pointer with g_free(). */
695
696 for (ii = 0; ii < G_N_ELEMENTS (PromptFlags); ii++) {
697 const gchar *add = NULL;
698
699 if (PromptFlags[ii].is_bit_flag) {
700 if ((prompt_flags & PromptFlags[ii].flag_uint) != 0)
701 add = PromptFlags[ii].flag_string;
702 } else if (masked == PromptFlags[ii].flag_uint) {
703 add = PromptFlags[ii].flag_string;
704 }
705
706 if (!add)
707 continue;
708
709 if (str->len)
710 g_string_append_c (str, ',');
711
712 g_string_append (str, add);
713 }
714
715 return g_string_free (str, FALSE);
716 }
717
718 /**
719 * e_credentials_util_string_to_prompt_flags:
720 * @prompt_flags_string: flags encoded as string
721 *
722 * Converts #ECredentialsPromptFlags represented as string back to
723 * the numeric representation. This is a reverse function of
724 * e_credentials_util_prompt_flags_to_string().
725 *
726 * Returns: decoded bit-or of #ECredentialsPromptFlags
727 *
728 * Since: 3.2
729 **/
730 guint
e_credentials_util_string_to_prompt_flags(const gchar * prompt_flags_string)731 e_credentials_util_string_to_prompt_flags (const gchar *prompt_flags_string)
732 {
733 gchar **strv;
734 gint ii, jj;
735 guint flags = 0;
736
737 if (!prompt_flags_string || !*prompt_flags_string)
738 return flags;
739
740 strv = g_strsplit (prompt_flags_string, ",", -1);
741 if (!strv)
742 return flags;
743
744 for (jj = 0; strv[jj]; jj++) {
745 const gchar *str = strv[jj];
746
747 for (ii = 0; ii < G_N_ELEMENTS (PromptFlags); ii++) {
748 if (g_str_equal (PromptFlags[ii].flag_string, str)) {
749 if (PromptFlags[ii].is_bit_flag)
750 flags |= PromptFlags[ii].flag_uint;
751 else
752 flags = (flags & (~E_CREDENTIALS_PROMPT_FLAG_REMEMBER_MASK)) | PromptFlags[ii].flag_uint;
753 }
754 }
755 }
756
757 g_strfreev (strv);
758
759 return flags;
760 }
761