evolution-3.6.4/plugins/dbx-import/dbx-importer.c

Location Tool Test ID Function Issue
dbx-importer.c:457:12 gcc unused-result dbx_read_mail_body ignoring return value of 'ftruncate', declared with attribute warn_unused_result
dbx-importer.c:457:12 gcc unused-result dbx_read_mail_body ignoring return value of 'ftruncate', declared with attribute warn_unused_result
  1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
  2 /* dbx-importer.c
  3 *
  4 * Author: David Woodhouse <dwmw2@infradead.org>
  5 *
  6 * Copyright © 2010 Intel Corporation
  7 *
  8 * Evolution parts largely lifted from pst-import.c:
  9 *   Author: Chris Halls <chris.halls@credativ.co.uk>
 10 *	    Bharath Acharya <abharath@novell.com>
 11 *   Copyright © 2006 Chris Halls
 12 *
 13 * Some DBX bits from libdbx:
 14 *   Author: David Smith <Dave.S@Earthcorp.Com>
 15 *    Copyright © 2001 David Smith
 16 *
 17 * This program is free software; you can redistribute it and/or
 18 * modify it under the terms of the GNU Lesser General Public
 19 * License as published by the Free Software Foundation; either
 20 * version 2 of the License, or (at your option) version 3.
 21 *
 22 * This program is distributed in the hope that it will be useful,
 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 25 * Lesser General Public License for more details.
 26 *
 27 * You should have received a copy of the GNU Lesser General Public
 28 * License along with the program; if not, see <http://www.gnu.org/licenses/>
 29 *
 30 */
 31 
 32 #ifdef HAVE_CONFIG_H
 33 #include <config.h>
 34 #endif
 35 
 36 #define G_LOG_DOMAIN "eplugin-readdbx"
 37 
 38 #include <sys/types.h>
 39 #include <sys/stat.h>
 40 #include <fcntl.h>
 41 #include <string.h>
 42 #include <unistd.h>
 43 #include <errno.h>
 44 
 45 #include <glib/gi18n-lib.h>
 46 #include <glib/gstdio.h>
 47 #include <glib/gprintf.h>
 48 
 49 #include <gtk/gtk.h>
 50 #include <libecal/libecal.h>
 51 #include <libebook/libebook.h>
 52 #include <libedataserverui/libedataserverui.h>
 53 
 54 #include <e-util/e-import.h>
 55 #include <e-util/e-plugin.h>
 56 #include <e-util/e-mktemp.h>
 57 
 58 #include <shell/e-shell.h>
 59 #include <shell/e-shell-window.h>
 60 #include <shell/e-shell-view.h>
 61 
 62 #include <libemail-utils/mail-mt.h>
 63 #include <libemail-engine/mail-tools.h>
 64 
 65 #include <mail/e-mail-backend.h>
 66 #include <mail/em-folder-selection-button.h>
 67 #include <mail/em-utils.h>
 68 
 69 #define d(x)
 70 
 71 #ifdef WIN32
 72 #ifdef gmtime_r
 73 #undef gmtime_r
 74 #endif
 75 #define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
 76 #endif
 77 
 78 gboolean	org_gnome_evolution_readdbx_supported
 79 						(EPlugin *epl,
 80 						 EImportTarget *target);
 81 GtkWidget *	org_gnome_evolution_readdbx_getwidget
 82 						(EImport *ei,
 83 						 EImportTarget *target,
 84 						 EImportImporter *im);
 85 void		org_gnome_evolution_readdbx_import
 86 						(EImport *ei,
 87 						 EImportTarget *target,
 88 						 EImportImporter *im);
 89 void		org_gnome_evolution_readdbx_cancel
 90 						(EImport *ei,
 91 						 EImportTarget *target,
 92 						 EImportImporter *im);
 93 gint		e_plugin_lib_enable		(EPlugin *ep,
 94 						 gint enable);
 95 
 96 /* em-folder-selection-button.h is private, even though other internal
 97  * evo plugins use it!
 98  * so declare the functions here
 99  * TODO: sort out whether this should really be private
100 */
101 
102 typedef struct {
103 	MailMsg base;
104 
105 	EImport *import;
106 	EImportTarget *target;
107 
108 	GMutex *status_lock;
109 	gchar *status_what;
110 	gint status_pc;
111 	gint status_timeout_id;
112 	GCancellable *cancellable;
113 
114 	guint32 *indices;
115 	guint32 index_count;
116 
117 	gchar *uri;
118 	gint dbx_fd;
119 
120 	CamelOperation *cancel;
121 	CamelFolder *folder;
122 	gchar *parent_uri;
123 	gchar *folder_name;
124 	gchar *folder_uri;
125 	gint folder_count;
126 	gint current_item;
127 } DbxImporter;
128 
129 static guchar oe56_mbox_sig[16] = {
130 	0xcf, 0xad, 0x12, 0xfe, 0xc5, 0xfd, 0x74, 0x6f,
131 	0x66, 0xe3, 0xd1, 0x11, 0x9a, 0x4e, 0x00, 0xc0
132 };
133 static guchar oe56_flist_sig[16] = {
134 	0xcf, 0xad, 0x12, 0xfe, 0xc6, 0xfd, 0x74, 0x6f,
135 	0x66, 0xe3, 0xd1, 0x11, 0x9a, 0x4e, 0x00, 0xc0
136 };
137 static guchar oe4_mbox_sig[8] = {
138 	0x4a, 0x4d, 0x46, 0x36, 0x03, 0x00, 0x01, 0x00
139 };
140 
141 gboolean
142 org_gnome_evolution_readdbx_supported (EPlugin *epl,
143                                        EImportTarget *target)
144 {
145 	gchar signature[16];
146 	gboolean ret = FALSE;
147 	gint fd, n;
148 	EImportTargetURI *s;
149 	gchar *filename;
150 
151 	if (target->type != E_IMPORT_TARGET_URI) {
152 		return FALSE;
153 	}
154 
155 	s = (EImportTargetURI *) target;
156 
157 	if (s->uri_src == NULL) {
158 		return TRUE;
159 	}
160 
161 	if (strncmp (s->uri_src, "file:///", strlen ("file:///")) != 0) {
162 		return FALSE;
163 	}
164 
165 	filename = g_filename_from_uri (s->uri_src, NULL, NULL);
166 	fd = g_open (filename, O_RDONLY, 0);
167 	g_free (filename);
168 
169 	if (fd != -1) {
170 		n = read (fd, signature, sizeof (signature));
171 		if (n == sizeof (signature)) {
172 			if (!memcmp (signature, oe56_mbox_sig, sizeof (oe56_mbox_sig))) {
173 				ret = TRUE;
174 			} else if (!memcmp (signature, oe56_flist_sig, sizeof (oe56_flist_sig))) {
175 				d (printf ("Found DBX folder list file\n"));
176 			} else if (!memcmp (signature, oe4_mbox_sig, sizeof (oe4_mbox_sig))) {
177 				d (printf ("Found OE4 DBX file\n"));
178 			}
179 		}
180 		close (fd);
181 	}
182 
183 	return ret;
184 }
185 
186 static void
187 folder_selected (EMFolderSelectionButton *button,
188                  EImportTargetURI *target)
189 {
190 	g_free (target->uri_dest);
191 	target->uri_dest = g_strdup (em_folder_selection_button_get_folder_uri (button));
192 }
193 
194 GtkWidget *
195 org_gnome_evolution_readdbx_getwidget (EImport *ei,
196                                        EImportTarget *target,
197                                        EImportImporter *im)
198 {
199 	EShell *shell;
200 	EShellBackend *shell_backend;
201 	EMailBackend *backend;
202 	EMailSession *session;
203 	GtkWidget *hbox, *w;
204 	GtkLabel *label;
205 	gchar *select_uri = NULL;
206 
207 #if 1
208 	GtkWindow *window;
209 	/* preselect the folder selected in a mail view */
210 	window = e_shell_get_active_window (e_shell_get_default ());
211 	if (E_IS_SHELL_WINDOW (window)) {
212 		EShellWindow *shell_window;
213 		const gchar *view;
214 
215 		shell_window = E_SHELL_WINDOW (window);
216 		view = e_shell_window_get_active_view (shell_window);
217 
218 		if (view && g_str_equal (view, "mail")) {
219 			EShellView *shell_view;
220 			EMFolderTree *folder_tree = NULL;
221 			EShellSidebar *shell_sidebar;
222 
223 			shell_view = e_shell_window_get_shell_view (
224 				shell_window, view);
225 
226 			shell_sidebar = e_shell_view_get_shell_sidebar (
227 				shell_view);
228 
229 			g_object_get (
230 				shell_sidebar, "folder-tree",
231 				&folder_tree, NULL);
232 
233 			select_uri = em_folder_tree_get_selected_uri (
234 				folder_tree);
235 		}
236 	}
237 #endif
238 
239 	shell = e_shell_get_default ();
240 	shell_backend = e_shell_get_backend_by_name (shell, "mail");
241 
242 	backend = E_MAIL_BACKEND (shell_backend);
243 	session = e_mail_backend_get_session (backend);
244 
245 	if (!select_uri) {
246 		const gchar *local_inbox_uri;
247 		local_inbox_uri =
248 			e_mail_session_get_local_folder_uri (
249 			session, E_MAIL_LOCAL_FOLDER_INBOX);
250 		select_uri = g_strdup (local_inbox_uri);
251 	}
252 
253 	hbox = gtk_hbox_new (FALSE, 0);
254 
255 	w = gtk_label_new_with_mnemonic (_("_Destination folder:"));
256 	gtk_box_pack_start ((GtkBox *) hbox, w, FALSE, TRUE, 6);
257 
258 	label = GTK_LABEL (w);
259 
260 	w = em_folder_selection_button_new (
261 		session, _("Select folder"),
262 		_("Select folder to import into"));
263 
264 	gtk_label_set_mnemonic_widget (label, w);
265 	em_folder_selection_button_set_folder_uri (
266 		EM_FOLDER_SELECTION_BUTTON (w), select_uri);
267 	folder_selected (
268 		EM_FOLDER_SELECTION_BUTTON (w), (EImportTargetURI *) target);
269 	g_signal_connect (
270 		w, "selected",
271 		G_CALLBACK (folder_selected), target);
272 	gtk_box_pack_start ((GtkBox *) hbox, w, FALSE, TRUE, 6);
273 
274 	w = gtk_vbox_new (FALSE, 0);
275 	gtk_box_pack_start ((GtkBox *) w, hbox, FALSE, FALSE, 0);
276 	gtk_widget_show_all (w);
277 
278 	g_free (select_uri);
279 
280 	return w;
281 }
282 
283 static gchar *
284 dbx_import_describe (DbxImporter *m,
285                      gint complete)
286 {
287 	return g_strdup (_("Importing Outlook Express data"));
288 }
289 
290 /* Types taken from libdbx and fixed */
291 struct _dbx_tableindexstruct {
292 	guint32 self;
293 	guint32 unknown1;
294 	guint32 anotherTablePtr;
295 	guint32 parent;
296 	gchar unknown2;
297 	gchar ptrCount;
298 	gchar reserve3;
299 	gchar reserve4;
300 	guint32 indexCount;
301 };
302 
303 struct _dbx_indexstruct {
304 	guint32 indexptr;
305 	guint32 anotherTablePtr;
306 	guint32 indexCount;
307 };
308 
309 #define INDEX_POINTER 0xE4
310 #define ITEM_COUNT 0xC4
311 
312 struct _dbx_email_headerstruct {
313 	guint32 self;
314 	guint32 size;
315 	gushort u1;
316 	guchar count;
317 	guchar u2;
318 };
319 
320 struct _dbx_block_hdrstruct {
321 	guint32 self;
322 	guint32 nextaddressoffset;
323 	gushort blocksize;
324 	guchar intcount;
325 	guchar unknown1;
326 	guint32 nextaddress;
327 };
328 
329 static gint dbx_pread (gint fd, gpointer buf, guint32 count, guint32 offset)
330 {
331 	if (lseek (fd, offset, SEEK_SET) != offset)
332 		return -1;
333 	return read (fd, buf, count);
334 }
335 
336 static gboolean dbx_load_index_table (DbxImporter *m, guint32 pos, guint32 *index_ofs)
337 {
338 	struct _dbx_tableindexstruct tindex;
339 	struct _dbx_indexstruct index;
340 	gint i;
341 
342 	d (printf ("Loading index table at 0x%x\n", pos));
343 
344 	if (dbx_pread (m->dbx_fd, &tindex, sizeof (tindex), pos) != sizeof (tindex)) {
345 		g_set_error (
346 			&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
347 			"Failed to read table index from DBX file");
348 		return FALSE;
349 	}
350 	tindex.anotherTablePtr = GUINT32_FROM_LE (tindex.anotherTablePtr);
351 	tindex.self = GUINT32_FROM_LE (tindex.self);
352 	tindex.indexCount = GUINT32_FROM_LE (tindex.indexCount);
353 
354 	if (tindex.self != pos) {
355 		g_set_error (
356 			&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
357 			"Corrupt DBX file: Index table at 0x%x does not "
358 			"point to itself", pos);
359 		return FALSE;
360 	}
361 
362 	d (
363 		printf ("Index at %x: indexCount %x, anotherTablePtr %x\n",
364 		pos, tindex.indexCount, tindex.anotherTablePtr));
365 
366 	if (tindex.indexCount > 0) {
367 		if (!dbx_load_index_table (m, tindex.anotherTablePtr, index_ofs))
368 			return FALSE;
369 	}
370 
371 	d (printf ("Index at %x has ptrCount %d\n", pos, tindex.ptrCount));
372 
373 	pos += sizeof (tindex);
374 
375 	for (i = 0; i < tindex.ptrCount; i++) {
376 		if (dbx_pread (m->dbx_fd, &index, sizeof (index), pos) != sizeof (index)) {
377 			g_set_error (
378 				&m->base.error,
379 				CAMEL_ERROR, CAMEL_ERROR_GENERIC,
380 				"Failed to read index entry from DBX file");
381 			return FALSE;
382 		}
383 		index.indexptr = GUINT32_FROM_LE (index.indexptr);
384 		index.anotherTablePtr = GUINT32_FROM_LE (index.anotherTablePtr);
385 		index.indexCount = GUINT32_FROM_LE (index.indexCount);
386 
387 		if (*index_ofs == m->index_count) {
388 			g_set_error (
389 				&m->base.error,
390 				CAMEL_ERROR, CAMEL_ERROR_GENERIC,
391 				"Corrupt DBX file: Seems to contain more "
392 				"than %d entries claimed in its header",
393 				m->index_count);
394 			return FALSE;
395 		}
396 		m->indices[(*index_ofs)++] = index.indexptr;
397 		if (index.indexCount > 0) {
398 			if (!dbx_load_index_table (m, index.anotherTablePtr, index_ofs))
399 				return FALSE;
400 		}
401 		pos += sizeof (index);
402 	}
403 	return TRUE;
404 }
405 static gboolean dbx_load_indices (DbxImporter *m)
406 {
407 	guint indexptr, itemcount;
408 	guint32 index_ofs = 0;
409 
410 	if (dbx_pread (m->dbx_fd, &indexptr, 4, INDEX_POINTER) != 4) {
411 		g_set_error (
412 			&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
413 			"Failed to read first index pointer from DBX file");
414 		return FALSE;
415 	}
416 
417 	if (dbx_pread (m->dbx_fd, &itemcount, 4, ITEM_COUNT) != 4) {
418 		g_set_error (
419 			&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
420 			"Failed to read item count from DBX file");
421 		return FALSE;
422 	}
423 
424 	indexptr = GUINT32_FROM_LE (indexptr);
425 	m->index_count = itemcount = GUINT32_FROM_LE (itemcount);
426 	m->indices = g_malloc (itemcount * 4);
427 
428 	d (printf ("indexptr %x, itemcount %d\n", indexptr, itemcount));
429 
430 	if (indexptr && !dbx_load_index_table (m, indexptr, &index_ofs))
431 		return FALSE;
432 
433 	d (printf ("Loaded %d of %d indices\n", index_ofs, m->index_count));
434 
435 	if (index_ofs < m->index_count) {
436 		g_set_error (
437 			&m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
438 			"Corrupt DBX file: Seems to contain fewer than %d "
439 			"entries claimed in its header", m->index_count);
440 		return FALSE;
441 	}
442 	return TRUE;
443 }
444 
445 static gboolean
446 dbx_read_mail_body (DbxImporter *m,
447                     guint32 offset,
448                     gint bodyfd)
449 {
450 	/* FIXME: We really ought to set up CamelStream that we can feed to the
451 	 * MIME parser, rather than using a temporary file */
452 
453 	struct _dbx_block_hdrstruct hdr;
454 	guint32 buflen = 0x200;
455 	guchar *buffer = g_malloc (buflen);
456 
457 	ftruncate (bodyfd, 0);
ignoring return value of 'ftruncate', declared with attribute warn_unused_result
(emitted by gcc)
ignoring return value of 'ftruncate', declared with attribute warn_unused_result
(emitted by gcc)
458 lseek (bodyfd, 0, SEEK_SET); 459 460 while (offset) { 461 d (printf ("Reading mail data chunk from %x\n", offset)); 462 463 if (dbx_pread (m->dbx_fd, &hdr, sizeof (hdr), offset) != sizeof (hdr)) { 464 g_set_error ( 465 &m->base.error, 466 CAMEL_ERROR, CAMEL_ERROR_GENERIC, 467 "Failed to read mail data block from " 468 "DBX file at offset %x", offset); 469 return FALSE; 470 } 471 hdr.self = GUINT32_FROM_LE (hdr.self); 472 hdr.blocksize = GUINT16_FROM_LE (hdr.blocksize); 473 hdr.nextaddress = GUINT32_FROM_LE (hdr.nextaddress); 474 475 if (hdr.self != offset) { 476 g_set_error ( 477 &m->base.error, 478 CAMEL_ERROR, CAMEL_ERROR_GENERIC, 479 "Corrupt DBX file: Mail data block at " 480 "0x%x does not point to itself", offset); 481 return FALSE; 482 } 483 484 if (hdr.blocksize > buflen) { 485 g_free (buffer); 486 buflen = hdr.blocksize; 487 buffer = g_malloc (buflen); 488 } 489 if (dbx_pread (m->dbx_fd, buffer, hdr.blocksize, 490 offset + sizeof (hdr)) != hdr.blocksize) { 491 g_set_error ( 492 &m->base.error, 493 CAMEL_ERROR, CAMEL_ERROR_GENERIC, 494 "Failed to read mail data from DBX file " 495 "at offset %lx", 496 (long)(offset + sizeof (hdr))); 497 return FALSE; 498 } 499 if (write (bodyfd, buffer, hdr.blocksize) != hdr.blocksize) { 500 g_set_error ( 501 &m->base.error, 502 CAMEL_ERROR, CAMEL_ERROR_GENERIC, 503 "Failed to write mail data to temporary file"); 504 return FALSE; 505 } 506 offset = hdr.nextaddress; 507 } 508 return TRUE; 509 } 510 511 static gboolean 512 dbx_read_email (DbxImporter *m, 513 guint32 offset, 514 gint bodyfd, 515 gint *flags) 516 { 517 struct _dbx_email_headerstruct hdr; 518 guchar *buffer; 519 guint32 dataptr = 0; 520 gint i; 521 522 if (dbx_pread (m->dbx_fd, &hdr, sizeof (hdr), offset) != sizeof (hdr)) { 523 g_set_error ( 524 &m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, 525 "Failed to read mail header from DBX file at offset %x", 526 offset); 527 return FALSE; 528 } 529 hdr.self = GUINT32_FROM_LE (hdr.self); 530 hdr.size = GUINT32_FROM_LE (hdr.size); 531 532 if (hdr.self != offset) { 533 g_set_error ( 534 &m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, 535 "Corrupt DBX file: Mail header at 0x%x does not " 536 "point to itself", offset); 537 return FALSE; 538 } 539 buffer = g_malloc (hdr.size); 540 offset += sizeof (hdr); 541 if (dbx_pread (m->dbx_fd, buffer, hdr.size, offset) != hdr.size) { 542 g_set_error ( 543 &m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, 544 "Failed to read mail data block from DBX file " 545 "at offset %x", offset); 546 g_free (buffer); 547 return FALSE; 548 } 549 550 for (i = 0; i < hdr.count; i++) { 551 guchar type = buffer[i *4]; 552 gint val; 553 554 val = buffer[i *4 + 1] + 555 (buffer[i *4 + 2] << 8) + 556 (buffer[i *4 + 3] << 16); 557 558 switch (type) { 559 case 0x01: 560 *flags = buffer[hdr.count*4 + val]; 561 d (printf ("Got type 0x01 flags %02x\n", *flags)); 562 break; 563 case 0x81: 564 *flags = val; 565 d (printf ("Got type 0x81 flags %02x\n", *flags)); 566 break; 567 case 0x04: 568 dataptr = GUINT32_FROM_LE (*(guint32 *)(buffer + hdr.count *4 + val)); 569 d (printf ("Got type 0x04 data pointer %x\n", dataptr)); 570 break; 571 case 0x84: 572 dataptr = val; 573 d (printf ("Got type 0x84 data pointer %x\n", dataptr)); 574 break; 575 default: 576 /* We don't care about anything else */ 577 d (printf ("Ignoring type %02x datum\n", type)); 578 break; 579 } 580 } 581 g_free (buffer); 582 583 if (!dataptr) 584 return FALSE; 585 586 return dbx_read_mail_body (m, dataptr, bodyfd); 587 } 588 589 static void 590 dbx_import_file (DbxImporter *m) 591 { 592 EShell *shell; 593 EShellBackend *shell_backend; 594 EMailSession *session; 595 GCancellable *cancellable; 596 gchar *filename; 597 CamelFolder *folder; 598 gint tmpfile; 599 gint i; 600 gint missing = 0; 601 m->status_what = NULL; 602 filename = g_filename_from_uri ( 603 ((EImportTargetURI *) m->target)->uri_src, NULL, NULL); 604 605 /* Destination folder, was set in our widget */ 606 m->parent_uri = g_strdup (((EImportTargetURI *) m->target)->uri_dest); 607 608 cancellable = m->base.cancellable; 609 610 /* XXX Dig up the EMailSession from the default EShell. 611 * Since the EImport framework doesn't allow for user 612 * data, I don't see how else to get to it. */ 613 shell = e_shell_get_default (); 614 shell_backend = e_shell_get_backend_by_name (shell, "mail"); 615 session = e_mail_backend_get_session (E_MAIL_BACKEND (shell_backend)); 616 617 camel_operation_push_message (NULL, _("Importing '%s'"), filename); 618 folder = e_mail_session_uri_to_folder_sync ( 619 session, m->parent_uri, CAMEL_STORE_FOLDER_CREATE, 620 cancellable, &m->base.error); 621 if (!folder) 622 return; 623 d (printf ("importing to %s\n", camel_folder_get_full_name (folder))); 624 625 camel_folder_freeze (folder); 626 627 filename = g_filename_from_uri ( 628 ((EImportTargetURI *) m->target)->uri_src, NULL, NULL); 629 m->dbx_fd = g_open (filename, O_RDONLY, 0); 630 g_free (filename); 631 632 if (m->dbx_fd == -1) { 633 g_set_error ( 634 &m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, 635 "Failed to open import file"); 636 goto out; 637 } 638 639 if (!dbx_load_indices (m)) 640 goto out; 641 642 tmpfile = e_mkstemp ("dbx-import-XXXXXX"); 643 if (tmpfile == -1) { 644 g_set_error ( 645 &m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, 646 "Failed to create temporary file for import"); 647 goto out; 648 } 649 650 for (i = 0; i < m->index_count; i++) { 651 CamelMessageInfo *info; 652 CamelMimeMessage *msg; 653 CamelMimeParser *mp; 654 gint dbx_flags = 0; 655 gint flags = 0; 656 gboolean success; 657 658 camel_operation_progress (NULL, 100 * i / m->index_count); 659 camel_operation_progress (cancellable, 100 * i / m->index_count); 660 661 if (!dbx_read_email (m, m->indices[i], tmpfile, &dbx_flags)) { 662 d ( 663 printf ("Cannot read email index %d at %x\n", 664 i, m->indices[i])); 665 if (m->base.error != NULL) 666 goto out; 667 missing++; 668 continue; 669 } 670 if (dbx_flags & 0x40) 671 flags |= CAMEL_MESSAGE_DELETED; 672 if (dbx_flags & 0x80) 673 flags |= CAMEL_MESSAGE_SEEN; 674 if (dbx_flags & 0x80000) 675 flags |= CAMEL_MESSAGE_ANSWERED; 676 677 mp = camel_mime_parser_new (); 678 679 lseek (tmpfile, 0, SEEK_SET); 680 camel_mime_parser_init_with_fd (mp, tmpfile); 681 682 msg = camel_mime_message_new (); 683 if (!camel_mime_part_construct_from_parser_sync ( 684 (CamelMimePart *) msg, mp, NULL, NULL)) { 685 /* set exception? */ 686 g_object_unref (msg); 687 g_object_unref (mp); 688 break; 689 } 690 691 info = camel_message_info_new (NULL); 692 camel_message_info_set_flags (info, flags, ~0); 693 success = camel_folder_append_message_sync ( 694 folder, msg, info, NULL, 695 cancellable, &m->base.error); 696 camel_message_info_free (info); 697 g_object_unref (msg); 698 699 if (!success) { 700 g_object_unref (mp); 701 break; 702 } 703 } 704 out: 705 if (m->dbx_fd != -1) 706 close (m->dbx_fd); 707 if (m->indices) 708 g_free (m->indices); 709 /* FIXME Not passing GCancellable or GError here. */ 710 camel_folder_synchronize_sync (folder, FALSE, NULL, NULL); 711 camel_folder_thaw (folder); 712 g_object_unref (folder); 713 if (missing && m->base.error == NULL) { 714 g_set_error ( 715 &m->base.error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, 716 "%d messages imported correctly; %d message " 717 "bodies were not present in the DBX file", 718 m->index_count - missing, missing); 719 } 720 camel_operation_pop_message (NULL); 721 } 722 723 static void 724 dbx_import_import (DbxImporter *m, 725 GCancellable *cancellable, 726 GError **error) 727 { 728 dbx_import_file (m); 729 } 730 731 static void 732 dbx_import_imported (DbxImporter *m) 733 { 734 e_import_complete (m->target->import, (EImportTarget *) m->target); 735 } 736 737 static void 738 dbx_import_free (DbxImporter *m) 739 { 740 g_free (m->status_what); 741 g_mutex_free (m->status_lock); 742 743 g_source_remove (m->status_timeout_id); 744 m->status_timeout_id = 0; 745 746 g_free (m->folder_name); 747 g_free (m->folder_uri); 748 g_free (m->parent_uri); 749 750 g_object_unref (m->import); 751 } 752 753 static MailMsgInfo dbx_import_info = { 754 sizeof (DbxImporter), 755 (MailMsgDescFunc) dbx_import_describe, 756 (MailMsgExecFunc) dbx_import_import, 757 (MailMsgDoneFunc) dbx_import_imported, 758 (MailMsgFreeFunc) dbx_import_free, 759 }; 760 761 static gboolean 762 dbx_status_timeout (gpointer data) 763 { 764 DbxImporter *importer = data; 765 gint pc; 766 gchar *what; 767 768 if (importer->status_what) { 769 g_mutex_lock (importer->status_lock); 770 what = importer->status_what; 771 importer->status_what = NULL; 772 pc = importer->status_pc; 773 g_mutex_unlock (importer->status_lock); 774 775 e_import_status ( 776 importer->target->import, 777 (EImportTarget *) importer->target, what, pc); 778 } 779 780 return TRUE; 781 } 782 783 static void 784 dbx_status (CamelOperation *op, 785 const gchar *what, 786 gint pc, 787 gpointer data) 788 { 789 DbxImporter *importer = data; 790 791 g_mutex_lock (importer->status_lock); 792 g_free (importer->status_what); 793 importer->status_what = g_strdup (what); 794 importer->status_pc = pc; 795 g_mutex_unlock (importer->status_lock); 796 } 797 798 /* Start the main import operation */ 799 void 800 org_gnome_evolution_readdbx_import (EImport *ei, 801 EImportTarget *target, 802 EImportImporter *im) 803 { 804 DbxImporter *m; 805 806 m = mail_msg_new (&dbx_import_info); 807 g_datalist_set_data (&target->data, "dbx-msg", m); 808 m->import = ei; 809 g_object_ref (m->import); 810 m->target = target; 811 812 m->parent_uri = NULL; 813 m->folder_name = NULL; 814 m->folder_uri = NULL; 815 816 m->status_timeout_id = g_timeout_add (100, dbx_status_timeout, m); 817 /*m->status_timeout_id = NULL;*/ 818 m->status_lock = g_mutex_new (); 819 m->cancellable = camel_operation_new (); 820 821 g_signal_connect ( 822 m->cancellable, "status", 823 G_CALLBACK (dbx_status), m); 824 825 mail_msg_unordered_push (m); 826 } 827 828 void 829 org_gnome_evolution_readdbx_cancel (EImport *ei, 830 EImportTarget *target, 831 EImportImporter *im) 832 { 833 DbxImporter *m = g_datalist_get_data (&target->data, "dbx-msg"); 834 835 if (m) { 836 g_cancellable_cancel (m->cancellable); 837 } 838 } 839 840 gint 841 e_plugin_lib_enable (EPlugin *ep, 842 gint enable) 843 { 844 return 0; 845 }