No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | e-mail-migrate.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-mail-migrate.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * e-mail-migrate.c
3 *
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.
8 *
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.
13 *
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/>
16 *
17 *
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include "e-mail-migrate.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <utime.h>
34 #include <unistd.h>
35 #include <dirent.h>
36 #include <regex.h>
37 #include <errno.h>
38 #include <ctype.h>
39
40 #include <glib/gi18n.h>
41 #include <glib/gstdio.h>
42
43 #include <gtk/gtk.h>
44
45 #include <libxml/tree.h>
46 #include <libxml/parser.h>
47 #include <libxml/xmlmemory.h>
48
49 #include <shell/e-shell.h>
50 #include <shell/e-shell-migrate.h>
51
52 #include <e-util/e-util.h>
53 #include <libevolution-utils/e-xml-utils.h>
54
55 #include <libevolution-utils/e-alert-dialog.h>
56 #include <e-util/e-util-private.h>
57 #include <e-util/e-plugin.h>
58
59 #include <libemail-engine/e-mail-folder-utils.h>
60
61 #include "e-mail-backend.h"
62 #include "em-utils.h"
63
64 #define d(x) x
65
66 /* 1.4 upgrade functions */
67
68 static GtkProgressBar *progress;
69
70 static void
71 em_migrate_set_progress (double percent)
72 {
73 gchar text[5];
74
75 snprintf (text, sizeof (text), "%d%%", (gint) (percent * 100.0f));
76
77 gtk_progress_bar_set_fraction (progress, percent);
78 gtk_progress_bar_set_text (progress, text);
79
80 while (gtk_events_pending ())
81 gtk_main_iteration ();
82 }
83
84 enum {
85 CP_UNIQUE = 0,
86 CP_OVERWRITE,
87 CP_APPEND
88 };
89
90 static gint open_flags[3] = {
91 O_WRONLY | O_CREAT | O_TRUNC,
92 O_WRONLY | O_CREAT | O_TRUNC,
93 O_WRONLY | O_CREAT | O_APPEND,
94 };
95
96 static gboolean
97 cp (const gchar *src,
98 const gchar *dest,
99 gboolean show_progress,
100 gint mode)
101 {
102 guchar readbuf[65536];
103 gssize nread, nwritten;
104 gint errnosav, readfd, writefd;
105 gsize total = 0;
106 struct stat st;
107 struct utimbuf ut;
108
109 /* if the dest file exists and has content, abort - we don't
110 * want to corrupt their existing data */
111 if (g_stat (dest, &st) == 0 && st.st_size > 0 && mode == CP_UNIQUE) {
112 errno = EEXIST;
113 return FALSE;
114 }
115
116 if (g_stat (src, &st) == -1
117 || (readfd = g_open (src, O_RDONLY | O_BINARY, 0)) == -1)
118 return FALSE;
119
120 if ((writefd = g_open (dest, open_flags[mode] | O_BINARY, 0666)) == -1) {
121 errnosav = errno;
122 close (readfd);
123 errno = errnosav;
124 return FALSE;
125 }
126
127 do {
128 do {
129 nread = read (readfd, readbuf, sizeof (readbuf));
130 } while (nread == -1 && errno == EINTR);
131
132 if (nread == 0)
133 break;
134 else if (nread < 0)
135 goto exception;
136
137 do {
138 nwritten = write (writefd, readbuf, nread);
139 } while (nwritten == -1 && errno == EINTR);
140
141 if (nwritten < nread)
142 goto exception;
143
144 total += nwritten;
145 if (show_progress)
146 em_migrate_set_progress (((gdouble) total) / ((gdouble) st.st_size));
147 } while (total < st.st_size);
148
149 if (fsync (writefd) == -1)
150 goto exception;
151
152 close (readfd);
153 if (close (writefd) == -1)
154 goto failclose;
155
156 ut.actime = st.st_atime;
157 ut.modtime = st.st_mtime;
158 utime (dest, &ut);
159 chmod (dest, st.st_mode);
160
161 return TRUE;
162
163 exception:
164
165 errnosav = errno;
166 close (readfd);
167 close (writefd);
168 errno = errnosav;
169
170 failclose:
171
172 errnosav = errno;
173 unlink (dest);
174 errno = errnosav;
175
176 return FALSE;
177 }
178
179 static gboolean
180 emm_setup_initial (const gchar *data_dir)
181 {
182 GDir *dir;
183 const gchar *d;
184 gchar *local = NULL, *base;
185 const gchar * const *language_names;
186
187 /* special-case - this means brand new install of evolution */
188 /* FIXME: create default folders and stuff... */
189
190 d (printf ("Setting up initial mail tree\n"));
191
192 base = g_build_filename (data_dir, "local", NULL);
193 if (g_mkdir_with_parents (base, 0700) == -1 && errno != EEXIST) {
194 g_free (base);
195 return FALSE;
196 }
197
198 /* e.g. try en-AU then en, etc */
199 language_names = g_get_language_names ();
200 while (*language_names != NULL) {
201 local = g_build_filename (
202 EVOLUTION_PRIVDATADIR, "default",
203 *language_names, "mail", "local", NULL);
204 if (g_file_test (local, G_FILE_TEST_EXISTS))
205 break;
206 g_free (local);
207 language_names++;
208 }
209
210 /* Make sure we found one. */
211 g_return_val_if_fail (*language_names != NULL, FALSE);
212
213 dir = g_dir_open (local, 0, NULL);
214 if (dir) {
215 while ((d = g_dir_read_name (dir))) {
216 gchar *src, *dest;
217
218 src = g_build_filename (local, d, NULL);
219 dest = g_build_filename (base, d, NULL);
220
221 cp (src, dest, FALSE, CP_UNIQUE);
222 g_free (dest);
223 g_free (src);
224 }
225 g_dir_close (dir);
226 }
227
228 g_free (local);
229 g_free (base);
230
231 return TRUE;
232 }
233
234 static void
235 em_rename_view_in_folder (gpointer data,
236 gpointer user_data)
237 {
238 const gchar *filename = data;
239 const gchar *views_dir = user_data;
240 gchar *folderpos, *dotpos;
241
242 g_return_if_fail (filename != NULL);
243 g_return_if_fail (views_dir != NULL);
244
245 folderpos = strstr (filename, "-folder:__");
246 if (!folderpos)
247 folderpos = strstr (filename, "-folder___");
248 if (!folderpos)
249 return;
250
251 /* points on 'f' from the "folder" word */
252 folderpos++;
253 dotpos = strrchr (filename, '.');
254 if (folderpos < dotpos && g_str_equal (dotpos, ".xml")) {
255 GChecksum *checksum;
256 gchar *oldname, *newname, *newfile;
257 const gchar *md5_string;
258
259 *dotpos = 0;
260
261 /* use MD5 checksum of the folder URI, to not depend on its length */
262 checksum = g_checksum_new (G_CHECKSUM_MD5);
263 g_checksum_update (checksum, (const guchar *) folderpos, -1);
264
265 *folderpos = 0;
266 md5_string = g_checksum_get_string (checksum);
267 newfile = g_strconcat (filename, md5_string, ".xml", NULL);
268 *folderpos = 'f';
269 *dotpos = '.';
270
271 oldname = g_build_filename (views_dir, filename, NULL);
272 newname = g_build_filename (views_dir, newfile, NULL);
273
274 g_rename (oldname, newname);
275
276 g_checksum_free (checksum);
277 g_free (oldname);
278 g_free (newname);
279 g_free (newfile);
280 }
281 }
282
283 static void
284 em_rename_folder_views (EShellBackend *shell_backend)
285 {
286 const gchar *config_dir;
287 gchar *views_dir;
288 GDir *dir;
289
290 g_return_if_fail (shell_backend != NULL);
291
292 config_dir = e_shell_backend_get_config_dir (shell_backend);
293 views_dir = g_build_filename (config_dir, "views", NULL);
294
295 dir = g_dir_open (views_dir, 0, NULL);
296 if (dir) {
297 GSList *to_rename = NULL;
298 const gchar *filename;
299
300 while (filename = g_dir_read_name (dir), filename) {
301 if (strstr (filename, "-folder:__") ||
302 strstr (filename, "-folder___"))
303 to_rename = g_slist_prepend (to_rename, g_strdup (filename));
304 }
305
306 g_dir_close (dir);
307
308 g_slist_foreach (to_rename, em_rename_view_in_folder, views_dir);
309 g_slist_free_full (to_rename, g_free);
310 }
311
312 g_free (views_dir);
313 }
314
315 gboolean
316 e_mail_migrate (EShellBackend *shell_backend,
317 gint major,
318 gint minor,
319 gint micro,
320 GError **error)
321 {
322 struct stat st;
323 const gchar *data_dir;
324
325 /* make sure ~/.evolution/mail exists */
326 data_dir = e_shell_backend_get_data_dir (shell_backend);
327 if (g_stat (data_dir, &st) == -1) {
328 if (errno != ENOENT || g_mkdir_with_parents (data_dir, 0700) == -1) {
329 g_set_error (
330 error, E_SHELL_MIGRATE_ERROR,
331 E_SHELL_MIGRATE_ERROR_FAILED,
332 _("Unable to create local mail folders at "
333 "'%s': %s"), data_dir, g_strerror (errno));
334 return FALSE;
335 }
336 }
337
338 if (major == 0)
339 return emm_setup_initial (data_dir);
340
341 if (major <= 2 || (major == 3 && minor < 4))
342 em_rename_folder_views (shell_backend);
343
344 return TRUE;
345 }