4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
21 #include <glib/gstdio.h>
22 #include <camel/camel.h>
23 #include <libsoup/soup.h>
25 /* XXX Yeah, yeah... */
26 #define SECRET_API_SUBJECT_TO_CHANGE
28 #include <libsecret/secret.h>
30 #include <libebackend/libebackend.h>
32 /* These constants are collected from various e-source-*.h files
33 * throughout evolution-data-server and known extension packages. */
34 #define E_SOURCE_GROUP_NAME "Data Source"
35 #define E_SOURCE_EXTENSION_CONTACTS_BACKEND "Contacts Backend"
36 #define E_SOURCE_EXTENSION_LDAP_BACKEND "LDAP Backend"
37 #define E_SOURCE_EXTENSION_LOCAL_BACKEND "Local Backend"
38 #define E_SOURCE_EXTENSION_VCF_BACKEND "VCF Backend"
39 #define E_SOURCE_EXTENSION_WEATHER_BACKEND "Weather Backend"
40 #define E_SOURCE_EXTENSION_WEBDAV_BACKEND "WebDAV Backend"
42 /* These constants are copied from e-source-password.c. */
43 #define KEYRING_ITEM_ATTRIBUTE_NAME "e-source-uid"
44 #define KEYRING_ITEM_DISPLAY_FORMAT "Evolution Data Source %s"
46 typedef struct _ParseData ParseData;
48 typedef void (*PropertyFunc) (ParseData *parse_data,
49 const gchar *property_name,
50 const gchar *property_value);
54 PARSE_TYPE_ADDRESSBOOK,
63 PARSE_STATE_IN_GCONF, /* GConf XML */
64 PARSE_STATE_IN_ACCOUNTS_ENTRY, /* GConf XML */
65 PARSE_STATE_IN_ACCOUNTS_VALUE, /* GConf XML */
66 PARSE_STATE_IN_SIGNATURES_ENTRY, /* GConf XML */
67 PARSE_STATE_IN_SIGNATURES_VALUE, /* GConf XML */
68 PARSE_STATE_IN_SOURCES_ENTRY, /* GConf XML */
69 PARSE_STATE_IN_SOURCES_VALUE, /* GConf XML */
71 PARSE_STATE_IN_ACCOUNT, /* EAccount XML */
72 PARSE_STATE_IN_IDENTITY, /* EAccount XML */
73 PARSE_STATE_IN_IDENTITY_NAME, /* EAccount XML */
74 PARSE_STATE_IN_IDENTITY_ADDR_SPEC, /* EAccount XML */
75 PARSE_STATE_IN_IDENTITY_REPLY_TO, /* EAccount XML */
76 PARSE_STATE_IN_IDENTITY_ORGANIZATION, /* EAccount XML */
77 PARSE_STATE_IN_IDENTITY_SIGNATURE, /* EAccount XML */
78 PARSE_STATE_IN_MAIL_SOURCE, /* EAccount XML */
79 PARSE_STATE_IN_MAIL_SOURCE_URL, /* EAccount XML */
80 PARSE_STATE_IN_MAIL_TRANSPORT, /* EAccount XML */
81 PARSE_STATE_IN_MAIL_TRANSPORT_URL, /* EAccount XML */
82 PARSE_STATE_IN_AUTO_CC, /* EAccount XML */
83 PARSE_STATE_IN_AUTO_CC_RECIPIENTS, /* EAccount XML */
84 PARSE_STATE_IN_AUTO_BCC, /* EAccount XML */
85 PARSE_STATE_IN_AUTO_BCC_RECIPIENTS, /* EAccount XML */
86 PARSE_STATE_IN_DRAFTS_FOLDER, /* EAccount XML */
87 PARSE_STATE_IN_SENT_FOLDER, /* EAccount XML */
88 PARSE_STATE_IN_RECEIPT_POLICY, /* EAccount XML */
89 PARSE_STATE_IN_PGP, /* EAccount XML */
90 PARSE_STATE_IN_PGP_KEY_ID, /* EAccount XML */
91 PARSE_STATE_IN_SMIME, /* EAccount XML */
92 PARSE_STATE_IN_SMIME_SIGN_KEY_ID, /* EAccount XML */
93 PARSE_STATE_IN_SMIME_ENCRYPT_KEY_ID, /* EAccount XML */
95 PARSE_STATE_IN_SIGNATURE, /* ESignature XML */
96 PARSE_STATE_IN_FILENAME, /* ESignature XML */
98 PARSE_STATE_IN_GROUP, /* ESource XML */
99 PARSE_STATE_IN_SOURCE, /* ESource XML */
100 PARSE_STATE_IN_PROPERTIES /* ESource XML */
107 /* Whether to skip writing a file
108 * for this account information. */
111 /* Set by <account>, <source> and <signature> tags. */
115 /* Set by <account>/<source> tags. */
119 /* Set by <identity> tags. */
120 GFile *identity_file;
121 GKeyFile *identity_key_file;
123 /* Set by <transport> tags. */
124 GFile *transport_file;
125 GKeyFile *transport_key_file;
127 /* Set by <account> tags. */
128 GFile *collection_file;
129 GKeyFile *collection_key_file;
131 /* Set by <signature> tags. */
132 GFile *signature_file;
135 /* Set by <group> tags. */
138 /* Set by <source> tags. */
141 PropertyFunc property_func;
144 /* XXX Probably want to share this with module-online-accounts.c */
145 static const SecretSchema schema = {
146 "org.gnome.Evolution.DataSource",
147 SECRET_SCHEMA_DONT_MATCH_NAME,
149 { KEYRING_ITEM_ATTRIBUTE_NAME,
150 SECRET_SCHEMA_ATTRIBUTE_STRING },
155 /* XXX Probably want to share this with e-passwords.c */
156 static const SecretSchema e_passwords_schema = {
157 "org.gnome.Evolution.Password",
158 SECRET_SCHEMA_DONT_MATCH_NAME,
160 { "application", SECRET_SCHEMA_ATTRIBUTE_STRING, },
161 { "user", SECRET_SCHEMA_ATTRIBUTE_STRING, },
162 { "server", SECRET_SCHEMA_ATTRIBUTE_STRING, },
163 { "protocol", SECRET_SCHEMA_ATTRIBUTE_STRING, },
167 /* Forward Declarations */
168 void evolution_source_registry_migrate_sources (void);
171 parse_data_new (ParseType parse_type)
173 ParseData *parse_data;
175 parse_data = g_slice_new0 (ParseData);
176 parse_data->type = parse_type;
177 parse_data->state = PARSE_STATE_INITIAL;
183 parse_data_free (ParseData *parse_data)
185 /* Normally the allocated data in ParseData is freed and the
186 * pointers are cleared before we get here. But if an error
187 * occurred we may leave data behind. This cleans it up. */
189 if (parse_data->file != NULL)
190 g_object_unref (parse_data->file);
192 if (parse_data->key_file != NULL)
193 g_key_file_free (parse_data->key_file);
195 if (parse_data->identity_file != NULL)
196 g_object_unref (parse_data->identity_file);
198 if (parse_data->identity_key_file != NULL)
199 g_key_file_free (parse_data->identity_key_file);
201 if (parse_data->transport_file != NULL)
202 g_object_unref (parse_data->transport_file);
204 if (parse_data->transport_key_file != NULL)
205 g_key_file_free (parse_data->transport_key_file);
207 if (parse_data->collection_file != NULL)
208 g_object_unref (parse_data->collection_file);
210 if (parse_data->collection_key_file != NULL)
211 g_key_file_free (parse_data->collection_key_file);
213 if (parse_data->signature_file != NULL)
214 g_object_unref (parse_data->signature_file);
216 g_free (parse_data->base_uri);
217 g_free (parse_data->mangled_uri);
219 if (parse_data->soup_uri != NULL)
220 soup_uri_free (parse_data->soup_uri);
222 g_slice_free (ParseData, parse_data);
226 is_true (const gchar *string)
228 return (g_ascii_strcasecmp (string, "1") == 0) ||
229 (g_ascii_strcasecmp (string, "true") == 0);
233 is_false (const gchar *string)
235 return (g_ascii_strcasecmp (string, "0") == 0) ||
236 (g_ascii_strcasecmp (string, "false") == 0);
240 base_uri_is_groupware (const gchar *base_uri)
242 /* Well-known scheme names from various groupware packages. */
244 /* We use a limited string comparsion here because the
245 * base_uri string may be 'scheme://' or just 'scheme'. */
247 g_return_val_if_fail (base_uri != NULL, FALSE);
249 if (g_ascii_strncasecmp (base_uri, "ews", 3) == 0)
252 if (g_ascii_strncasecmp (base_uri, "exchange", 8) == 0)
255 if (g_ascii_strncasecmp (base_uri, "groupwise", 9) == 0)
258 if (g_ascii_strncasecmp (base_uri, "kolab", 5) == 0)
261 if (g_ascii_strncasecmp (base_uri, "mapi", 4) == 0)
268 migrate_keyring_entry (const gchar *uid,
271 const gchar *protocol)
273 GHashTable *attributes;
274 GList *found_list = NULL;
277 /* Don't migrate entries with empty attributes */
278 if (!user || !server || !protocol) {
282 /* This is a best-effort routine, so we don't really care about
283 * errors. We leave the old keyring entry in place since it may
284 * be reused for address book or calendar migration. */
286 display_name = g_strdup_printf (KEYRING_ITEM_DISPLAY_FORMAT, uid);
288 attributes = secret_attributes_build (
290 "application", "Evolution",
293 "protocol", protocol,
296 found_list = secret_service_search_sync (
297 NULL, &e_passwords_schema, attributes,
299 SECRET_SEARCH_UNLOCK |
300 SECRET_SEARCH_LOAD_SECRETS,
303 /* Pick the first match we find. */
304 if (found_list != NULL) {
305 SecretItem *item = found_list->data;
306 SecretValue *secret = secret_item_get_secret (item);
309 g_return_if_fail (secret != NULL);
311 secret_password_store_sync (
312 &schema, SECRET_COLLECTION_DEFAULT, display_name,
313 secret_value_get (secret, NULL), NULL, NULL,
314 KEYRING_ITEM_ATTRIBUTE_NAME, uid, NULL);
316 secret_value_unref (secret);
319 g_list_free_full (found_list, g_object_unref);
320 g_hash_table_unref (attributes);
322 g_free (display_name);
326 migrate_parse_commit_changes (ParseType parse_type,
329 const gchar *mangled_uri,
332 const gchar *data_dir;
333 const gchar *cache_dir;
334 const gchar *component;
335 gchar *old_directory;
336 gchar *new_directory;
341 gboolean old_directory_exists;
342 gboolean new_directory_exists;
344 data_dir = e_get_user_data_dir ();
345 cache_dir = e_get_user_cache_dir ();
347 uid = e_server_side_source_uid_from_file (file, error);
352 g_print (" * Source: %s\n", uid);
354 g_print (" Writing key file...\n");
356 /* Save the key file contents to disk. */
357 contents = g_key_file_to_data (key_file, &length, NULL);
358 success = g_file_replace_contents (
359 file, contents, length, NULL, FALSE,
360 G_FILE_CREATE_PRIVATE, NULL, NULL, error);
366 /* Rename the source's local cache directory from its mangled
367 * URI to its UID. The key file's basename contains the UID.
368 * All source types but "local" should have cache directories. */
370 /* Mail cache directories already use UIDs. */
371 switch (parse_type) {
372 case PARSE_TYPE_ADDRESSBOOK:
373 component = "addressbook";
375 case PARSE_TYPE_CALENDAR:
376 component = "calendar";
378 case PARSE_TYPE_TASKS:
381 case PARSE_TYPE_MEMOS:
388 g_assert (mangled_uri != NULL);
390 old_directory = g_build_filename (
391 cache_dir, component, mangled_uri, NULL);
393 new_directory = g_build_filename (
394 cache_dir, component, uid, NULL);
396 old_directory_exists = g_file_test (old_directory, G_FILE_TEST_EXISTS);
397 new_directory_exists = g_file_test (new_directory, G_FILE_TEST_EXISTS);
400 " Checking for old cache dir '%s'... %s\n",
402 old_directory_exists ? "found" : "not found");
404 if (old_directory_exists) {
406 " Checking for new cache dir '%s'... %s\n",
408 new_directory_exists ? "found" : "not found");
410 if (new_directory_exists)
411 g_print (" Skipping cache directory rename.\n");
413 g_print (" Renaming old cache directory...\n");
414 if (g_rename (old_directory, new_directory) < 0) {
417 g_file_error_from_errno (errno),
418 "%s", g_strerror (errno));
424 g_free (old_directory);
425 g_free (new_directory);
430 /* Rename the source's local data directory from its mangled
431 * URI to its UID. The key file's basename contains the UID.
432 * Only "local" sources have local data directores. */
434 old_directory = g_build_filename (
435 data_dir, component, mangled_uri, NULL);
437 new_directory = g_build_filename (
438 data_dir, component, uid, NULL);
440 old_directory_exists = g_file_test (old_directory, G_FILE_TEST_EXISTS);
441 new_directory_exists = g_file_test (new_directory, G_FILE_TEST_EXISTS);
444 " Checking for old data dir '%s'... %s\n",
446 old_directory_exists ? "found" : "not found");
448 if (old_directory_exists) {
450 " Checking for new data dir '%s'... %s\n",
452 new_directory_exists ? "found" : "not found");
454 if (new_directory_exists)
455 g_print (" Skipping data directory rename.\n");
457 g_print (" Renaming old data directory...\n");
458 if (g_rename (old_directory, new_directory) < 0) {
461 g_file_error_from_errno (errno),
462 "%s", g_strerror (errno));
468 g_free (old_directory);
469 g_free (new_directory);
478 migrate_setup_collection (ParseData *parse_data,
481 gchar *collection_uid;
485 g_return_if_fail (parse_data->key_file != NULL);
486 g_return_if_fail (parse_data->identity_key_file != NULL);
487 g_return_if_fail (parse_data->transport_key_file != NULL);
489 parse_data->collection_file = e_server_side_source_new_user_file (NULL);
490 parse_data->collection_key_file = g_key_file_new ();
492 collection_uid = e_server_side_source_uid_from_file (
493 parse_data->collection_file, NULL);
495 /* Copy the display name from the mail account source. */
497 display_name = g_key_file_get_string (
498 parse_data->key_file,
499 E_SOURCE_GROUP_NAME, "DisplayName", NULL);
501 g_key_file_set_string (
502 parse_data->collection_key_file,
503 E_SOURCE_GROUP_NAME, "DisplayName", display_name);
505 /* Copy the enabled state from the mail account source. */
507 enabled = g_key_file_get_boolean (
508 parse_data->key_file,
509 E_SOURCE_GROUP_NAME, "Enabled", NULL);
511 g_key_file_set_boolean (
512 parse_data->collection_key_file,
513 E_SOURCE_GROUP_NAME, "Enabled", enabled);
515 /* Collection sources are always top-level sources. */
517 g_key_file_set_string (
518 parse_data->collection_key_file,
519 E_SOURCE_GROUP_NAME, "Parent", "");
521 /* Collection backend name should match the CamelURL protocol. */
523 g_key_file_set_string (
524 parse_data->collection_key_file,
525 E_SOURCE_EXTENSION_COLLECTION,
526 "BackendName", url->protocol);
528 g_key_file_set_boolean (
529 parse_data->collection_key_file,
530 E_SOURCE_EXTENSION_COLLECTION,
531 "CalendarEnabled", TRUE);
533 g_key_file_set_boolean (
534 parse_data->collection_key_file,
535 E_SOURCE_EXTENSION_COLLECTION,
536 "ContactsEnabled", TRUE);
538 g_key_file_set_boolean (
539 parse_data->collection_key_file,
540 E_SOURCE_EXTENSION_COLLECTION,
541 "MailEnabled", TRUE);
543 /* Enable all mail sources since we set "MailEnabled=true" above. */
545 g_key_file_set_boolean (
546 parse_data->key_file,
547 E_SOURCE_GROUP_NAME, "Enabled", TRUE);
549 g_key_file_set_boolean (
550 parse_data->identity_key_file,
551 E_SOURCE_GROUP_NAME, "Enabled", TRUE);
553 g_key_file_set_boolean (
554 parse_data->transport_key_file,
555 E_SOURCE_GROUP_NAME, "Enabled", TRUE);
557 /* The other mail sources are children of the collection source. */
559 g_key_file_set_string (
560 parse_data->key_file,
562 "Parent", collection_uid);
564 g_key_file_set_string (
565 parse_data->identity_key_file,
567 "Parent", collection_uid);
569 g_key_file_set_string (
570 parse_data->transport_key_file,
572 "Parent", collection_uid);
574 /* The collection identity has to be determined case-by-case.
575 * Some are based on user name, some are based on email address. */
577 if (g_strcmp0 (url->protocol, "ews") == 0)
578 g_key_file_set_string (
579 parse_data->collection_key_file,
580 E_SOURCE_EXTENSION_COLLECTION,
581 "Identity", url->user);
583 g_free (collection_uid);
584 g_free (display_name);
588 migrate_parse_account (ParseData *parse_data,
589 const gchar *element_name,
590 const gchar **attribute_names,
591 const gchar **attribute_values,
597 gchar *transport_uid;
601 success = g_markup_collect_attributes (
606 G_MARKUP_COLLECT_STRING,
608 G_MARKUP_COLLECT_STRING,
610 G_MARKUP_COLLECT_BOOLEAN,
612 G_MARKUP_COLLECT_INVALID);
617 parse_data->file = e_server_side_source_new_user_file (uid);
619 /* If the file already exists, skip this source. It may be that we
620 * already migrated it, in which case we don't want to overwrite it. */
621 if (g_file_query_exists (parse_data->file, NULL))
624 parse_data->key_file = g_key_file_new ();
626 parse_data->identity_file = e_server_side_source_new_user_file (NULL);
627 parse_data->identity_key_file = g_key_file_new ();
629 parse_data->transport_file = e_server_side_source_new_user_file (NULL);
630 parse_data->transport_key_file = g_key_file_new ();
632 identity_uid = e_server_side_source_uid_from_file (
633 parse_data->identity_file, NULL);
635 transport_uid = e_server_side_source_uid_from_file (
636 parse_data->transport_file, NULL);
638 g_key_file_set_string (
639 parse_data->key_file,
641 "DisplayName", name);
643 g_key_file_set_boolean (
644 parse_data->key_file,
648 /* Mail account source references the identity source. */
649 g_key_file_set_string (
650 parse_data->key_file,
651 E_SOURCE_EXTENSION_MAIL_ACCOUNT,
652 "IdentityUid", identity_uid);
654 /* Mail account source references the transport source. */
655 g_key_file_set_string (
656 parse_data->identity_key_file,
657 E_SOURCE_EXTENSION_MAIL_SUBMISSION,
658 "TransportUid", transport_uid);
660 /* Identity source gets the same display name. */
661 g_key_file_set_string (
662 parse_data->identity_key_file,
664 "DisplayName", name);
666 /* Identity source gets the same enabled state. */
667 g_key_file_set_boolean (
668 parse_data->identity_key_file,
672 /* Identity source is a child of the mail account. */
673 g_key_file_set_string (
674 parse_data->identity_key_file,
678 /* Transport source gets the same display name. */
679 g_key_file_set_string (
680 parse_data->transport_key_file,
682 "DisplayName", name);
684 /* Always enable the transport source, even if the mail account
685 * is disabled. Evolution does not currently honor the enabled
686 * setting on transports, so disabling the transport would only
687 * confuse matters should Evolution honor it in the future. */
688 g_key_file_set_boolean (
689 parse_data->transport_key_file,
693 /* Transport source is a child of the mail account. */
694 g_key_file_set_string (
695 parse_data->transport_key_file,
699 g_free (identity_uid);
700 g_free (transport_uid);
704 migrate_parse_pgp (ParseData *parse_data,
705 const gchar *element_name,
706 const gchar **attribute_names,
707 const gchar **attribute_values,
710 const gchar *hash_algo;
711 gboolean always_sign;
712 gboolean always_trust;
713 gboolean encrypt_to_self;
714 gboolean no_imip_sign;
717 success = g_markup_collect_attributes (
722 G_MARKUP_COLLECT_BOOLEAN,
723 "always-sign", &always_sign,
724 G_MARKUP_COLLECT_BOOLEAN,
725 "always-trust", &always_trust,
726 G_MARKUP_COLLECT_BOOLEAN,
727 "encrypt-to-self", &encrypt_to_self,
728 G_MARKUP_COLLECT_BOOLEAN,
729 "no-imip-sign", &no_imip_sign,
730 G_MARKUP_COLLECT_STRING |
731 G_MARKUP_COLLECT_OPTIONAL,
732 "hash-algo", &hash_algo,
733 G_MARKUP_COLLECT_INVALID);
738 g_key_file_set_boolean (
739 parse_data->identity_key_file,
740 E_SOURCE_EXTENSION_OPENPGP,
741 "AlwaysSign", always_sign);
743 g_key_file_set_boolean (
744 parse_data->identity_key_file,
745 E_SOURCE_EXTENSION_OPENPGP,
746 "AlwaysTrust", always_trust);
748 g_key_file_set_boolean (
749 parse_data->identity_key_file,
750 E_SOURCE_EXTENSION_OPENPGP,
751 "EncryptToSelf", encrypt_to_self);
753 if (hash_algo != NULL && *hash_algo != '\0')
754 g_key_file_set_string (
755 parse_data->identity_key_file,
756 E_SOURCE_EXTENSION_OPENPGP,
757 "SigningAlgorithm", hash_algo);
759 /* XXX Don't know why this is under the <pgp>
760 * element, it applies to S/MIME as well.
761 * Also note we're inverting the setting. */
762 g_key_file_set_boolean (
763 parse_data->identity_key_file,
764 E_SOURCE_EXTENSION_MAIL_COMPOSITION,
765 "SignImip", !no_imip_sign);
769 migrate_parse_recipients (ParseData *parse_data,
771 const gchar *recipients)
773 CamelAddress *address;
774 CamelInternetAddress *inet_address;
779 if (recipients == NULL || *recipients == '\0')
782 inet_address = camel_internet_address_new ();
783 address = CAMEL_ADDRESS (inet_address);
785 if (camel_address_decode (address, recipients) == -1)
788 length = camel_address_length (address);
789 string_list = g_new0 (gchar *, length + 1);
791 for (ii = 0; ii < length; ii++) {
792 const gchar *name, *addr;
794 if (!camel_internet_address_get (
795 inet_address, ii, &name, &addr))
798 string_list[index++] =
799 camel_internet_address_format_address (name, addr);
802 g_key_file_set_string_list (
803 parse_data->identity_key_file,
804 E_SOURCE_EXTENSION_MAIL_COMPOSITION, key,
805 (const gchar *const *) string_list, index);
807 g_strfreev (string_list);
810 g_object_unref (inet_address);
814 migrate_parse_smime (ParseData *parse_data,
815 const gchar *element_name,
816 const gchar **attribute_names,
817 const gchar **attribute_values,
820 const gchar *hash_algo;
821 gboolean encrypt_default;
822 gboolean encrypt_to_self;
823 gboolean sign_default;
826 success = g_markup_collect_attributes (
831 G_MARKUP_COLLECT_BOOLEAN,
832 "encrypt-default", &encrypt_default,
833 G_MARKUP_COLLECT_BOOLEAN,
834 "encrypt-to-self", &encrypt_to_self,
835 G_MARKUP_COLLECT_STRING |
836 G_MARKUP_COLLECT_OPTIONAL,
837 "hash-algo", &hash_algo,
838 G_MARKUP_COLLECT_BOOLEAN,
839 "sign-default", &sign_default,
840 G_MARKUP_COLLECT_INVALID);
845 g_key_file_set_boolean (
846 parse_data->identity_key_file,
847 E_SOURCE_EXTENSION_SMIME,
848 "EncryptByDefault", encrypt_default);
850 g_key_file_set_boolean (
851 parse_data->identity_key_file,
852 E_SOURCE_EXTENSION_SMIME,
853 "EncryptToSelf", encrypt_to_self);
855 if (hash_algo != NULL && *hash_algo != '\0')
856 g_key_file_set_string (
857 parse_data->identity_key_file,
858 E_SOURCE_EXTENSION_SMIME,
859 "SigningAlgorithm", hash_algo);
861 g_key_file_set_boolean (
862 parse_data->identity_key_file,
863 E_SOURCE_EXTENSION_SMIME,
864 "SignByDefault", sign_default);
868 migrate_parse_mail_source (ParseData *parse_data,
869 const gchar *element_name,
870 const gchar **attribute_names,
871 const gchar **attribute_values,
874 const gchar *auto_check_timeout;
875 glong interval_minutes = 0;
879 /* Disregard "keep-on-server" and "save-passwd" attributes. */
880 success = g_markup_collect_attributes (
885 G_MARKUP_COLLECT_BOOLEAN,
886 "auto-check", &auto_check,
887 G_MARKUP_COLLECT_STRING,
888 "auto-check-timeout", &auto_check_timeout,
889 G_MARKUP_COLLECT_BOOLEAN |
890 G_MARKUP_COLLECT_OPTIONAL,
891 "keep-on-server", NULL,
892 G_MARKUP_COLLECT_BOOLEAN |
893 G_MARKUP_COLLECT_OPTIONAL,
895 G_MARKUP_COLLECT_INVALID);
900 if (auto_check_timeout != NULL)
901 interval_minutes = strtol (auto_check_timeout, NULL, 10);
903 g_key_file_set_boolean (
904 parse_data->key_file,
905 E_SOURCE_EXTENSION_REFRESH,
906 "Enabled", auto_check);
908 if (interval_minutes > 0)
909 g_key_file_set_integer (
910 parse_data->key_file,
911 E_SOURCE_EXTENSION_REFRESH,
912 "IntervalMinutes", interval_minutes);
916 migrate_parse_url_rename_params (CamelURL *url)
918 /* This list includes known URL parameters from built-in providers
919 * in Camel, as well as from evolution-exchange/groupwise/mapi/ews.
920 * Add more as needed. */
922 const gchar *url_parameter;
923 const gchar *property_name;
924 } camel_url_conversion[] = {
925 { "account_uid", "account-uid" },
926 { "ad_auth", "gc-auth-method" },
927 { "ad_browse", "gc-allow-browse" },
928 { "ad_expand_groups", "gc-expand-groups" },
929 { "ad_limit", "gc-results-limit" },
930 { "ad_server", "gc-server-name" },
931 { "all_headers", "fetch-headers" },
932 { "basic_headers", "fetch-headers" },
933 { "cachedconn" "concurrent-connections" },
934 { "check_all", "check-all" },
935 { "check_lsub", "check-subscribed" },
936 { "command", "shell-command" },
937 { "delete_after", "delete-after-days" },
938 { "delete_expunged", "delete-expunged" },
939 { "disable_extensions", "disable-extensions" },
940 { "dotfolders", "use-dot-folders" },
941 { "filter", "filter-inbox" },
942 { "filter_junk", "filter-junk" },
943 { "filter_junk_inbox", "filter-junk-inbox" },
944 { "folder_hierarchy_relative", "folder-hierarchy-relative" },
945 { "imap_custom_headers", "fetch-headers-extra" },
946 { "keep_on_server", "keep-on-server" },
947 { "oab_offline", "oab-offline" },
948 { "oal_selected", "oal-selected" },
949 { "offline_sync", "stay-synchronized" },
950 { "override_namespace", "use-namespace" },
951 { "owa_path", "owa-path" },
952 { "owa_url", "owa-url" },
953 { "password_exp_warn_period", "password-exp-warn-period" },
954 { "real_junk_path", "real-junk-path" },
955 { "real_trash_path", "real-trash-path" },
956 { "show_short_notation", "short-folder-names" },
957 { "soap_port", "soap-port" },
958 { "ssl", "security-method" },
959 { "sync_offline", "stay-synchronized" },
960 { "use_command", "use-shell-command" },
961 { "use_idle", "use-idle" },
962 { "use_lsub", "use-subscriptions" },
963 { "use_qresync", "use-qresync" },
964 { "use_ssl", "security-method" },
965 { "xstatus", "use-xstatus-headers" }
969 const gchar *use_param;
972 for (ii = 0; ii < G_N_ELEMENTS (camel_url_conversion); ii++) {
976 key = camel_url_conversion[ii].url_parameter;
977 value = g_datalist_get_data (&url->params, key);
982 g_datalist_remove_no_notify (&url->params, key);
984 key = camel_url_conversion[ii].property_name;
986 /* Deal with a few special enum cases where
987 * the parameter value also needs renamed. */
989 if (strcmp (key, "all_headers") == 0) {
990 GEnumClass *enum_class;
991 GEnumValue *enum_value;
993 enum_class = g_type_class_ref (
994 CAMEL_TYPE_FETCH_HEADERS_TYPE);
995 enum_value = g_enum_get_value (
996 enum_class, CAMEL_FETCH_HEADERS_ALL);
997 if (enum_value != NULL) {
999 value = g_strdup (enum_value->value_nick);
1001 g_warn_if_reached ();
1002 g_type_class_unref (enum_class);
1005 if (strcmp (key, "basic_headers") == 0) {
1006 GEnumClass *enum_class;
1007 GEnumValue *enum_value;
1009 enum_class = g_type_class_ref (
1010 CAMEL_TYPE_FETCH_HEADERS_TYPE);
1011 enum_value = g_enum_get_value (
1012 enum_class, CAMEL_FETCH_HEADERS_BASIC);
1013 if (enum_value != NULL) {
1015 value = g_strdup (enum_value->value_nick);
1017 g_warn_if_reached ();
1018 g_type_class_unref (enum_class);
1021 if (strcmp (key, "imap_custom_headers") == 0)
1022 g_strdelimit (value, " ", ',');
1024 if (strcmp (key, "security-method") == 0) {
1025 CamelNetworkSecurityMethod method;
1026 GEnumClass *enum_class;
1027 GEnumValue *enum_value;
1029 if (strcmp (value, "always") == 0)
1030 method = CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT;
1031 else if (strcmp (value, "1") == 0)
1032 method = CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT;
1033 else if (strcmp (value, "when-possible") == 0)
1034 method = CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT;
1036 method = CAMEL_NETWORK_SECURITY_METHOD_NONE;
1038 enum_class = g_type_class_ref (
1039 CAMEL_TYPE_NETWORK_SECURITY_METHOD);
1040 enum_value = g_enum_get_value (enum_class, method);
1041 if (enum_value != NULL) {
1043 value = g_strdup (enum_value->value_nick);
1045 g_warn_if_reached ();
1046 g_type_class_unref (enum_class);
1049 g_datalist_set_data_full (&url->params, key, value, g_free);
1052 /* missing "security-method" means STARTTLS, as it was the default value in 3.4- */
1053 if (!g_datalist_get_data (&url->params, "security-method")) {
1054 GEnumClass *enum_class;
1055 GEnumValue *enum_value;
1056 gchar *value = NULL;
1058 enum_class = g_type_class_ref (CAMEL_TYPE_NETWORK_SECURITY_METHOD);
1059 enum_value = g_enum_get_value (
1061 CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT);
1062 if (enum_value != NULL) {
1063 value = g_strdup (enum_value->value_nick);
1065 g_warn_if_reached ();
1066 g_type_class_unref (enum_class);
1068 g_datalist_set_data_full (&url->params, "security-method", value, g_free);
1071 /* A few more adjustments...
1073 * These are all CAMEL_PROVIDER_CONF_CHECKSPIN settings. The spin
1074 * button value is bound to "param" and the checkbox state is bound
1075 * to "use-param". The "use-param" settings are new. If "param"
1076 * exists but no "use-param", then set "use-param" to "true". */
1078 param = g_datalist_get_data (&url->params, "gc-results-limit");
1079 use_param = g_datalist_get_data (&url->params, "use-gc-results-limit");
1080 if (param != NULL && *param != '\0' && use_param == NULL) {
1081 g_datalist_set_data_full (
1082 &url->params, "use-gc-results-limit",
1083 g_strdup ("true"), (GDestroyNotify) g_free);
1086 param = g_datalist_get_data (&url->params, "kerberos");
1087 if (g_strcmp0 (param, "required") == 0) {
1088 g_datalist_set_data_full (
1089 &url->params, "kerberos",
1090 g_strdup ("true"), (GDestroyNotify) g_free);
1093 param = g_datalist_get_data (
1094 &url->params, "password-exp-warn-period");
1095 use_param = g_datalist_get_data (
1096 &url->params, "use-password-exp-warn-period");
1097 if (param != NULL && *param != '\0' && use_param == NULL) {
1098 g_datalist_set_data_full (
1099 &url->params, "use-password-exp-warn-period",
1100 g_strdup ("true"), (GDestroyNotify) g_free);
1103 param = g_datalist_get_data (&url->params, "real-junk-path");
1104 use_param = g_datalist_get_data (&url->params, "use-real-junk-path");
1105 if (param != NULL && *param != '\0' && use_param == NULL) {
1106 g_datalist_set_data_full (
1107 &url->params, "use-real-junk-path",
1108 g_strdup ("true"), (GDestroyNotify) g_free);
1111 param = g_datalist_get_data (&url->params, "real-trash-path");
1112 use_param = g_datalist_get_data (&url->params, "use-real-trash-path");
1113 if (param != NULL && *param != '\0' && use_param == NULL) {
1114 g_datalist_set_data_full (
1115 &url->params, "use-real-trash-path",
1116 g_strdup ("true"), (GDestroyNotify) g_free);
1119 /* Remove an empty "namespace" parameter (if present) to avoid
1120 * it being converted to "true" in migrate_parse_url_foreach(). */
1121 param = g_datalist_get_data (&url->params, "namespace");
1122 if (param != NULL && *param == '\0')
1123 g_datalist_remove_data (&url->params, "namespace");
1127 migrate_parse_url_foreach (GQuark key_id,
1131 const gchar *param_name;
1136 const gchar *group_name;
1137 } *foreach_data = user_data;
1139 g_return_if_fail (value != NULL);
1141 param_name = g_quark_to_string (key_id);
1142 key = e_source_parameter_to_key (param_name);
1144 /* If the value is empty, then the mere
1145 * presence of the parameter implies TRUE. */
1149 g_key_file_set_string (
1150 foreach_data->key_file,
1151 foreach_data->group_name,
1156 migrate_parse_url (ParseData *parse_data,
1159 const gchar *group_name,
1160 const gchar *url_string,
1164 GKeyFile *backend_key_file;
1165 GFile *backend_file;
1167 gboolean setup_collection;
1172 const gchar *group_name;
1175 url = camel_url_new (url_string, error);
1176 if (url == NULL || url->protocol == NULL)
1179 /* Rename URL params as necessary to match
1180 * their ESourceExtension property names. */
1181 migrate_parse_url_rename_params (url);
1184 (key_file == parse_data->key_file) &&
1185 base_uri_is_groupware (url->protocol);
1187 if (setup_collection)
1188 migrate_setup_collection (parse_data, url);
1190 /* Store backend settings in the collection GKeyFile, if one is
1191 * defined. Otherwise store them in the GKeyFile we were passed.
1192 * Same goes for the keyring entry, which uses the GFile. */
1193 if (parse_data->collection_key_file != NULL) {
1194 backend_key_file = parse_data->collection_key_file;
1195 backend_file = parse_data->collection_file;
1197 backend_key_file = key_file;
1198 backend_file = file;
1201 /* This is not a backend setting. */
1202 g_key_file_set_string (
1203 key_file, group_name,
1204 "BackendName", url->protocol);
1206 /* Set authentication details. */
1208 if (url->host != NULL)
1209 g_key_file_set_string (
1211 E_SOURCE_EXTENSION_AUTHENTICATION,
1214 if (url->authmech != NULL)
1215 g_key_file_set_string (
1217 E_SOURCE_EXTENSION_AUTHENTICATION,
1218 "Method", url->authmech);
1221 g_key_file_set_integer (
1223 E_SOURCE_EXTENSION_AUTHENTICATION,
1226 if (url->user != NULL)
1227 g_key_file_set_string (
1229 E_SOURCE_EXTENSION_AUTHENTICATION,
1232 /* Pick out particular URL parameters we know about. */
1234 /* If set, this should be "true" or "false",
1235 * but we'll just write it like it's a string. */
1236 value = g_datalist_get_data (&url->params, "stay-synchronized");
1238 g_key_file_set_string (
1240 E_SOURCE_EXTENSION_OFFLINE,
1241 "StaySynchronized", value);
1242 g_datalist_set_data (&url->params, "stay-synchronized", NULL);
1244 value = g_datalist_get_data (&url->params, "security-method");
1246 g_key_file_set_string (
1248 E_SOURCE_EXTENSION_SECURITY,
1250 g_datalist_set_data (&url->params, "security-method", NULL);
1252 /* If we see a "goa-account-id" parameter, skip the entire
1253 * account and let the online-accounts module recreate it. */
1254 value = g_datalist_get_data (&url->params, "goa-account-id");
1255 if (value != NULL && *value != '\0')
1256 parse_data->skip = TRUE;
1258 /* The rest of the URL parameters go in the backend group. */
1260 group_name = e_source_camel_get_extension_name (url->protocol);
1262 foreach_data.key_file = backend_key_file;
1263 foreach_data.group_name = group_name;
1265 g_datalist_foreach (
1266 &url->params, (GDataForeachFunc)
1267 migrate_parse_url_foreach, &foreach_data);
1269 /* Local providers store their "path" as the url->path */
1270 if (g_strcmp0 (url->protocol, "mh") == 0 ||
1271 g_strcmp0 (url->protocol, "mbox") == 0 ||
1272 g_strcmp0 (url->protocol, "maildir") == 0 ||
1273 g_strcmp0 (url->protocol, "spool") == 0 ||
1274 g_strcmp0 (url->protocol, "spooldir") == 0)
1275 g_key_file_set_string (
1280 uid = e_server_side_source_uid_from_file (backend_file, error);
1283 migrate_keyring_entry (
1284 uid, url->user, url->host, url->protocol);
1288 camel_url_free (url);
1292 migrate_parse_account_xml_start_element (GMarkupParseContext *context,
1293 const gchar *element_name,
1294 const gchar **attribute_names,
1295 const gchar **attribute_values,
1299 ParseData *parse_data = user_data;
1301 if (g_strcmp0 (element_name, "account") == 0) {
1302 if (parse_data->state != PARSE_STATE_IN_ACCOUNTS_VALUE)
1303 goto invalid_content;
1305 parse_data->state = PARSE_STATE_IN_ACCOUNT;
1307 migrate_parse_account (
1317 if (g_strcmp0 (element_name, "addr-spec") == 0) {
1318 if (parse_data->state != PARSE_STATE_IN_IDENTITY)
1319 goto invalid_content;
1321 parse_data->state = PARSE_STATE_IN_IDENTITY_ADDR_SPEC;
1326 if (g_strcmp0 (element_name, "auto-bcc") == 0) {
1327 if (parse_data->state != PARSE_STATE_IN_ACCOUNT)
1328 goto invalid_content;
1330 parse_data->state = PARSE_STATE_IN_AUTO_BCC;
1332 g_markup_collect_attributes (
1337 G_MARKUP_COLLECT_BOOLEAN,
1338 "always", &parse_data->auto_bcc,
1339 G_MARKUP_COLLECT_INVALID);
1344 if (g_strcmp0 (element_name, "auto-cc") == 0) {
1345 if (parse_data->state != PARSE_STATE_IN_ACCOUNT)
1346 goto invalid_content;
1348 parse_data->state = PARSE_STATE_IN_AUTO_CC;
1350 g_markup_collect_attributes (
1355 G_MARKUP_COLLECT_BOOLEAN,
1356 "always", &parse_data->auto_cc,
1357 G_MARKUP_COLLECT_INVALID);
1362 if (g_strcmp0 (element_name, "drafts-folder") == 0) {
1363 if (parse_data->state != PARSE_STATE_IN_ACCOUNT)
1364 goto invalid_content;
1366 parse_data->state = PARSE_STATE_IN_DRAFTS_FOLDER;
1371 if (g_strcmp0 (element_name, "encrypt-key-id") == 0) {
1372 if (parse_data->state != PARSE_STATE_IN_SMIME)
1373 goto invalid_content;
1375 parse_data->state = PARSE_STATE_IN_SMIME_ENCRYPT_KEY_ID;
1380 if (g_strcmp0 (element_name, "identity") == 0) {
1381 if (parse_data->state != PARSE_STATE_IN_ACCOUNT)
1382 goto invalid_content;
1384 parse_data->state = PARSE_STATE_IN_IDENTITY;
1389 if (g_strcmp0 (element_name, "key-id") == 0) {
1390 if (parse_data->state != PARSE_STATE_IN_PGP)
1391 goto invalid_content;
1393 parse_data->state = PARSE_STATE_IN_PGP_KEY_ID;
1398 if (g_strcmp0 (element_name, "name") == 0) {
1399 if (parse_data->state != PARSE_STATE_IN_IDENTITY)
1400 goto invalid_content;
1402 parse_data->state = PARSE_STATE_IN_IDENTITY_NAME;
1407 if (g_strcmp0 (element_name, "reply-to") == 0) {
1408 if (parse_data->state != PARSE_STATE_IN_IDENTITY)
1409 goto invalid_content;
1411 parse_data->state = PARSE_STATE_IN_IDENTITY_REPLY_TO;
1416 if (g_strcmp0 (element_name, "organization") == 0) {
1417 if (parse_data->state != PARSE_STATE_IN_IDENTITY)
1418 goto invalid_content;
1420 parse_data->state = PARSE_STATE_IN_IDENTITY_ORGANIZATION;
1425 if (g_strcmp0 (element_name, "pgp") == 0) {
1426 if (parse_data->state != PARSE_STATE_IN_ACCOUNT)
1427 goto invalid_content;
1429 parse_data->state = PARSE_STATE_IN_PGP;
1441 if (g_strcmp0 (element_name, "receipt-policy") == 0) {
1442 const gchar *policy;
1445 if (parse_data->state != PARSE_STATE_IN_ACCOUNT)
1446 goto invalid_content;
1448 parse_data->state = PARSE_STATE_IN_RECEIPT_POLICY;
1450 success = g_markup_collect_attributes (
1455 G_MARKUP_COLLECT_STRING,
1457 G_MARKUP_COLLECT_INVALID);
1459 /* The new enum strings match the old ones. */
1460 if (success && policy != NULL)
1461 g_key_file_set_string (
1462 parse_data->key_file,
1463 E_SOURCE_EXTENSION_MDN,
1464 "ResponsePolicy", policy);
1469 if (g_strcmp0 (element_name, "recipients") == 0) {
1470 if (parse_data->state == PARSE_STATE_IN_AUTO_BCC) {
1471 parse_data->state = PARSE_STATE_IN_AUTO_BCC_RECIPIENTS;
1475 if (parse_data->state == PARSE_STATE_IN_AUTO_CC) {
1476 parse_data->state = PARSE_STATE_IN_AUTO_CC_RECIPIENTS;
1480 goto invalid_content;
1483 if (g_strcmp0 (element_name, "sent-folder") == 0) {
1484 if (parse_data->state != PARSE_STATE_IN_ACCOUNT)
1485 goto invalid_content;
1487 parse_data->state = PARSE_STATE_IN_SENT_FOLDER;
1492 if (g_strcmp0 (element_name, "signature") == 0) {
1496 if (parse_data->state != PARSE_STATE_IN_IDENTITY)
1497 goto invalid_content;
1499 parse_data->state = PARSE_STATE_IN_IDENTITY_SIGNATURE;
1501 success = g_markup_collect_attributes (
1506 G_MARKUP_COLLECT_STRING,
1508 G_MARKUP_COLLECT_INVALID);
1510 if (success && uid != NULL)
1511 g_key_file_set_string (
1512 parse_data->identity_key_file,
1513 E_SOURCE_EXTENSION_MAIL_IDENTITY,
1514 "SignatureUid", uid);
1519 if (g_strcmp0 (element_name, "sign-key-id") == 0) {
1520 if (parse_data->state != PARSE_STATE_IN_SMIME)
1521 goto invalid_content;
1523 parse_data->state = PARSE_STATE_IN_SMIME_SIGN_KEY_ID;
1528 if (g_strcmp0 (element_name, "smime") == 0) {
1529 if (parse_data->state != PARSE_STATE_IN_ACCOUNT)
1530 goto invalid_content;
1532 parse_data->state = PARSE_STATE_IN_SMIME;
1534 migrate_parse_smime (
1544 if (g_strcmp0 (element_name, "source") == 0) {
1545 if (parse_data->state != PARSE_STATE_IN_ACCOUNT)
1546 goto invalid_content;
1548 parse_data->state = PARSE_STATE_IN_MAIL_SOURCE;
1550 migrate_parse_mail_source (
1560 if (g_strcmp0 (element_name, "transport") == 0) {
1561 if (parse_data->state != PARSE_STATE_IN_ACCOUNT)
1562 goto invalid_content;
1564 parse_data->state = PARSE_STATE_IN_MAIL_TRANSPORT;
1569 if (g_strcmp0 (element_name, "url") == 0) {
1570 if (parse_data->state == PARSE_STATE_IN_MAIL_SOURCE) {
1571 parse_data->state = PARSE_STATE_IN_MAIL_SOURCE_URL;
1575 if (parse_data->state == PARSE_STATE_IN_MAIL_TRANSPORT) {
1576 parse_data->state = PARSE_STATE_IN_MAIL_TRANSPORT_URL;
1580 goto invalid_content;
1584 error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1585 "Unknown element <%s>", element_name);
1592 error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1593 "Element <%s> at unexpected location", element_name);
1597 migrate_parse_account_xml_end_element (GMarkupParseContext *context,
1598 const gchar *element_name,
1602 ParseData *parse_data = user_data;
1604 if (g_strcmp0 (element_name, "account") == 0) {
1605 if (parse_data->state == PARSE_STATE_IN_ACCOUNT) {
1606 parse_data->state = PARSE_STATE_IN_ACCOUNTS_VALUE;
1608 /* Clean up <account> tag data. */
1610 /* The key file will be NULL if we decided to skip it.
1611 * e.g. A file with the same UID may already exist. */
1612 if (parse_data->key_file != NULL) {
1613 GError *local_error = NULL;
1615 if (!parse_data->skip)
1616 migrate_parse_commit_changes (
1619 parse_data->key_file,
1620 NULL, &local_error);
1622 if (local_error != NULL) {
1625 local_error->message);
1626 g_error_free (local_error);
1629 g_key_file_free (parse_data->key_file);
1630 parse_data->key_file = NULL;
1633 /* Same deal for the identity key file. */
1634 if (parse_data->identity_key_file != NULL) {
1635 GError *local_error = NULL;
1637 if (!parse_data->skip)
1638 migrate_parse_commit_changes (
1640 parse_data->identity_file,
1641 parse_data->identity_key_file,
1642 NULL, &local_error);
1644 if (local_error != NULL) {
1647 local_error->message);
1648 g_error_free (local_error);
1651 g_key_file_free (parse_data->identity_key_file);
1652 parse_data->identity_key_file = NULL;
1655 /* Same deal for the transport key file. */
1656 if (parse_data->transport_key_file != NULL) {
1657 GError *local_error = NULL;
1659 if (!parse_data->skip)
1660 migrate_parse_commit_changes (
1662 parse_data->transport_file,
1663 parse_data->transport_key_file,
1664 NULL, &local_error);
1666 if (local_error != NULL) {
1669 local_error->message);
1670 g_error_free (local_error);
1673 g_key_file_free (parse_data->transport_key_file);
1674 parse_data->transport_key_file = NULL;
1677 /* The collection key file is optional anyway. */
1678 if (parse_data->collection_key_file != NULL) {
1679 GError *local_error = NULL;
1681 if (!parse_data->skip)
1682 migrate_parse_commit_changes (
1684 parse_data->collection_file,
1685 parse_data->collection_key_file,
1686 NULL, &local_error);
1688 if (local_error != NULL) {
1691 local_error->message);
1692 g_error_free (local_error);
1695 g_key_file_free (parse_data->collection_key_file);
1696 parse_data->collection_key_file = NULL;
1699 if (parse_data->file != NULL) {
1700 g_object_unref (parse_data->file);
1701 parse_data->file = NULL;
1704 if (parse_data->identity_file != NULL) {
1705 g_object_unref (parse_data->identity_file);
1706 parse_data->identity_file = NULL;
1709 if (parse_data->transport_file != NULL) {
1710 g_object_unref (parse_data->transport_file);
1711 parse_data->transport_file = NULL;
1714 if (parse_data->collection_file != NULL) {
1715 g_object_unref (parse_data->collection_file);
1716 parse_data->collection_file = NULL;
1719 parse_data->skip = FALSE;
1724 if (g_strcmp0 (element_name, "addr-spec") == 0) {
1725 if (parse_data->state == PARSE_STATE_IN_IDENTITY_ADDR_SPEC)
1726 parse_data->state = PARSE_STATE_IN_IDENTITY;
1730 if (g_strcmp0 (element_name, "auto-bcc") == 0) {
1731 if (parse_data->state == PARSE_STATE_IN_AUTO_BCC)
1732 parse_data->state = PARSE_STATE_IN_ACCOUNT;
1736 if (g_strcmp0 (element_name, "auto-cc") == 0) {
1737 if (parse_data->state == PARSE_STATE_IN_AUTO_CC)
1738 parse_data->state = PARSE_STATE_IN_ACCOUNT;
1742 if (g_strcmp0 (element_name, "drafts-folder") == 0) {
1743 if (parse_data->state == PARSE_STATE_IN_DRAFTS_FOLDER)
1744 parse_data->state = PARSE_STATE_IN_ACCOUNT;
1748 if (g_strcmp0 (element_name, "encrypt-key-id") == 0) {
1749 if (parse_data->state == PARSE_STATE_IN_SMIME_ENCRYPT_KEY_ID)
1750 parse_data->state = PARSE_STATE_IN_SMIME;
1754 if (g_strcmp0 (element_name, "identity") == 0) {
1755 if (parse_data->state == PARSE_STATE_IN_IDENTITY)
1756 parse_data->state = PARSE_STATE_IN_ACCOUNT;
1760 if (g_strcmp0 (element_name, "key-id") == 0) {
1761 if (parse_data->state == PARSE_STATE_IN_PGP_KEY_ID)
1762 parse_data->state = PARSE_STATE_IN_PGP;
1766 if (g_strcmp0 (element_name, "name") == 0) {
1767 if (parse_data->state == PARSE_STATE_IN_IDENTITY_NAME)
1768 parse_data->state = PARSE_STATE_IN_IDENTITY;
1772 if (g_strcmp0 (element_name, "organization") == 0) {
1773 if (parse_data->state == PARSE_STATE_IN_IDENTITY_ORGANIZATION)
1774 parse_data->state = PARSE_STATE_IN_IDENTITY;
1778 if (g_strcmp0 (element_name, "pgp") == 0) {
1779 if (parse_data->state == PARSE_STATE_IN_PGP)
1780 parse_data->state = PARSE_STATE_IN_ACCOUNT;
1784 if (g_strcmp0 (element_name, "receipt-policy") == 0) {
1785 if (parse_data->state == PARSE_STATE_IN_RECEIPT_POLICY)
1786 parse_data->state = PARSE_STATE_IN_ACCOUNT;
1790 if (g_strcmp0 (element_name, "recipients") == 0) {
1791 if (parse_data->state == PARSE_STATE_IN_AUTO_BCC_RECIPIENTS)
1792 parse_data->state = PARSE_STATE_IN_AUTO_BCC;
1793 if (parse_data->state == PARSE_STATE_IN_AUTO_CC_RECIPIENTS)
1794 parse_data->state = PARSE_STATE_IN_AUTO_CC;
1798 if (g_strcmp0 (element_name, "reply-to") == 0) {
1799 if (parse_data->state == PARSE_STATE_IN_IDENTITY_REPLY_TO)
1800 parse_data->state = PARSE_STATE_IN_IDENTITY;
1804 if (g_strcmp0 (element_name, "sent-folder") == 0) {
1805 if (parse_data->state == PARSE_STATE_IN_SENT_FOLDER)
1806 parse_data->state = PARSE_STATE_IN_ACCOUNT;
1810 if (g_strcmp0 (element_name, "signature") == 0) {
1811 if (parse_data->state == PARSE_STATE_IN_IDENTITY_SIGNATURE)
1812 parse_data->state = PARSE_STATE_IN_IDENTITY;
1816 if (g_strcmp0 (element_name, "sign-key-id") == 0) {
1817 if (parse_data->state == PARSE_STATE_IN_SMIME_SIGN_KEY_ID)
1818 parse_data->state = PARSE_STATE_IN_SMIME;
1822 if (g_strcmp0 (element_name, "smime") == 0) {
1823 if (parse_data->state == PARSE_STATE_IN_SMIME)
1824 parse_data->state = PARSE_STATE_IN_ACCOUNT;
1828 if (g_strcmp0 (element_name, "source") == 0) {
1829 if (parse_data->state == PARSE_STATE_IN_MAIL_SOURCE)
1830 parse_data->state = PARSE_STATE_IN_ACCOUNT;
1834 if (g_strcmp0 (element_name, "transport") == 0) {
1835 if (parse_data->state == PARSE_STATE_IN_MAIL_TRANSPORT)
1836 parse_data->state = PARSE_STATE_IN_ACCOUNT;
1840 if (g_strcmp0 (element_name, "url") == 0) {
1841 if (parse_data->state == PARSE_STATE_IN_MAIL_SOURCE_URL)
1842 parse_data->state = PARSE_STATE_IN_MAIL_SOURCE;
1843 if (parse_data->state == PARSE_STATE_IN_MAIL_TRANSPORT_URL)
1844 parse_data->state = PARSE_STATE_IN_MAIL_TRANSPORT;
1850 migrate_parse_account_xml_text (GMarkupParseContext *context,
1856 ParseData *parse_data = user_data;
1858 switch (parse_data->state) {
1859 case PARSE_STATE_IN_AUTO_BCC_RECIPIENTS:
1860 /* Disregard the recipient list if
1861 * we're not going to auto-BCC them. */
1862 if (parse_data->auto_bcc)
1863 migrate_parse_recipients (
1864 parse_data, "Bcc", text);
1867 case PARSE_STATE_IN_AUTO_CC_RECIPIENTS:
1868 /* Disregard the recipient list if
1869 * we're not going to auto-CC them. */
1870 if (parse_data->auto_cc)
1871 migrate_parse_recipients (
1872 parse_data, "Cc", text);
1875 case PARSE_STATE_IN_DRAFTS_FOLDER:
1876 g_key_file_set_string (
1877 parse_data->identity_key_file,
1878 E_SOURCE_EXTENSION_MAIL_COMPOSITION,
1879 "DraftsFolder", text);
1882 case PARSE_STATE_IN_SMIME_ENCRYPT_KEY_ID:
1883 g_key_file_set_string (
1884 parse_data->identity_key_file,
1885 E_SOURCE_EXTENSION_SMIME,
1886 "EncryptionCertificate", text);
1889 case PARSE_STATE_IN_IDENTITY_ADDR_SPEC:
1890 g_key_file_set_string (
1891 parse_data->identity_key_file,
1892 E_SOURCE_EXTENSION_MAIL_IDENTITY,
1896 case PARSE_STATE_IN_IDENTITY_NAME:
1897 g_key_file_set_string (
1898 parse_data->identity_key_file,
1899 E_SOURCE_EXTENSION_MAIL_IDENTITY,
1903 case PARSE_STATE_IN_IDENTITY_ORGANIZATION:
1904 g_key_file_set_string (
1905 parse_data->identity_key_file,
1906 E_SOURCE_EXTENSION_MAIL_IDENTITY,
1907 "Organization", text);
1910 case PARSE_STATE_IN_IDENTITY_REPLY_TO:
1911 g_key_file_set_string (
1912 parse_data->identity_key_file,
1913 E_SOURCE_EXTENSION_MAIL_IDENTITY,
1917 case PARSE_STATE_IN_MAIL_SOURCE_URL:
1918 /* XXX Workaround for so-called "send-only"
1919 * accounts, which have no source URL.
1920 * Their backend name is "none". */
1921 if (text != NULL && *text == '\0')
1926 parse_data->key_file,
1928 E_SOURCE_EXTENSION_MAIL_ACCOUNT,
1932 case PARSE_STATE_IN_MAIL_TRANSPORT_URL:
1935 parse_data->transport_key_file,
1936 parse_data->transport_file,
1937 E_SOURCE_EXTENSION_MAIL_TRANSPORT,
1941 case PARSE_STATE_IN_PGP_KEY_ID:
1942 g_key_file_set_string (
1943 parse_data->identity_key_file,
1944 E_SOURCE_EXTENSION_OPENPGP,
1948 case PARSE_STATE_IN_SENT_FOLDER:
1949 g_key_file_set_string (
1950 parse_data->identity_key_file,
1951 E_SOURCE_EXTENSION_MAIL_SUBMISSION,
1952 "SentFolder", text);
1955 case PARSE_STATE_IN_SMIME_SIGN_KEY_ID:
1956 g_key_file_set_string (
1957 parse_data->identity_key_file,
1958 E_SOURCE_EXTENSION_SMIME,
1959 "SigningCertificate", text);
1967 static GMarkupParser account_xml_parser = {
1968 migrate_parse_account_xml_start_element,
1969 migrate_parse_account_xml_end_element,
1970 migrate_parse_account_xml_text,
1971 NULL, /* passthrough */
1976 migrate_parse_signature (ParseData *parse_data,
1977 const gchar *element_name,
1978 const gchar **attribute_names,
1979 const gchar **attribute_values,
1984 const gchar *format;
1985 const gchar *config_dir;
1987 gchar *absolute_path;
1988 gboolean autogenerated;
1991 success = g_markup_collect_attributes (
1996 G_MARKUP_COLLECT_STRING,
1998 G_MARKUP_COLLECT_STRING,
2000 G_MARKUP_COLLECT_BOOLEAN,
2001 "auto", &autogenerated,
2002 G_MARKUP_COLLECT_STRING |
2003 G_MARKUP_COLLECT_OPTIONAL,
2005 G_MARKUP_COLLECT_INVALID);
2010 /* Skip the "autogenerated" signature. */
2014 parse_data->file = e_server_side_source_new_user_file (uid);
2016 config_dir = e_get_user_config_dir ();
2017 directory = g_build_filename (config_dir, "signatures", NULL);
2018 absolute_path = g_build_filename (directory, uid, NULL);
2019 parse_data->signature_file = g_file_new_for_path (absolute_path);
2020 g_mkdir_with_parents (directory, 0700);
2021 g_free (absolute_path);
2024 /* If the file already exists, skip this source. It may be that we
2025 * already migrated it, in which case we don't want to overwrite it. */
2026 if (g_file_query_exists (parse_data->file, NULL))
2029 parse_data->key_file = g_key_file_new ();
2031 g_key_file_set_string (
2032 parse_data->key_file,
2033 E_SOURCE_GROUP_NAME,
2034 "DisplayName", name);
2036 g_key_file_set_string (
2037 parse_data->key_file,
2038 E_SOURCE_EXTENSION_MAIL_SIGNATURE,
2039 "MimeType", format);
2043 migrate_parse_signature_xml_start_element (GMarkupParseContext *context,
2044 const gchar *element_name,
2045 const gchar **attribute_names,
2046 const gchar **attribute_values,
2050 ParseData *parse_data = user_data;
2052 if (g_strcmp0 (element_name, "filename") == 0) {
2053 if (parse_data->state != PARSE_STATE_IN_SIGNATURE)
2054 goto invalid_content;
2056 parse_data->state = PARSE_STATE_IN_FILENAME;
2058 g_markup_collect_attributes (
2063 G_MARKUP_COLLECT_BOOLEAN |
2064 G_MARKUP_COLLECT_OPTIONAL,
2065 "script", &parse_data->is_script,
2066 G_MARKUP_COLLECT_INVALID);
2071 if (g_strcmp0 (element_name, "signature") == 0) {
2072 if (parse_data->state != PARSE_STATE_IN_SIGNATURES_VALUE)
2073 goto invalid_content;
2075 parse_data->state = PARSE_STATE_IN_SIGNATURE;
2077 migrate_parse_signature (
2088 error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
2089 "Unknown element <%s>", element_name);
2096 error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
2097 "Element <%s> at unexpected location", element_name);
2101 migrate_parse_signature_xml_end_element (GMarkupParseContext *context,
2102 const gchar *element_name,
2106 ParseData *parse_data = user_data;
2108 if (g_strcmp0 (element_name, "filename") == 0) {
2109 if (parse_data->state == PARSE_STATE_IN_FILENAME) {
2110 parse_data->state = PARSE_STATE_IN_SIGNATURE;
2116 if (g_strcmp0 (element_name, "signature") == 0) {
2117 if (parse_data->state == PARSE_STATE_IN_SIGNATURE) {
2118 parse_data->state = PARSE_STATE_IN_SIGNATURES_VALUE;
2120 /* Clean up <signature> tag data. */
2122 /* The key file will be NULL if we decided to skip it.
2123 * e.g. A file with the same UID may already exist. */
2124 if (parse_data->key_file != NULL) {
2125 GError *local_error = NULL;
2127 if (!parse_data->skip)
2128 migrate_parse_commit_changes (
2131 parse_data->key_file,
2132 NULL, &local_error);
2134 if (local_error != NULL) {
2137 local_error->message);
2138 g_error_free (local_error);
2141 g_key_file_free (parse_data->key_file);
2142 parse_data->key_file = NULL;
2145 if (parse_data->file != NULL) {
2146 g_object_unref (parse_data->file);
2147 parse_data->file = NULL;
2150 parse_data->skip = FALSE;
2158 migrate_parse_signature_xml_text (GMarkupParseContext *context,
2164 ParseData *parse_data = user_data;
2166 if (parse_data->state == PARSE_STATE_IN_FILENAME) {
2167 GFile *old_signature_file;
2168 GFile *new_signature_file;
2169 const gchar *data_dir;
2170 gchar *absolute_path;
2172 /* Note we're moving the signature files
2173 * from $XDG_DATA_HOME to $XDG_CONFIG_HOME. */
2174 data_dir = e_get_user_data_dir ();
2176 /* Text should be either an absolute file name
2177 * or a base file name with no path components. */
2178 if (g_path_is_absolute (text))
2179 absolute_path = g_strdup (text);
2181 absolute_path = g_build_filename (
2182 data_dir, "signatures", text, NULL);
2184 old_signature_file = g_file_new_for_path (absolute_path);
2185 new_signature_file = parse_data->signature_file;
2186 parse_data->signature_file = NULL;
2188 /* If the signature is a script, we symlink to it.
2189 * Otherwise we move and rename the regular file. */
2190 if (parse_data->is_script)
2191 g_file_make_symbolic_link (
2193 absolute_path, NULL, error);
2199 NULL, NULL, NULL, error);
2201 g_object_unref (old_signature_file);
2202 g_object_unref (new_signature_file);
2203 g_free (absolute_path);
2207 static GMarkupParser signature_xml_parser = {
2208 migrate_parse_signature_xml_start_element,
2209 migrate_parse_signature_xml_end_element,
2210 migrate_parse_signature_xml_text,
2211 NULL, /* passthrough */
2216 migrate_parse_local_calendar_property (ParseData *parse_data,
2217 const gchar *property_name,
2218 const gchar *property_value)
2220 if (g_strcmp0 (property_name, "custom-file") == 0) {
2223 /* Property value is a local filename. Convert it to a
2226 * Note: The key is named "CustomFile" instead of, say,
2227 * "CustomURI" because the corresponding ESourceExtension
2228 * property is a GFile. The fact that ESource saves GFile
2229 * properties as URI strings is an implementation detail. */
2230 uri = g_filename_to_uri (property_value, NULL, NULL);
2232 g_key_file_set_string (
2233 parse_data->key_file,
2234 E_SOURCE_EXTENSION_LOCAL_BACKEND,
2242 migrate_parse_local_source (ParseData *parse_data)
2244 if (parse_data->type != PARSE_TYPE_ADDRESSBOOK)
2245 parse_data->property_func =
2246 migrate_parse_local_calendar_property;
2248 /* Local ADDRESS BOOK Backend has no special properties to parse. */
2252 migrate_parse_caldav_property (ParseData *parse_data,
2253 const gchar *property_name,
2254 const gchar *property_value)
2256 if (g_strcmp0 (property_name, "autoschedule") == 0) {
2257 g_key_file_set_boolean (
2258 parse_data->key_file,
2259 E_SOURCE_EXTENSION_WEBDAV_BACKEND,
2260 "CalendarAutoSchedule",
2261 is_true (property_value));
2263 } else if (g_strcmp0 (property_name, "usermail") == 0) {
2264 g_key_file_set_string (
2265 parse_data->key_file,
2266 E_SOURCE_EXTENSION_WEBDAV_BACKEND,
2267 "EmailAddress", property_value);
2272 migrate_parse_caldav_source (ParseData *parse_data)
2274 if (parse_data->soup_uri->host != NULL)
2275 g_key_file_set_string (
2276 parse_data->key_file,
2277 E_SOURCE_EXTENSION_AUTHENTICATION,
2278 "Host", parse_data->soup_uri->host);
2280 /* We may override this later if we see an "ssl" property. */
2281 if (parse_data->soup_uri->port == 0)
2282 parse_data->soup_uri->port = 80;
2284 g_key_file_set_integer (
2285 parse_data->key_file,
2286 E_SOURCE_EXTENSION_AUTHENTICATION,
2287 "Port", parse_data->soup_uri->port);
2289 if (parse_data->soup_uri->user != NULL)
2290 g_key_file_set_string (
2291 parse_data->key_file,
2292 E_SOURCE_EXTENSION_AUTHENTICATION,
2293 "User", parse_data->soup_uri->user);
2295 if (parse_data->soup_uri->path != NULL)
2296 g_key_file_set_string (
2297 parse_data->key_file,
2298 E_SOURCE_EXTENSION_WEBDAV_BACKEND,
2299 "ResourcePath", parse_data->soup_uri->path);
2301 if (parse_data->soup_uri->query != NULL)
2302 g_key_file_set_string (
2303 parse_data->key_file,
2304 E_SOURCE_EXTENSION_WEBDAV_BACKEND,
2305 "ResourceQuery", parse_data->soup_uri->query);
2307 parse_data->property_func = migrate_parse_caldav_property;
2311 migrate_parse_google_calendar_property (ParseData *parse_data,
2312 const gchar *property_name,
2313 const gchar *property_value)
2315 if (g_strcmp0 (property_name, "username") == 0) {
2318 g_key_file_set_string (
2319 parse_data->key_file,
2320 E_SOURCE_EXTENSION_AUTHENTICATION,
2321 "User", property_value);
2323 path = g_strdup_printf (
2324 "/calendar/dav/%s/events", property_value);
2326 g_key_file_set_string (
2327 parse_data->key_file,
2328 E_SOURCE_EXTENSION_WEBDAV_BACKEND,
2329 "ResourcePath", path);
2336 migrate_parse_google_contacts_property (ParseData *parse_data,
2337 const gchar *property_name,
2338 const gchar *property_value)
2340 if (g_strcmp0 (property_name, "refresh-interval") == 0) {
2341 guint64 interval_seconds;
2344 g_ascii_strtoull (property_value, NULL, 10);
2346 if (interval_seconds >= 60) {
2347 g_key_file_set_boolean (
2348 parse_data->key_file,
2349 E_SOURCE_EXTENSION_REFRESH,
2351 g_key_file_set_uint64 (
2352 parse_data->key_file,
2353 E_SOURCE_EXTENSION_REFRESH,
2355 interval_seconds / 60);
2358 } else if (g_strcmp0 (property_name, "username") == 0) {
2359 g_key_file_set_string (
2360 parse_data->key_file,
2361 E_SOURCE_EXTENSION_AUTHENTICATION,
2362 "User", property_value);
2367 migrate_parse_google_source (ParseData *parse_data)
2369 if (parse_data->type == PARSE_TYPE_ADDRESSBOOK)
2370 parse_data->property_func =
2371 migrate_parse_google_contacts_property;
2374 g_key_file_set_string (
2375 parse_data->key_file,
2376 E_SOURCE_EXTENSION_AUTHENTICATION,
2377 "Host", "www.google.com");
2379 g_key_file_set_integer (
2380 parse_data->key_file,
2381 E_SOURCE_EXTENSION_AUTHENTICATION,
2384 g_key_file_set_string (
2385 parse_data->key_file,
2386 E_SOURCE_EXTENSION_SECURITY,
2389 parse_data->property_func =
2390 migrate_parse_google_calendar_property;
2395 migrate_parse_ldap_property (ParseData *parse_data,
2396 const gchar *property_name,
2397 const gchar *property_value)
2399 if (g_strcmp0 (property_name, "can-browse") == 0) {
2400 g_key_file_set_boolean (
2401 parse_data->key_file,
2402 E_SOURCE_EXTENSION_LDAP_BACKEND,
2404 is_true (property_value));
2406 /* This is an integer value, but we can use the string as is. */
2407 } else if (g_strcmp0 (property_name, "limit") == 0) {
2408 g_key_file_set_string (
2409 parse_data->key_file,
2410 E_SOURCE_EXTENSION_LDAP_BACKEND,
2411 "Limit", property_value);
2416 migrate_parse_ldap_source (ParseData *parse_data)
2418 if (parse_data->soup_uri->host != NULL)
2419 g_key_file_set_string (
2420 parse_data->key_file,
2421 E_SOURCE_EXTENSION_AUTHENTICATION,
2422 "Host", parse_data->soup_uri->host);
2424 if (parse_data->soup_uri->port != 0)
2425 g_key_file_set_integer (
2426 parse_data->key_file,
2427 E_SOURCE_EXTENSION_AUTHENTICATION,
2428 "Port", parse_data->soup_uri->port);
2430 if (parse_data->soup_uri->user != NULL)
2431 g_key_file_set_string (
2432 parse_data->key_file,
2433 E_SOURCE_EXTENSION_AUTHENTICATION,
2434 "User", parse_data->soup_uri->user);
2436 /* Skip the leading slash on the URI path to get the RootDn. */
2437 if (parse_data->soup_uri->path != NULL)
2438 g_key_file_set_string (
2439 parse_data->key_file,
2440 E_SOURCE_EXTENSION_LDAP_BACKEND,
2441 "RootDn", parse_data->soup_uri->path + 1);
2443 if (g_strcmp0 (parse_data->soup_uri->query, "?sub?") == 0)
2444 g_key_file_set_string (
2445 parse_data->key_file,
2446 E_SOURCE_EXTENSION_LDAP_BACKEND,
2447 "Scope", "subtree");
2449 if (g_strcmp0 (parse_data->soup_uri->query, "?one?") == 0)
2450 g_key_file_set_string (
2451 parse_data->key_file,
2452 E_SOURCE_EXTENSION_LDAP_BACKEND,
2453 "Scope", "onelevel");
2455 parse_data->property_func = migrate_parse_ldap_property;
2459 migrate_parse_vcf_source (ParseData *parse_data)
2461 if (parse_data->soup_uri->path != NULL)
2462 g_key_file_set_string (
2463 parse_data->key_file,
2464 E_SOURCE_EXTENSION_VCF_BACKEND,
2465 "Path", parse_data->soup_uri->path);
2467 /* VCF Backend has no special properties to parse. */
2471 migrate_parse_weather_property (ParseData *parse_data,
2472 const gchar *property_name,
2473 const gchar *property_value)
2475 /* XXX Temperature property was replaced by units... I think. */
2476 if (g_strcmp0 (property_name, "temperature") == 0) {
2479 metric = (g_strcmp0 (property_value, "fahrenheit") != 0);
2481 g_key_file_set_string (
2482 parse_data->key_file,
2483 E_SOURCE_EXTENSION_WEATHER_BACKEND,
2484 "Units", metric ? "metric" : "imperial");
2486 } else if (g_strcmp0 (property_name, "units") == 0) {
2489 metric = (g_strcmp0 (property_value, "metric") == 0);
2491 g_key_file_set_string (
2492 parse_data->key_file,
2493 E_SOURCE_EXTENSION_WEATHER_BACKEND,
2494 "Units", metric ? "metric" : "imperial");
2499 migrate_parse_weather_source (ParseData *parse_data)
2501 /* Oh man, we actually try to shove a weather location into
2502 * a URI! The station code winds up as the host component,
2503 * and the location name winds up as the path component. */
2504 if (parse_data->soup_uri->host != NULL) {
2507 if (parse_data->soup_uri->path != NULL)
2508 location = g_strconcat (
2509 parse_data->soup_uri->host,
2510 parse_data->soup_uri->path, NULL);
2512 location = g_strdup (parse_data->soup_uri->host);
2514 g_key_file_set_string (
2515 parse_data->key_file,
2516 E_SOURCE_EXTENSION_WEATHER_BACKEND,
2517 "Location", location);
2522 parse_data->property_func = migrate_parse_weather_property;
2526 migrate_parse_webcal_source (ParseData *parse_data)
2528 if (parse_data->soup_uri->host != NULL)
2529 g_key_file_set_string (
2530 parse_data->key_file,
2531 E_SOURCE_EXTENSION_AUTHENTICATION,
2532 "Host", parse_data->soup_uri->host);
2534 /* We may override this later if we see an "ssl" property. */
2535 if (parse_data->soup_uri->port == 0)
2536 parse_data->soup_uri->port = 80;
2538 g_key_file_set_integer (
2539 parse_data->key_file,
2540 E_SOURCE_EXTENSION_AUTHENTICATION,
2541 "Port", parse_data->soup_uri->port);
2543 if (parse_data->soup_uri->user != NULL)
2544 g_key_file_set_string (
2545 parse_data->key_file,
2546 E_SOURCE_EXTENSION_AUTHENTICATION,
2547 "User", parse_data->soup_uri->user);
2549 if (parse_data->soup_uri->path != NULL)
2550 g_key_file_set_string (
2551 parse_data->key_file,
2552 E_SOURCE_EXTENSION_WEBDAV_BACKEND,
2553 "ResourcePath", parse_data->soup_uri->path);
2555 if (parse_data->soup_uri->query != NULL)
2556 g_key_file_set_string (
2557 parse_data->key_file,
2558 E_SOURCE_EXTENSION_WEBDAV_BACKEND,
2559 "ResourceQuery", parse_data->soup_uri->query);
2561 /* Webcal Backend has no special properties to parse. */
2565 migrate_parse_webdav_property (ParseData *parse_data,
2566 const gchar *property_name,
2567 const gchar *property_value)
2569 if (g_strcmp0 (property_name, "avoid_ifmatch") == 0) {
2570 g_key_file_set_boolean (
2571 parse_data->key_file,
2572 E_SOURCE_EXTENSION_WEBDAV_BACKEND,
2574 is_true (property_value));
2579 migrate_parse_webdav_source (ParseData *parse_data)
2581 if (parse_data->soup_uri->host != NULL)
2582 g_key_file_set_string (
2583 parse_data->key_file,
2584 E_SOURCE_EXTENSION_AUTHENTICATION,
2585 "Host", parse_data->soup_uri->host);
2587 if (parse_data->soup_uri->port != 0)
2588 g_key_file_set_integer (
2589 parse_data->key_file,
2590 E_SOURCE_EXTENSION_AUTHENTICATION,
2591 "Port", parse_data->soup_uri->port);
2593 if (parse_data->soup_uri->user != NULL)
2594 g_key_file_set_string (
2595 parse_data->key_file,
2596 E_SOURCE_EXTENSION_AUTHENTICATION,
2597 "User", parse_data->soup_uri->user);
2599 if (parse_data->soup_uri->path != NULL)
2600 g_key_file_set_string (
2601 parse_data->key_file,
2602 E_SOURCE_EXTENSION_WEBDAV_BACKEND,
2603 "ResourcePath", parse_data->soup_uri->path);
2605 if (parse_data->soup_uri->query != NULL)
2606 g_key_file_set_string (
2607 parse_data->key_file,
2608 E_SOURCE_EXTENSION_WEBDAV_BACKEND,
2609 "ResourceQuery", parse_data->soup_uri->query);
2611 parse_data->property_func = migrate_parse_webdav_property;
2615 migrate_parse_group (ParseData *parse_data,
2616 const gchar *element_name,
2617 const gchar **attribute_names,
2618 const gchar **attribute_values,
2621 const gchar *base_uri;
2624 success = g_markup_collect_attributes (
2629 G_MARKUP_COLLECT_STRING,
2631 G_MARKUP_COLLECT_STRING,
2633 G_MARKUP_COLLECT_STRING,
2634 "base_uri", &base_uri,
2635 G_MARKUP_COLLECT_BOOLEAN |
2636 G_MARKUP_COLLECT_OPTIONAL,
2638 G_MARKUP_COLLECT_INVALID);
2643 /* Convert "file://" schemes to "local:". */
2644 if (g_strcmp0 (base_uri, "file://") == 0)
2645 base_uri = "local:";
2647 parse_data->base_uri = g_strdup (base_uri);
2651 migrate_parse_source (ParseData *parse_data,
2652 const gchar *element_name,
2653 const gchar **attribute_names,
2654 const gchar **attribute_values,
2659 const gchar *color_spec;
2660 const gchar *group_name;
2661 const gchar *absolute_uri;
2662 const gchar *relative_uri;
2663 gchar *backend_name;
2668 gboolean is_google_calendar;
2670 success = g_markup_collect_attributes (
2675 G_MARKUP_COLLECT_STRING,
2677 G_MARKUP_COLLECT_STRING,
2679 G_MARKUP_COLLECT_STRING |
2680 G_MARKUP_COLLECT_OPTIONAL,
2681 "color_spec", &color_spec,
2682 G_MARKUP_COLLECT_STRING,
2683 "relative_uri", &relative_uri,
2684 G_MARKUP_COLLECT_STRING |
2685 G_MARKUP_COLLECT_OPTIONAL,
2686 "uri", &absolute_uri,
2687 G_MARKUP_COLLECT_INVALID);
2692 /* Don't try and migrate the "system" sources, as
2693 * we'll defer to the built-in "system-*" key files. */
2694 if (g_strcmp0 (relative_uri, "system") == 0)
2697 /* Also skip any sources with a "contacts://" base URI, which
2698 * should just be "Birthdays & Anniversaries". We'll reset to
2699 * the built-in key file. */
2700 if (g_strcmp0 (parse_data->base_uri, "contacts://") == 0)
2703 /* Also skip any sources for groupware extensions, as these are
2704 * no longer saved to disk. We do have a mechanism in place for
2705 * remembering the UIDs of memory-only sources so that cached
2706 * data can be reused, but let's not bother with it here. Let
2707 * the sources be set up fresh. */
2708 if (base_uri_is_groupware (parse_data->base_uri))
2711 switch (parse_data->type) {
2712 case PARSE_TYPE_ADDRESSBOOK:
2713 group_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
2715 case PARSE_TYPE_CALENDAR:
2716 group_name = E_SOURCE_EXTENSION_CALENDAR;
2718 case PARSE_TYPE_TASKS:
2719 group_name = E_SOURCE_EXTENSION_TASK_LIST;
2721 case PARSE_TYPE_MEMOS:
2722 group_name = E_SOURCE_EXTENSION_MEMO_LIST;
2725 g_return_if_reached ();
2728 parse_data->file = e_server_side_source_new_user_file (uid);
2730 /* If the file already exists, skip this source. It may be that we
2731 * already migrated it, in which case we don't want to overwrite it. */
2732 if (g_file_query_exists (parse_data->file, NULL))
2735 parse_data->key_file = g_key_file_new ();
2737 /* Trim ':' or '://' off the base_uri to get the backend name. */
2738 backend_name = g_strdup (parse_data->base_uri);
2739 if ((cp = strchr (backend_name, ':')) != NULL)
2742 /* The parent name is generally the backend name + "-stub". */
2743 parent_name = g_strdup_printf ("%s-stub", backend_name);
2745 g_key_file_set_string (
2746 parse_data->key_file,
2747 E_SOURCE_GROUP_NAME,
2748 "DisplayName", name);
2750 g_key_file_set_string (
2751 parse_data->key_file,
2752 E_SOURCE_GROUP_NAME,
2753 "Parent", parent_name);
2755 if (color_spec != NULL)
2756 g_key_file_set_string (
2757 parse_data->key_file, group_name,
2758 "Color", color_spec);
2760 is_google_calendar =
2761 (parse_data->type == PARSE_TYPE_CALENDAR) &&
2762 (g_strcmp0 (parse_data->base_uri, "google://") == 0);
2764 /* For Google Calendar sources we override the backend name. */
2765 if (is_google_calendar)
2766 g_key_file_set_string (
2767 parse_data->key_file, group_name,
2768 "BackendName", "caldav");
2770 g_key_file_set_string (
2771 parse_data->key_file, group_name,
2772 "BackendName", backend_name);
2774 g_free (backend_name);
2775 g_free (parent_name);
2777 /* Prefer absolute URIs over relative URIs. All these
2778 * other strange rules are for backward-compatibility. */
2779 if (absolute_uri != NULL)
2780 uri_string = g_strdup (absolute_uri);
2781 else if (g_str_has_suffix (parse_data->base_uri, "/"))
2782 uri_string = g_strconcat (
2783 parse_data->base_uri, relative_uri, NULL);
2784 else if (g_strcmp0 (parse_data->base_uri, "local:") == 0)
2785 uri_string = g_strconcat (
2786 parse_data->base_uri, relative_uri, NULL);
2788 uri_string = g_strconcat (
2789 parse_data->base_uri, "/", relative_uri, NULL);
2791 parse_data->soup_uri = soup_uri_new (uri_string);
2793 /* Mangle the URI to not contain invalid characters. We'll need
2794 * this later to rename the source's cache and data directories. */
2795 parse_data->mangled_uri = g_strdelimit (uri_string, ":/", '_');
2797 /* g_strdelimit() modifies the input string in place, so ParseData
2798 * now owns 'uri_string'. Clear the pointer to emphasize that. */
2801 if (parse_data->soup_uri == NULL) {
2803 " Failed to parse source URI: %s",
2804 (absolute_uri != NULL) ? absolute_uri : relative_uri);
2805 g_key_file_free (parse_data->key_file);
2806 parse_data->key_file = NULL;
2810 if (g_strcmp0 (parse_data->base_uri, "local:") == 0)
2811 migrate_parse_local_source (parse_data);
2813 else if (g_strcmp0 (parse_data->base_uri, "caldav://") == 0)
2814 migrate_parse_caldav_source (parse_data);
2816 else if (g_strcmp0 (parse_data->base_uri, "google://") == 0)
2817 migrate_parse_google_source (parse_data);
2819 else if (g_strcmp0 (parse_data->base_uri, "ldap://") == 0)
2820 migrate_parse_ldap_source (parse_data);
2822 else if (g_strcmp0 (parse_data->base_uri, "vcf://") == 0)
2823 migrate_parse_vcf_source (parse_data);
2825 else if (g_strcmp0 (parse_data->base_uri, "weather://") == 0)
2826 migrate_parse_weather_source (parse_data);
2828 else if (g_strcmp0 (parse_data->base_uri, "webcal://") == 0)
2829 migrate_parse_webcal_source (parse_data);
2831 else if (g_strcmp0 (parse_data->base_uri, "webdav://") == 0)
2832 migrate_parse_webdav_source (parse_data);
2834 migrate_keyring_entry (
2836 parse_data->soup_uri->user,
2837 parse_data->soup_uri->host,
2838 parse_data->soup_uri->scheme);
2842 migrate_parse_property (ParseData *parse_data,
2843 const gchar *element_name,
2844 const gchar **attribute_names,
2845 const gchar **attribute_values,
2848 const gchar *property_name;
2849 const gchar *property_value;
2852 success = g_markup_collect_attributes (
2857 G_MARKUP_COLLECT_STRING,
2858 "name", &property_name,
2859 G_MARKUP_COLLECT_STRING,
2860 "value", &property_value,
2861 G_MARKUP_COLLECT_INVALID);
2866 if (g_strcmp0 (property_name, "alarm") == 0) {
2867 g_key_file_set_boolean (
2868 parse_data->key_file,
2869 E_SOURCE_EXTENSION_ALARMS,
2871 is_true (property_value));
2873 } else if (g_strcmp0 (property_name, "auth") == 0) {
2874 if (is_true (property_value))
2875 g_key_file_set_string (
2876 parse_data->key_file,
2877 E_SOURCE_EXTENSION_AUTHENTICATION,
2878 "Method", "plain/password");
2879 else if (is_false (property_value))
2880 g_key_file_set_string (
2881 parse_data->key_file,
2882 E_SOURCE_EXTENSION_AUTHENTICATION,
2885 g_key_file_set_string (
2886 parse_data->key_file,
2887 E_SOURCE_EXTENSION_AUTHENTICATION,
2888 "Method", property_value);
2890 } else if (g_strcmp0 (property_name, "completion") == 0) {
2891 g_key_file_set_boolean (
2892 parse_data->key_file,
2893 E_SOURCE_EXTENSION_AUTOCOMPLETE,
2895 is_true (property_value));
2897 /* If we see a "goa-account-id" property, skip the entire
2898 * source and let the online-accounts module recreate it. */
2899 } else if (g_strcmp0 (property_name, "goa-account-id") == 0) {
2900 parse_data->skip = TRUE;
2902 } else if (g_strcmp0 (property_name, "last-notified") == 0) {
2903 g_key_file_set_string (
2904 parse_data->key_file,
2905 E_SOURCE_EXTENSION_ALARMS,
2906 "LastNotified", property_value);
2908 } else if (g_strcmp0 (property_name, "offline_sync") == 0) {
2909 g_key_file_set_boolean (
2910 parse_data->key_file,
2911 E_SOURCE_EXTENSION_OFFLINE,
2913 is_true (property_value));
2915 } else if (g_strcmp0 (property_name, "refresh") == 0) {
2916 g_key_file_set_boolean (
2917 parse_data->key_file,
2918 E_SOURCE_EXTENSION_REFRESH,
2920 g_key_file_set_string (
2921 parse_data->key_file,
2922 E_SOURCE_EXTENSION_REFRESH,
2923 "IntervalMinutes", property_value);
2925 } else if (g_strcmp0 (property_name, "remember_password") == 0) {
2926 g_key_file_set_boolean (
2927 parse_data->key_file,
2928 E_SOURCE_EXTENSION_AUTHENTICATION,
2930 is_true (property_value));
2932 } else if (g_strcmp0 (property_name, "ssl") == 0) {
2933 if (is_true (property_value))
2934 g_key_file_set_string (
2935 parse_data->key_file,
2936 E_SOURCE_EXTENSION_SECURITY,
2938 else if (is_false (property_value))
2939 g_key_file_set_string (
2940 parse_data->key_file,
2941 E_SOURCE_EXTENSION_SECURITY,
2944 /* These next two are LDAP-specific. */
2945 else if (g_strcmp0 (property_value, "always") == 0)
2946 g_key_file_set_string (
2947 parse_data->key_file,
2948 E_SOURCE_EXTENSION_SECURITY,
2949 "Method", "starttls");
2950 else if (g_strcmp0 (property_value, "whenever_possible") == 0)
2951 g_key_file_set_string (
2952 parse_data->key_file,
2953 E_SOURCE_EXTENSION_SECURITY,
2956 /* For WebDAV-based backends we set the port to 80
2957 * (http://) by default. If we see that and we're
2958 * using a secure connection, bump the port to 443
2960 if (parse_data->soup_uri->port == 80)
2961 if (is_true (property_value))
2962 g_key_file_set_integer (
2963 parse_data->key_file,
2964 E_SOURCE_EXTENSION_AUTHENTICATION,
2967 } else if (g_strcmp0 (property_name, "use_ssl") == 0) {
2968 g_key_file_set_string (
2969 parse_data->key_file,
2970 E_SOURCE_EXTENSION_SECURITY,
2972 is_true (property_value) ?
2975 /* For WebDAV-based backends we set the port to 80
2976 * (http://) by default. If we see that and we're
2977 * using a secure connection, bump the port to 443
2979 if (parse_data->soup_uri->port == 80)
2980 if (is_true (property_value))
2981 g_key_file_set_integer (
2982 parse_data->key_file,
2983 E_SOURCE_EXTENSION_AUTHENTICATION,
2986 } else if (g_strcmp0 (property_name, "use-in-contacts-calendar") == 0) {
2987 g_key_file_set_boolean (
2988 parse_data->key_file,
2989 E_SOURCE_EXTENSION_CONTACTS_BACKEND,
2991 is_true (property_value));
2993 } else if (parse_data->property_func != NULL) {
2994 parse_data->property_func (
2995 parse_data, property_name, property_value);
3000 migrate_parse_source_xml_start_element (GMarkupParseContext *context,
3001 const gchar *element_name,
3002 const gchar **attribute_names,
3003 const gchar **attribute_values,
3007 ParseData *parse_data = user_data;
3009 if (g_strcmp0 (element_name, "group") == 0) {
3010 if (parse_data->state != PARSE_STATE_IN_SOURCES_VALUE)
3011 goto invalid_content;
3013 parse_data->state = PARSE_STATE_IN_GROUP;
3015 migrate_parse_group (
3025 if (g_strcmp0 (element_name, "source") == 0) {
3026 if (parse_data->state != PARSE_STATE_IN_GROUP)
3027 goto invalid_content;
3029 parse_data->state = PARSE_STATE_IN_SOURCE;
3031 migrate_parse_source (
3041 if (g_strcmp0 (element_name, "properties") == 0) {
3042 /* Disregard group properties, we're only
3043 * interested in source properties. */
3044 if (parse_data->state == PARSE_STATE_IN_GROUP)
3047 if (parse_data->state != PARSE_STATE_IN_SOURCE)
3048 goto invalid_content;
3050 parse_data->state = PARSE_STATE_IN_PROPERTIES;
3055 if (g_strcmp0 (element_name, "property") == 0) {
3056 /* Disregard group properties, we're only
3057 * interested in source properties. */
3058 if (parse_data->state == PARSE_STATE_IN_GROUP)
3061 if (parse_data->state != PARSE_STATE_IN_PROPERTIES)
3062 goto invalid_content;
3064 /* The key file will be NULL if we decided to skip it.
3065 * e.g. A file with the same UID may already exist. */
3066 if (parse_data->key_file != NULL)
3067 migrate_parse_property (
3078 error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
3079 "Unknown element <%s>", element_name);
3086 error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
3087 "Element <%s> at unexpected location", element_name);
3091 migrate_parse_source_xml_end_element (GMarkupParseContext *context,
3092 const gchar *element_name,
3096 ParseData *parse_data = user_data;
3098 if (g_strcmp0 (element_name, "group") == 0) {
3099 if (parse_data->state == PARSE_STATE_IN_GROUP) {
3100 parse_data->state = PARSE_STATE_IN_SOURCES_VALUE;
3102 /* Clean up <group> tag data. */
3104 g_free (parse_data->base_uri);
3105 parse_data->base_uri = NULL;
3110 if (g_strcmp0 (element_name, "source") == 0) {
3111 if (parse_data->state == PARSE_STATE_IN_SOURCE) {
3112 parse_data->state = PARSE_STATE_IN_GROUP;
3114 /* Clean up <source> tag data. */
3116 /* The key file will be NULL if we decided to skip it.
3117 * e.g. A file with the same UID may already exist. */
3118 if (parse_data->key_file != NULL) {
3119 GError *local_error = NULL;
3121 if (!parse_data->skip)
3122 migrate_parse_commit_changes (
3125 parse_data->key_file,
3126 parse_data->mangled_uri,
3129 if (local_error != NULL) {
3132 local_error->message);
3133 g_error_free (local_error);
3136 g_key_file_free (parse_data->key_file);
3137 parse_data->key_file = NULL;
3140 if (parse_data->file != NULL) {
3141 g_object_unref (parse_data->file);
3142 parse_data->file = NULL;
3145 g_free (parse_data->mangled_uri);
3146 parse_data->mangled_uri = NULL;
3148 if (parse_data->soup_uri != NULL) {
3149 soup_uri_free (parse_data->soup_uri);
3150 parse_data->soup_uri = NULL;
3153 parse_data->property_func = NULL;
3155 parse_data->skip = FALSE;
3160 if (g_strcmp0 (element_name, "properties") == 0) {
3161 if (parse_data->state == PARSE_STATE_IN_PROPERTIES)
3162 parse_data->state = PARSE_STATE_IN_SOURCE;
3167 static GMarkupParser source_xml_parser = {
3168 migrate_parse_source_xml_start_element,
3169 migrate_parse_source_xml_end_element,
3171 NULL, /* passthrough */
3176 migrate_parse_gconf_xml_start_element (GMarkupParseContext *context,
3177 const gchar *element_name,
3178 const gchar **attribute_names,
3179 const gchar **attribute_values,
3183 ParseData *parse_data = user_data;
3185 if (g_strcmp0 (element_name, "gconf") == 0) {
3186 if (parse_data->state != PARSE_STATE_INITIAL)
3187 goto invalid_content;
3189 parse_data->state = PARSE_STATE_IN_GCONF;
3194 if (g_strcmp0 (element_name, "entry") == 0) {
3198 if (parse_data->state != PARSE_STATE_IN_GCONF)
3199 goto invalid_content;
3201 success = g_markup_collect_attributes (
3206 G_MARKUP_COLLECT_STRING,
3208 G_MARKUP_COLLECT_STRING,
3210 G_MARKUP_COLLECT_STRING |
3211 G_MARKUP_COLLECT_OPTIONAL,
3213 G_MARKUP_COLLECT_STRING |
3214 G_MARKUP_COLLECT_OPTIONAL,
3216 G_MARKUP_COLLECT_STRING |
3217 G_MARKUP_COLLECT_OPTIONAL,
3219 G_MARKUP_COLLECT_STRING |
3220 G_MARKUP_COLLECT_OPTIONAL,
3222 G_MARKUP_COLLECT_STRING |
3223 G_MARKUP_COLLECT_OPTIONAL,
3225 G_MARKUP_COLLECT_INVALID);
3227 if (success && g_strcmp0 (name, "accounts") == 0)
3228 parse_data->state = PARSE_STATE_IN_ACCOUNTS_ENTRY;
3230 if (success && g_strcmp0 (name, "signatures") == 0)
3231 parse_data->state = PARSE_STATE_IN_SIGNATURES_ENTRY;
3233 if (success && g_strcmp0 (name, "sources") == 0)
3234 parse_data->state = PARSE_STATE_IN_SOURCES_ENTRY;
3239 if (g_strcmp0 (element_name, "li") == 0)
3242 if (g_strcmp0 (element_name, "stringvalue") == 0) {
3243 if (parse_data->state == PARSE_STATE_IN_ACCOUNTS_ENTRY)
3244 parse_data->state = PARSE_STATE_IN_ACCOUNTS_VALUE;
3246 if (parse_data->state == PARSE_STATE_IN_SIGNATURES_ENTRY)
3247 parse_data->state = PARSE_STATE_IN_SIGNATURES_VALUE;
3249 if (parse_data->state == PARSE_STATE_IN_SOURCES_ENTRY)
3250 parse_data->state = PARSE_STATE_IN_SOURCES_VALUE;
3256 error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
3257 "Unknown element <%s>", element_name);
3264 error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
3265 "Element <%s> at unexpected location", element_name);
3269 migrate_parse_gconf_xml_end_element (GMarkupParseContext *context,
3270 const gchar *element_name,
3274 ParseData *parse_data = user_data;
3276 if (g_strcmp0 (element_name, "gconf") == 0) {
3277 if (parse_data->state == PARSE_STATE_IN_GCONF)
3278 parse_data->state = PARSE_STATE_INITIAL;
3283 if (g_strcmp0 (element_name, "entry") == 0) {
3284 if (parse_data->state == PARSE_STATE_IN_ACCOUNTS_ENTRY)
3285 parse_data->state = PARSE_STATE_IN_GCONF;
3287 if (parse_data->state == PARSE_STATE_IN_SIGNATURES_ENTRY)
3288 parse_data->state = PARSE_STATE_IN_GCONF;
3290 if (parse_data->state == PARSE_STATE_IN_SOURCES_ENTRY)
3291 parse_data->state = PARSE_STATE_IN_GCONF;
3296 if (g_strcmp0 (element_name, "stringvalue") == 0) {
3297 if (parse_data->state == PARSE_STATE_IN_ACCOUNTS_VALUE)
3298 parse_data->state = PARSE_STATE_IN_ACCOUNTS_ENTRY;
3300 if (parse_data->state == PARSE_STATE_IN_SIGNATURES_VALUE)
3301 parse_data->state = PARSE_STATE_IN_SIGNATURES_ENTRY;
3303 if (parse_data->state == PARSE_STATE_IN_SOURCES_VALUE)
3304 parse_data->state = PARSE_STATE_IN_SOURCES_ENTRY;
3311 migrate_parse_gconf_xml_text (GMarkupParseContext *context,
3317 ParseData *parse_data = user_data;
3319 /* The account and signature data is encoded XML stuffed into
3320 * GConf XML (yuck!). Fortunately GMarkupParseContext decodes
3321 * the XML for us, so we just have to feed it to a nested
3322 * GMarkupParseContext. */
3324 switch (parse_data->state) {
3325 case PARSE_STATE_IN_ACCOUNTS_VALUE:
3326 context = g_markup_parse_context_new (
3327 &account_xml_parser, 0, parse_data, NULL);
3330 case PARSE_STATE_IN_SIGNATURES_VALUE:
3331 context = g_markup_parse_context_new (
3332 &signature_xml_parser, 0, parse_data, NULL);
3335 case PARSE_STATE_IN_SOURCES_VALUE:
3336 context = g_markup_parse_context_new (
3337 &source_xml_parser, 0, parse_data, NULL);
3344 if (g_markup_parse_context_parse (context, text, length, error))
3345 g_markup_parse_context_end_parse (context, error);
3347 g_markup_parse_context_free (context);
3350 static GMarkupParser gconf_xml_parser = {
3351 migrate_parse_gconf_xml_start_element,
3352 migrate_parse_gconf_xml_end_element,
3353 migrate_parse_gconf_xml_text,
3354 NULL, /* passthrough */
3359 migrate_parse_gconf_xml (ParseType parse_type,
3360 const gchar *contents,
3364 GMarkupParseContext *context;
3365 ParseData *parse_data;
3366 gboolean success = FALSE;
3368 parse_data = parse_data_new (parse_type);
3370 context = g_markup_parse_context_new (
3371 &gconf_xml_parser, 0, parse_data,
3372 (GDestroyNotify) parse_data_free);
3374 if (g_markup_parse_context_parse (context, contents, length, error))
3375 if (g_markup_parse_context_end_parse (context, error))
3378 g_markup_parse_context_free (context);
3384 migrate_remove_gconf_xml (const gchar *gconf_key,
3385 const gchar *gconf_xml)
3387 /* Remove the GConf string list so the user is not haunted by
3388 * old data sources being resurrected from leftover GConf data.
3389 * Also delete the %gconf.xml file itself. If gconfd is running
3390 * then it will just recreate the file from memory when it exits
3391 * (which is why we invoke gconftool-2), otherwise the file will
3394 gchar *path_to_program;
3396 path_to_program = g_find_program_in_path ("gconftool-2");
3398 if (path_to_program != NULL) {
3399 gchar *command_line;
3400 GError *error = NULL;
3402 command_line = g_strjoin (
3407 "--list-type=string",
3408 gconf_key, "[]", NULL);
3410 /* We don't really care if the command worked or not,
3411 * just check that the program got spawned successfully. */
3412 if (!g_spawn_command_line_async (command_line, &error)) {
3414 "Failed to spawn '%s': %s\n",
3415 path_to_program, error->message);
3416 g_error_free (error);
3419 g_free (path_to_program);
3420 g_free (command_line);
3423 if (g_file_test (gconf_xml, G_FILE_TEST_IS_REGULAR)) {
3424 if (g_remove (gconf_xml) == -1) {
3426 "Failed to remove '%s': %s\n",
3427 gconf_xml, g_strerror (errno));
3433 migrate_handle_error (const GError *error)
3435 g_return_if_fail (error != NULL);
3437 if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
3438 g_printerr (" FAILED: %s\n", error->message);
3442 evolution_source_registry_migrate_sources (void)
3448 const gchar *gconf_key;
3449 GError *error = NULL;
3451 base_dir = g_build_filename (
3452 g_get_home_dir (), ".gconf", "apps", "evolution", NULL);
3454 /* ------------------------------------------------------------------*/
3456 g_print ("Migrating mail accounts from GConf...\n");
3458 gconf_xml = g_build_filename (
3459 base_dir, "mail", "%gconf.xml", NULL);
3460 g_file_get_contents (gconf_xml, &contents, &length, &error);
3462 if (error == NULL) {
3463 migrate_parse_gconf_xml (
3465 contents, length, &error);
3469 if (error == NULL) {
3470 gconf_key = "/apps/evolution/mail/accounts";
3471 migrate_remove_gconf_xml (gconf_key, gconf_xml);
3473 migrate_handle_error (error);
3474 g_clear_error (&error);
3479 /* ------------------------------------------------------------------*/
3481 g_print ("Migrating addressbook sources from GConf...\n");
3483 gconf_xml = g_build_filename (
3484 base_dir, "addressbook", "%gconf.xml", NULL);
3485 g_file_get_contents (gconf_xml, &contents, &length, &error);
3487 if (error == NULL) {
3488 migrate_parse_gconf_xml (
3489 PARSE_TYPE_ADDRESSBOOK,
3490 contents, length, &error);
3494 if (error == NULL) {
3495 gconf_key = "/apps/evolution/addressbook/sources";
3496 migrate_remove_gconf_xml (gconf_key, gconf_xml);
3498 migrate_handle_error (error);
3499 g_clear_error (&error);
3504 /* ------------------------------------------------------------------*/
3506 g_print ("Migrating calendar sources from GConf...\n");
3508 gconf_xml = g_build_filename (
3509 base_dir, "calendar", "%gconf.xml", NULL);
3510 g_file_get_contents (gconf_xml, &contents, &length, &error);
3512 if (error == NULL) {
3513 migrate_parse_gconf_xml (
3514 PARSE_TYPE_CALENDAR,
3515 contents, length, &error);
3519 if (error == NULL) {
3520 gconf_key = "/apps/evolution/calendar/sources";
3521 migrate_remove_gconf_xml (gconf_key, gconf_xml);
3523 migrate_handle_error (error);
3524 g_clear_error (&error);
3529 /* ------------------------------------------------------------------*/
3531 g_print ("Migrating task list sources from GConf...\n");
3533 gconf_xml = g_build_filename (
3534 base_dir, "tasks", "%gconf.xml", NULL);
3535 g_file_get_contents (gconf_xml, &contents, &length, &error);
3537 if (error == NULL) {
3538 migrate_parse_gconf_xml (
3540 contents, length, &error);
3544 if (error == NULL) {
3545 gconf_key = "/apps/evolution/tasks/sources";
3546 migrate_remove_gconf_xml (gconf_key, gconf_xml);
3548 migrate_handle_error (error);
3549 g_clear_error (&error);
3554 /* ------------------------------------------------------------------*/
3556 g_print ("Migrating memo list sources from GConf...\n");
3558 gconf_xml = g_build_filename (
3559 base_dir, "memos", "%gconf.xml", NULL);
3560 g_file_get_contents (gconf_xml, &contents, &length, &error);
3562 if (error == NULL) {
3563 migrate_parse_gconf_xml (
3565 contents, length, &error);
3569 if (error == NULL) {
3570 gconf_key = "/apps/evolution/memos/sources";
3571 migrate_remove_gconf_xml (gconf_key, gconf_xml);
3573 migrate_handle_error (error);
3574 g_clear_error (&error);
3579 /* ------------------------------------------------------------------*/