4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
21 #include "evolution-config.h"
23 #include "e-mail-migrate.h"
28 #include <sys/types.h>
37 #include <glib/gi18n.h>
38 #include <glib/gstdio.h>
42 #include <libxml/tree.h>
43 #include <libxml/parser.h>
44 #include <libxml/xmlmemory.h>
46 #include <shell/e-shell.h>
47 #include <shell/e-shell-migrate.h>
49 #include <libemail-engine/libemail-engine.h>
51 #include "e-mail-backend.h"
56 /* 1.4 upgrade functions */
58 static GtkProgressBar
*progress
;
61 em_migrate_set_progress (double percent
)
65 snprintf (text
, sizeof (text
), "%d%%", (gint
) (percent
* 100.0f
));
67 gtk_progress_bar_set_fraction (progress
, percent
);
68 gtk_progress_bar_set_text (progress
, text
);
70 while (gtk_events_pending ())
71 gtk_main_iteration ();
80 static gint open_flags
[3] = {
81 O_WRONLY
| O_CREAT
| O_TRUNC
,
82 O_WRONLY
| O_CREAT
| O_TRUNC
,
83 O_WRONLY
| O_CREAT
| O_APPEND
,
89 gboolean show_progress
,
92 guchar readbuf
[65536];
93 gssize nread
, nwritten
;
94 gint errnosav
, readfd
, writefd
;
99 /* if the dest file exists and has content, abort - we don't
100 * want to corrupt their existing data */
101 if (g_stat (dest
, &st
) == 0 && st
.st_size
> 0 && mode
== CP_UNIQUE
) {
106 if (g_stat (src
, &st
) == -1
107 || (readfd
= g_open (src
, O_RDONLY
| O_BINARY
, 0)) == -1)
110 if ((writefd
= g_open (dest
, open_flags
[mode
] | O_BINARY
, 0666)) == -1) {
119 nread
= read (readfd
, readbuf
, sizeof (readbuf
));
120 } while (nread
== -1 && errno
== EINTR
);
128 nwritten
= write (writefd
, readbuf
, nread
);
129 } while (nwritten
== -1 && errno
== EINTR
);
131 if (nwritten
< nread
)
136 em_migrate_set_progress (((gdouble
) total
) / ((gdouble
) st
.st_size
));
137 } while (total
< st
.st_size
);
140 if (fsync (writefd
) == -1)
145 if (close (writefd
) == -1)
148 ut
.actime
= st
.st_atime
;
149 ut
.modtime
= st
.st_mtime
;
151 if (chmod (dest
, st
.st_mode
) == -1) {
152 g_warning ("%s: Failed to chmod '%s': %s", G_STRFUNC
, dest
, g_strerror (errno
));
174 emm_setup_initial (const gchar
*data_dir
)
178 gchar
*local
= NULL
, *base
;
179 const gchar
* const *language_names
;
181 /* special-case - this means brand new install of evolution */
182 /* FIXME: create default folders and stuff... */
184 d (printf ("Setting up initial mail tree\n"));
186 base
= g_build_filename (data_dir
, "local", NULL
);
187 if (g_mkdir_with_parents (base
, 0700) == -1 && errno
!= EEXIST
) {
192 /* e.g. try en-AU then en, etc */
193 language_names
= g_get_language_names ();
194 while (*language_names
!= NULL
) {
195 local
= g_build_filename (
196 EVOLUTION_PRIVDATADIR
, "default",
197 *language_names
, "mail", "local", NULL
);
198 if (g_file_test (local
, G_FILE_TEST_EXISTS
))
204 /* Make sure we found one. */
205 g_return_val_if_fail (*language_names
!= NULL
, FALSE
);
207 dir
= g_dir_open (local
, 0, NULL
);
209 while ((d
= g_dir_read_name (dir
))) {
212 src
= g_build_filename (local
, d
, NULL
);
213 dest
= g_build_filename (base
, d
, NULL
);
215 cp (src
, dest
, FALSE
, CP_UNIQUE
);
229 em_rename_view_in_folder (gpointer data
,
232 const gchar
*filename
= data
;
233 const gchar
*views_dir
= user_data
;
234 gchar
*folderpos
, *dotpos
;
236 g_return_if_fail (filename
!= NULL
);
237 g_return_if_fail (views_dir
!= NULL
);
239 folderpos
= strstr (filename
, "-folder:__");
241 folderpos
= strstr (filename
, "-folder___");
245 /* points on 'f' from the "folder" word */
247 dotpos
= strrchr (filename
, '.');
248 if (folderpos
< dotpos
&& g_str_equal (dotpos
, ".xml")) {
250 gchar
*oldname
, *newname
, *newfile
;
251 const gchar
*md5_string
;
255 /* use MD5 checksum of the folder URI, to not depend on its length */
256 checksum
= g_checksum_new (G_CHECKSUM_MD5
);
257 g_checksum_update (checksum
, (const guchar
*) folderpos
, -1);
260 md5_string
= g_checksum_get_string (checksum
);
261 newfile
= g_strconcat (filename
, md5_string
, ".xml", NULL
);
265 oldname
= g_build_filename (views_dir
, filename
, NULL
);
266 newname
= g_build_filename (views_dir
, newfile
, NULL
);
268 if (g_rename (oldname
, newname
) == -1) {
270 "%s: Failed to rename '%s' to '%s': %s", G_STRFUNC
,
271 oldname
, newname
, g_strerror (errno
));
274 g_checksum_free (checksum
);
282 em_rename_folder_views (EShellBackend
*shell_backend
)
284 const gchar
*config_dir
;
288 g_return_if_fail (shell_backend
!= NULL
);
290 config_dir
= e_shell_backend_get_config_dir (shell_backend
);
291 views_dir
= g_build_filename (config_dir
, "views", NULL
);
293 dir
= g_dir_open (views_dir
, 0, NULL
);
295 GSList
*to_rename
= NULL
;
296 const gchar
*filename
;
298 while (filename
= g_dir_read_name (dir
), filename
) {
299 if (strstr (filename
, "-folder:__") ||
300 strstr (filename
, "-folder___"))
301 to_rename
= g_slist_prepend (to_rename
, g_strdup (filename
));
306 g_slist_foreach (to_rename
, em_rename_view_in_folder
, views_dir
);
307 g_slist_free_full (to_rename
, g_free
);
314 em_maybe_update_filter_rule_part (xmlNodePtr part
)
317 xmlChar
*name
, *value
;
319 name
= xmlGetProp (part
, (xmlChar
*) "name");
321 if (g_strcmp0 ((const gchar
*) name
, "completed-on") != 0) {
331 xmlSetProp (part
, (xmlChar
*) "name", (xmlChar
*) "follow-up");
333 values
= part
->children
;
335 if (g_strcmp0 ((const gchar
*) values
->name
, "value") == 0) {
336 name
= xmlGetProp (values
, (xmlChar
*) "name");
338 if (g_strcmp0 ((const gchar
*) name
, "date-spec-type") == 0) {
339 xmlSetProp (values
, (xmlChar
*) "name", (xmlChar
*) "match-type");
341 value
= xmlGetProp (values
, (xmlChar
*) "value");
343 if (g_strcmp0 ((const gchar
*) value
, "is set") == 0)
344 xmlSetProp (values
, (xmlChar
*) "value", (xmlChar
*) "is completed");
345 else if (g_strcmp0 ((const gchar
*) value
, "is not set") == 0)
346 xmlSetProp (values
, (xmlChar
*) "value", (xmlChar
*) "is not completed");
356 values
= values
->next
;
363 em_update_filter_rules_file (const gchar
*filename
)
365 xmlNodePtr set
, rule
, root
;
367 gboolean changed
= FALSE
;
369 if (!filename
|| !*filename
|| !g_file_test (filename
, G_FILE_TEST_IS_REGULAR
))
372 doc
= e_xml_parse_file (filename
);
376 root
= xmlDocGetRootElement (doc
);
377 set
= root
&& g_strcmp0 ((const gchar
*) root
->name
, "filteroptions") == 0 ? root
->children
: NULL
;
379 if (g_strcmp0 ((const gchar
*) set
->name
, "ruleset") == 0) {
380 rule
= set
->children
;
382 if (g_strcmp0 ((const gchar
*) rule
->name
, "rule") == 0) {
385 partset
= rule
->children
;
387 if (g_strcmp0 ((const gchar
*) partset
->name
, "partset") == 0) {
390 part
= partset
->children
;
392 if (g_strcmp0 ((const gchar
*) part
->name
, "part") == 0) {
393 changed
= em_maybe_update_filter_rule_part (part
) || changed
;
400 partset
= partset
->next
;
412 e_xml_save_file (filename
, doc
);
418 em_update_filter_rules (EShellBackend
*shell_backend
)
420 const gchar
*config_dir
;
423 g_return_if_fail (shell_backend
!= NULL
);
425 config_dir
= e_shell_backend_get_config_dir (shell_backend
);
427 filename
= g_build_filename (config_dir
, "filters.xml", NULL
);
428 em_update_filter_rules_file (filename
);
431 filename
= g_build_filename (config_dir
, "searches.xml", NULL
);
432 em_update_filter_rules_file (filename
);
435 filename
= g_build_filename (config_dir
, "vfolders.xml", NULL
);
436 em_update_filter_rules_file (filename
);
441 unset_initial_setup_write_finished_cb (GObject
*source_object
,
442 GAsyncResult
*result
,
446 GError
*local_error
= NULL
;
448 g_return_if_fail (E_IS_SOURCE (source_object
));
449 g_return_if_fail (result
!= NULL
);
451 source
= E_SOURCE (source_object
);
453 if (!e_source_write_finish (source
, result
, &local_error
)) {
454 g_warning ("%s: Failed to save source '%s' (%s): %s", G_STRFUNC
, e_source_get_uid (source
),
455 e_source_get_display_name (source
), local_error
? local_error
->message
: "Unknown error");
458 g_clear_error (&local_error
);
462 em_unset_initial_setup_for_accounts (EShellBackend
*shell_backend
)
464 ESourceRegistry
*registry
;
465 GList
*sources
, *link
;
467 g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend
));
469 registry
= e_shell_get_registry (e_shell_backend_get_shell (shell_backend
));
470 sources
= e_source_registry_list_sources (registry
, E_SOURCE_EXTENSION_MAIL_ACCOUNT
);
472 for (link
= sources
; link
; link
= g_list_next (link
)) {
473 ESource
*source
= link
->data
;
474 ESourceMailAccount
*mail_account
;
476 mail_account
= e_source_get_extension (source
, E_SOURCE_EXTENSION_MAIL_ACCOUNT
);
477 if (e_source_mail_account_get_needs_initial_setup (mail_account
)) {
478 e_source_mail_account_set_needs_initial_setup (mail_account
, FALSE
);
480 e_source_write (source
, NULL
, unset_initial_setup_write_finished_cb
, NULL
);
484 g_list_free_full (sources
, g_object_unref
);
488 e_mail_migrate (EShellBackend
*shell_backend
,
494 const gchar
*data_dir
;
496 data_dir
= e_shell_backend_get_data_dir (shell_backend
);
499 return emm_setup_initial (data_dir
);
501 if (major
<= 2 || (major
== 3 && minor
< 4))
502 em_rename_folder_views (shell_backend
);
504 if (major
<= 2 || (major
== 3 && minor
< 17))
505 em_update_filter_rules (shell_backend
);
507 if (major
<= 2 || (major
== 3 && minor
< 19) || (major
== 3 && minor
== 19 && micro
< 90))
508 em_unset_initial_setup_for_accounts (shell_backend
);