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

Location Tool Test ID Function Issue
pst-importer.c:870:31 clang-analyzer Access to field 'next' results in a dereference of a null pointer (loaded from variable 'd_ptr')
pst-importer.c:870:31 clang-analyzer Access to field 'next' results in a dereference of a null pointer (loaded from variable 'd_ptr')
   1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
   2 /* pst-importer.c
   3 *
   4 * Author: Chris Halls <chris.halls@credativ.co.uk>
   5 *	  Bharath Acharya <abharath@novell.com>
   6 *
   7 * Copyright (C) 2006  Chris Halls
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation; either
  12 * version 2 of the License, or (at your option) version 3.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17 * Lesser General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with the program; if not, see <http://www.gnu.org/licenses/>
  21 *
  22 */
  23 
  24 #ifdef HAVE_CONFIG_H
  25 #include <config.h>
  26 #endif
  27 
  28 #define G_LOG_DOMAIN "eplugin-readpst"
  29 
  30 #include <sys/types.h>
  31 #include <sys/stat.h>
  32 #include <fcntl.h>
  33 #include <string.h>
  34 #include <unistd.h>
  35 #include <errno.h>
  36 
  37 #include <glib/gi18n-lib.h>
  38 #include <glib/gstdio.h>
  39 #include <glib/gprintf.h>
  40 
  41 #include <gtk/gtk.h>
  42 #include <libecal/libecal.h>
  43 #include <libebook/libebook.h>
  44 #include <libedataserverui/libedataserverui.h>
  45 
  46 #include <e-util/e-import.h>
  47 #include <e-util/e-plugin.h>
  48 
  49 #include <libemail-utils/mail-mt.h>
  50 #include <libemail-engine/mail-tools.h>
  51 
  52 #include <mail/e-mail-backend.h>
  53 #include <mail/em-folder-selection-button.h>
  54 #include <mail/em-utils.h>
  55 #include <shell/e-shell.h>
  56 #include <shell/e-shell-window.h>
  57 #include <shell/e-shell-view.h>
  58 #include <shell/e-shell-sidebar.h>
  59 
  60 #include <libpst/libpst.h>
  61 #include <libpst/timeconv.h>
  62 
  63 #ifdef WIN32
  64 #ifdef gmtime_r
  65 #undef gmtime_r
  66 #endif
  67 #define gmtime_r(tp,tmp) (gmtime(tp)?(*(tmp)=*gmtime(tp),(tmp)):0)
  68 #endif
  69 
  70 typedef struct _PstImporter PstImporter;
  71 
  72 gint pst_init (pst_file *pst, gchar *filename);
  73 gchar *get_pst_rootname (pst_file *pst, gchar *filename);
  74 static void pst_error_msg (const gchar *fmt, ...);
  75 static void pst_import_folders (PstImporter *m, pst_desc_tree *topitem);
  76 static void pst_process_item (PstImporter *m, pst_desc_tree *d_ptr, gchar **previouss_folder);
  77 static void pst_process_folder (PstImporter *m, pst_item *item);
  78 static void pst_process_email (PstImporter *m, pst_item *item);
  79 static void pst_process_contact (PstImporter *m, pst_item *item);
  80 static void pst_process_appointment (PstImporter *m, pst_item *item);
  81 static void pst_process_task (PstImporter *m, pst_item *item);
  82 static void pst_process_journal (PstImporter *m, pst_item *item);
  83 
  84 static void pst_import_file (PstImporter *m);
  85 gchar *foldername_to_utf8 (const gchar *pstname);
  86 gchar *string_to_utf8 (const gchar *string);
  87 void contact_set_date (EContact *contact, EContactField id, FILETIME *date);
  88 static void fill_calcomponent (PstImporter *m, pst_item *item, ECalComponent *ec, const gchar *type);
  89 struct icaltimetype get_ical_date (FILETIME *date, gboolean is_date);
  90 gchar *rfc2445_datetime_format (FILETIME *ft);
  91 
  92 gboolean org_credativ_evolution_readpst_supported (EPlugin *epl, EImportTarget *target);
  93 GtkWidget *org_credativ_evolution_readpst_getwidget (EImport *ei, EImportTarget *target, EImportImporter *im);
  94 void org_credativ_evolution_readpst_import (EImport *ei, EImportTarget *target, EImportImporter *im);
  95 void org_credativ_evolution_readpst_cancel (EImport *ei, EImportTarget *target, EImportImporter *im);
  96 gint e_plugin_lib_enable (EPlugin *ep, gint enable);
  97 
  98 /* em-folder-selection-button.h is private, even though other internal evo plugins use it!
  99  * so declare the functions here
 100  * TODO: sort out whether this should really be private
 101 */
 102 
 103 static guchar pst_signature[] = { '!', 'B', 'D', 'N' };
 104 
 105 struct _PstImporter {
 106 	MailMsg base;
 107 
 108 	EImport *import;
 109 	EImportTarget *target;
 110 
 111 	gint waiting_open;
 112 	GMutex *status_lock;
 113 	gchar *status_what;
 114 	gint status_pc;
 115 	gint status_timeout_id;
 116 	GCancellable *cancellable;
 117 
 118 	pst_file pst;
 119 
 120 	CamelFolder *folder;
 121 	gchar *folder_name;
 122 	gchar *folder_uri;
 123 	gint folder_count;
 124 	gint current_item;
 125 
 126 	EBookClient *addressbook;
 127 	ECalClient *calendar;
 128 	ECalClient *tasks;
 129 	ECalClient *journal;
 130 
 131 	/* progress indicator */
 132 	gint position;
 133 	gint total;
 134 };
 135 
 136 gboolean
 137 org_credativ_evolution_readpst_supported (EPlugin *epl,
 138                                           EImportTarget *target)
 139 {
 140 	gchar signature[sizeof (pst_signature)];
 141 	gboolean ret = FALSE;
 142 	gint fd, n;
 143 	EImportTargetURI *s;
 144 	gchar *filename;
 145 
 146 	if (target->type != E_IMPORT_TARGET_URI) {
 147 		return FALSE;
 148 	}
 149 
 150 	s = (EImportTargetURI *) target;
 151 
 152 	if (s->uri_src == NULL) {
 153 		return TRUE;
 154 	}
 155 
 156 	if (strncmp (s->uri_src, "file:///", strlen ("file:///")) != 0) {
 157 		return FALSE;
 158 	}
 159 
 160 	filename = g_filename_from_uri (s->uri_src, NULL, NULL);
 161 	fd = g_open (filename, O_RDONLY, 0);
 162 	g_free (filename);
 163 
 164 	if (fd != -1) {
 165 		n = read (fd, signature, sizeof (pst_signature));
 166 		ret = n == sizeof (pst_signature) && memcmp (signature, pst_signature, sizeof (pst_signature)) == 0;
 167 		close (fd);
 168 	}
 169 
 170 	return ret;
 171 }
 172 
 173 static void
 174 checkbox_mail_toggle_cb (GtkToggleButton *tb,
 175                          EImportTarget *target)
 176 {
 177 	g_datalist_set_data (&target->data, "pst-do-mail", GINT_TO_POINTER (gtk_toggle_button_get_active (tb)));
 178 }
 179 
 180 static void
 181 checkbox_addr_toggle_cb (GtkToggleButton *tb,
 182                          EImportTarget *target)
 183 {
 184 	g_datalist_set_data (&target->data, "pst-do-addr", GINT_TO_POINTER (gtk_toggle_button_get_active (tb)));
 185 }
 186 
 187 static void
 188 checkbox_appt_toggle_cb (GtkToggleButton *tb,
 189                          EImportTarget *target)
 190 {
 191 	g_datalist_set_data (&target->data, "pst-do-appt", GINT_TO_POINTER (gtk_toggle_button_get_active (tb)));
 192 }
 193 
 194 static void
 195 checkbox_task_toggle_cb (GtkToggleButton *tb,
 196                          EImportTarget *target)
 197 {
 198 	g_datalist_set_data (&target->data, "pst-do-task", GINT_TO_POINTER (gtk_toggle_button_get_active (tb)));
 199 }
 200 
 201 static void
 202 checkbox_journal_toggle_cb (GtkToggleButton *tb,
 203                             EImportTarget *target)
 204 {
 205 	g_datalist_set_data (&target->data, "pst-do-journal", GINT_TO_POINTER (gtk_toggle_button_get_active (tb)));
 206 }
 207 
 208 static void
 209 folder_selected (EMFolderSelectionButton *button,
 210                  EImportTargetURI *target)
 211 {
 212 	g_free (target->uri_dest);
 213 	target->uri_dest = g_strdup (em_folder_selection_button_get_folder_uri (button));
 214 }
 215 
 216 /**
 217  * Suggest a folder to import data into
 218  */
 219 static gchar *
 220 get_suggested_foldername (EImportTargetURI *target)
 221 {
 222 	EShell *shell;
 223 	EShellBackend *shell_backend;
 224 	EMailBackend *backend;
 225 	EMailSession *session;
 226 	GtkWindow *window;
 227 	const gchar *inbox;
 228 	gchar *delim, *filename;
 229 	gchar *rootname = NULL;
 230 	GString *foldername;
 231 	pst_file pst;
 232 
 233 	/* XXX Dig up the EMailSession from the default EShell.
 234 	 *     Since the EImport framework doesn't allow for user
 235 	 *     data, I don't see how else to get to it. */
 236 	shell = e_shell_get_default ();
 237 	shell_backend = e_shell_get_backend_by_name (shell, "mail");
 238 
 239 	backend = E_MAIL_BACKEND (shell_backend);
 240 	session = e_mail_backend_get_session (backend);
 241 
 242 	foldername = NULL;
 243 
 244 	/* preselect the folder selected in a mail view */
 245 	window = e_shell_get_active_window (shell);
 246 	if (E_IS_SHELL_WINDOW (window)) {
 247 		EShellWindow *shell_window;
 248 		const gchar *view;
 249 
 250 		shell_window = E_SHELL_WINDOW (window);
 251 		view = e_shell_window_get_active_view (shell_window);
 252 
 253 		if (view && g_str_equal (view, "mail")) {
 254 			EShellView *shell_view;
 255 			EShellSidebar *shell_sidebar;
 256 			EMFolderTree *folder_tree = NULL;
 257 			gchar *selected_uri;
 258 
 259 			shell_view = e_shell_window_get_shell_view (
 260 				shell_window, view);
 261 
 262 			shell_sidebar =
 263 				e_shell_view_get_shell_sidebar (shell_view);
 264 
 265 			g_object_get (
 266 				shell_sidebar, "folder-tree",
 267 				&folder_tree, NULL);
 268 
 269 			selected_uri = em_folder_tree_get_selected_uri (folder_tree);
 270 
 271 			g_object_unref (folder_tree);
 272 
 273 			if (selected_uri && *selected_uri)
 274 				foldername = g_string_new (selected_uri);
 275 
 276 			g_free (selected_uri);
 277 		}
 278 	}
 279 
 280 	if (!foldername) {
 281 		/* Suggest a folder that is in the same mail storage as the users' inbox,
 282 		 * with a name derived from the .PST file */
 283 		inbox =
 284 			e_mail_session_get_local_folder_uri (
 285 			session, E_MAIL_LOCAL_FOLDER_INBOX);
 286 
 287 		delim = g_strrstr (inbox, "#");
 288 		if (delim != NULL) {
 289 			foldername = g_string_new_len (inbox, delim - inbox);
 290 		} else {
 291 			foldername = g_string_new (inbox);
 292 		}
 293 	}
 294 
 295 	g_string_append_c (foldername, '/');
 296 
 297 	filename = g_filename_from_uri (target->uri_src, NULL, NULL);
 298 
 299 	if (pst_init (&pst, filename) == 0) {
 300 		rootname = get_pst_rootname (&pst, filename);
 301 	}
 302 
 303 	g_free (filename);
 304 
 305 	if (rootname != NULL) {
 306 		gchar *utf8name;
 307 		utf8name = foldername_to_utf8 (rootname);
 308 		g_string_append (foldername, utf8name);
 309 		g_free (utf8name);
 310 		g_free (rootname);
 311 	} else {
 312 		g_string_append (foldername, "outlook_data");
 313 	}
 314 
 315 	/* FIXME Leaking a CamelFolder reference here. */
 316 	/* FIXME Not passing a GCancellable or GError here. */
 317 	if (e_mail_session_uri_to_folder_sync (
 318 		session, foldername->str, 0, NULL, NULL) != NULL) {
 319 		CamelFolder *folder;
 320 
 321 		/* Folder exists - add a number */
 322 		gint i, len;
 323 		len = foldername->len;
 324 
 325 		for (i = 1; i < 10000; i++) {
 326 			g_string_truncate (foldername, len);
 327 			g_string_append_printf (foldername, "_%d", i);
 328 			/* FIXME Not passing a GCancellable or GError here. */
 329 			if ((folder = e_mail_session_uri_to_folder_sync (
 330 				session, foldername->str, 0, NULL, NULL)) == NULL) {
 331 				/* Folder does not exist */
 332 				break;
 333 			}
 334 		}
 335 
 336 		if (folder != NULL) {
 337 			pst_error_msg ("Error searching for an unused folder name. uri=%s", foldername->str);
 338 		}
 339 	}
 340 
 341 	return g_string_free (foldername, FALSE);
 342 
 343 }
 344 
 345 static void
 346 widget_sanitizer_cb (GtkToggleButton *button,
 347                      GtkWidget *source_combo)
 348 {
 349 	g_return_if_fail (button != NULL);
 350 	g_return_if_fail (source_combo != NULL);
 351 
 352 	gtk_widget_set_sensitive (source_combo, gtk_toggle_button_get_active (button));
 353 }
 354 
 355 static const gchar *
 356 get_source_combo_key (EClientSourceType source_type)
 357 {
 358 	const gchar *key = NULL;
 359 
 360 	switch (source_type) {
 361 	case E_CLIENT_SOURCE_TYPE_CONTACTS:
 362 		key = "pst-contacts-source-combo";
 363 		break;
 364 	case E_CLIENT_SOURCE_TYPE_EVENTS:
 365 		key = "pst-events-source-combo";
 366 		break;
 367 	case E_CLIENT_SOURCE_TYPE_TASKS:
 368 		key = "pst-tasks-source-combo";
 369 		break;
 370 	case E_CLIENT_SOURCE_TYPE_MEMOS:
 371 		key = "pst-memos-source-combo";
 372 		break;
 373 	case E_CLIENT_SOURCE_TYPE_LAST:
 374 		break;
 375 	}
 376 
 377 	return key;
 378 }
 379 
 380 static void
 381 add_source_list_with_check (GtkWidget *frame,
 382                             const gchar *caption,
 383                             ESourceRegistry *registry,
 384                             EClientSourceType source_type,
 385                             GCallback toggle_callback,
 386                             EImportTarget *target,
 387                             gboolean active)
 388 {
 389 	ESource *source;
 390 	GtkWidget *check, *hbox;
 391 	GtkWidget *combo = NULL;
 392 	const gchar *extension_name;
 393 
 394 	g_return_if_fail (frame != NULL);
 395 	g_return_if_fail (caption != NULL);
 396 	g_return_if_fail (toggle_callback != NULL);
 397 
 398 	switch (source_type) {
 399 		case E_CLIENT_SOURCE_TYPE_CONTACTS:
 400 			extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
 401 			source = e_source_registry_ref_default_address_book (registry);
 402 			break;
 403 		case E_CLIENT_SOURCE_TYPE_EVENTS:
 404 			extension_name = E_SOURCE_EXTENSION_CALENDAR;
 405 			source = e_source_registry_ref_default_calendar (registry);
 406 			break;
 407 		case E_CLIENT_SOURCE_TYPE_TASKS:
 408 			extension_name = E_SOURCE_EXTENSION_TASK_LIST;
 409 			source = e_source_registry_ref_default_task_list (registry);
 410 			break;
 411 		case E_CLIENT_SOURCE_TYPE_MEMOS:
 412 			extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
 413 			source = e_source_registry_ref_default_memo_list (registry);
 414 			break;
 415 		default:
 416 			g_return_if_reached ();
 417 	}
 418 
 419 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
 420 
 421 	check = gtk_check_button_new_with_mnemonic (caption);
 422 	gtk_toggle_button_set_active ((GtkToggleButton *) check, active);
 423 	g_signal_connect (check, "toggled", toggle_callback, target);
 424 	gtk_box_pack_start ((GtkBox *) hbox, check, FALSE, FALSE, 0);
 425 
 426 	combo = e_source_combo_box_new (registry, extension_name);
 427 	e_source_combo_box_set_active (E_SOURCE_COMBO_BOX (combo), source);
 428 
 429 	gtk_box_pack_end ((GtkBox *) hbox, combo, FALSE, FALSE, 0);
 430 
 431 	g_signal_connect (
 432 		check, "toggled",
 433 		G_CALLBACK (widget_sanitizer_cb), combo);
 434 	widget_sanitizer_cb (GTK_TOGGLE_BUTTON (check), combo);
 435 
 436 	gtk_box_pack_start ((GtkBox *) frame, hbox, FALSE, FALSE, 0);
 437 
 438 	if (combo) {
 439 		const gchar *key = get_source_combo_key (source_type);
 440 
 441 		g_return_if_fail (key != NULL);
 442 
 443 		g_datalist_set_data (&target->data, key, combo);
 444 	}
 445 
 446 	g_object_unref (source);
 447 }
 448 
 449 static void
 450 pst_import_check_items (EImportTarget *target)
 451 {
 452 	gboolean has_mail = FALSE, has_addr = FALSE, has_appt = FALSE, has_task = FALSE, has_journal = FALSE;
 453 	gchar *filename;
 454 	pst_file pst;
 455 	pst_item *item = NULL, *subitem;
 456 	pst_desc_tree *d_ptr, *topitem;
 457 
 458 	filename = g_filename_from_uri (((EImportTargetURI *) target)->uri_src, NULL, NULL);
 459 
 460 	if (pst_init (&pst, filename) < 0) {
 461 		goto end;
 462 	}
 463 
 464 	if ((item = pst_parse_item (&pst, pst.d_head, NULL)) == NULL) {
 465 		goto end;
 466 	}
 467 
 468 	if ((topitem = pst_getTopOfFolders (&pst, item)) == NULL) {
 469 		goto end;
 470 	}
 471 
 472 	d_ptr = topitem->child;
 473 
 474 	/* Walk through folder tree */
 475 	while (d_ptr != NULL && (!has_mail || !has_addr || !has_appt || !has_task || !has_journal)) {
 476 		subitem = pst_parse_item (&pst, d_ptr, NULL);
 477 
 478 		if (subitem != NULL &&
 479 		    subitem->message_store == NULL &&
 480 		    subitem->folder == NULL) {
 481 			switch (subitem->type) {
 482 			case PST_TYPE_CONTACT:
 483 				if (subitem->contact)
 484 					has_addr = TRUE;
 485 				break;
 486 			case PST_TYPE_APPOINTMENT:
 487 				if (subitem->appointment)
 488 					has_appt = TRUE;
 489 				break;
 490 			case PST_TYPE_TASK:
 491 				if (subitem->appointment)
 492 					has_task = TRUE;
 493 				break;
 494 			case PST_TYPE_JOURNAL:
 495 				if (subitem->appointment)
 496 					has_journal = TRUE;
 497 				break;
 498 			case PST_TYPE_NOTE:
 499 			case PST_TYPE_SCHEDULE:
 500 			case PST_TYPE_REPORT:
 501 				if (subitem->email)
 502 					has_mail = TRUE;
 503 				break;
 504 			}
 505 		}
 506 
 507 		pst_freeItem (subitem);
 508 
 509 		if (d_ptr->child != NULL) {
 510 			d_ptr = d_ptr->child;
 511 		} else if (d_ptr->next != NULL) {
 512 			d_ptr = d_ptr->next;
 513 		} else {
 514 			while (d_ptr != topitem && d_ptr->next == NULL) {
 515 				d_ptr = d_ptr->parent;
 516 			}
 517 
 518 			if (d_ptr == topitem)
 519 				break;
 520 
 521 			d_ptr = d_ptr->next;
 522 		}
 523 	}
 524 
 525 	pst_freeItem (item);
 526 
 527  end:
 528 	g_free (filename);
 529 	g_datalist_set_data (&target->data, "pst-do-mail", GINT_TO_POINTER (has_mail));
 530 	g_datalist_set_data (&target->data, "pst-do-addr", GINT_TO_POINTER (has_addr));
 531 	g_datalist_set_data (&target->data, "pst-do-appt", GINT_TO_POINTER (has_appt));
 532 	g_datalist_set_data (&target->data, "pst-do-task", GINT_TO_POINTER (has_task));
 533 	g_datalist_set_data (&target->data, "pst-do-journal", GINT_TO_POINTER (has_journal));
 534 }
 535 
 536 GtkWidget *
 537 org_credativ_evolution_readpst_getwidget (EImport *ei,
 538                                           EImportTarget *target,
 539                                           EImportImporter *im)
 540 {
 541 	EShell *shell;
 542 	ESourceRegistry *registry;
 543 	EShellBackend *shell_backend;
 544 	EMailBackend *backend;
 545 	EMailSession *session;
 546 	GtkWidget *hbox, *framebox, *w, *check;
 547 	gchar *foldername;
 548 
 549 	pst_import_check_items (target);
 550 
 551 	framebox = gtk_vbox_new (FALSE, 2);
 552 
 553 	/* Mail */
 554 	hbox = gtk_hbox_new (FALSE, 0);
 555 	check = gtk_check_button_new_with_mnemonic (_("_Mail"));
 556 	gtk_toggle_button_set_active ((GtkToggleButton *) check, GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-mail")));
 557 	g_signal_connect (
 558 		check, "toggled",
 559 		G_CALLBACK (checkbox_mail_toggle_cb), target);
 560 	gtk_box_pack_start ((GtkBox *) hbox, check, FALSE, FALSE, 0);
 561 
 562 	shell = e_shell_get_default ();
 563 	registry = e_shell_get_registry (shell);
 564 	shell_backend = e_shell_get_backend_by_name (shell, "mail");
 565 
 566 	backend = E_MAIL_BACKEND (shell_backend);
 567 	session = e_mail_backend_get_session (backend);
 568 
 569 	w = em_folder_selection_button_new (
 570 		session, _("Select folder"),
 571 		_("Select folder to import into"));
 572 	foldername = get_suggested_foldername ((EImportTargetURI *) target);
 573 	((EImportTargetURI *) target)->uri_dest = g_strdup (foldername);
 574 	em_folder_selection_button_set_folder_uri ((EMFolderSelectionButton *) w, foldername);
 575 	g_signal_connect (
 576 		w, "selected",
 577 		G_CALLBACK (folder_selected), target);
 578 	gtk_box_pack_end ((GtkBox *) hbox, w, FALSE, FALSE, 0);
 579 	g_signal_connect (
 580 		check, "toggled",
 581 		G_CALLBACK (widget_sanitizer_cb), w);
 582 	widget_sanitizer_cb (GTK_TOGGLE_BUTTON (check), w);
 583 
 584 	w = gtk_label_new (_("Destination folder:"));
 585 	gtk_box_pack_end ((GtkBox *) hbox, w, FALSE, TRUE, 6);
 586 	g_signal_connect (
 587 		check, "toggled",
 588 		G_CALLBACK (widget_sanitizer_cb), w);
 589 	widget_sanitizer_cb (GTK_TOGGLE_BUTTON (check), w);
 590 
 591 	gtk_box_pack_start ((GtkBox *) framebox, hbox, FALSE, FALSE, 0);
 592 
 593 	add_source_list_with_check (
 594 		framebox, _("_Address Book"),
 595 		registry, E_CLIENT_SOURCE_TYPE_CONTACTS,
 596 		G_CALLBACK (checkbox_addr_toggle_cb), target,
 597 		GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-addr")));
 598 	add_source_list_with_check (
 599 		framebox, _("A_ppointments"),
 600 		registry, E_CLIENT_SOURCE_TYPE_EVENTS,
 601 		G_CALLBACK (checkbox_appt_toggle_cb), target,
 602 		GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-appt")));
 603 	add_source_list_with_check (
 604 		framebox, _("_Tasks"),
 605 		registry, E_CLIENT_SOURCE_TYPE_TASKS,
 606 		G_CALLBACK (checkbox_task_toggle_cb), target,
 607 		GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-task")));
 608 	add_source_list_with_check (
 609 		framebox, _("_Journal entries"),
 610 		registry, E_CLIENT_SOURCE_TYPE_MEMOS,
 611 		G_CALLBACK (checkbox_journal_toggle_cb), target,
 612 		GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-journal")));
 613 
 614 	gtk_widget_show_all (framebox);
 615 
 616 	g_free (foldername);
 617 
 618 	return framebox;
 619 }
 620 
 621 static void
 622 client_opened_cb (GObject *source_object,
 623                   GAsyncResult *result,
 624                   gpointer user_data)
 625 {
 626 	PstImporter *m = user_data;
 627 	GError *error = NULL;
 628 	EClient *client = NULL;
 629 
 630 	g_return_if_fail (result != NULL);
 631 	g_return_if_fail (m != NULL);
 632 	g_return_if_fail (m->waiting_open > 0);
 633 
 634 	if (!e_client_utils_open_new_finish (E_SOURCE (source_object), result, &client, &error))
 635 		client = NULL;
 636 
 637 	if (error)
 638 		g_debug ("%s: Failed to open client: %s", G_STRFUNC, error->message);
 639 	g_clear_error (&error);
 640 
 641 	if (client) {
 642 		if (E_IS_BOOK_CLIENT (client)) {
 643 			m->addressbook = E_BOOK_CLIENT (client);
 644 		} else if (E_IS_CAL_CLIENT (client)) {
 645 			ECalClient *cal_client = E_CAL_CLIENT (client);
 646 			switch (e_cal_client_get_source_type (cal_client)) {
 647 			case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
 648 				m->calendar = cal_client;
 649 				break;
 650 			case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
 651 				m->tasks = cal_client;
 652 				break;
 653 			case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
 654 				m->journal = cal_client;
 655 				break;
 656 			default:
 657 				g_object_unref (client);
 658 				g_warn_if_reached ();
 659 				break;
 660 			}
 661 		} else {
 662 			g_object_unref (client);
 663 			g_warn_if_reached ();
 664 		}
 665 	}
 666 
 667 	m->waiting_open--;
 668 	if (!m->waiting_open)
 669 		mail_msg_unordered_push (m);
 670 }
 671 
 672 static void
 673 open_client (PstImporter *m,
 674              EClientSourceType source_type)
 675 {
 676 	ESourceComboBox *combo;
 677 	ESource *source;
 678 
 679 	combo = g_datalist_get_data (&m->target->data, get_source_combo_key (source_type));
 680 	g_return_if_fail (combo != NULL);
 681 
 682 	source = e_source_combo_box_ref_active (combo);
 683 	g_return_if_fail (source != NULL);
 684 
 685 	m->waiting_open++;
 686 
 687 	e_client_utils_open_new (
 688 		source, source_type, FALSE, m->cancellable,
 689 		client_opened_cb, m);
 690 
 691 	g_object_unref (source);
 692 }
 693 
 694 static void
 695 pst_prepare_run (PstImporter *m)
 696 {
 697 	if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-addr"))) {
 698 		open_client (m, E_CLIENT_SOURCE_TYPE_CONTACTS);
 699 	}
 700 
 701 	if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-appt"))) {
 702 		open_client (m, E_CLIENT_SOURCE_TYPE_EVENTS);
 703 	}
 704 
 705 	if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-task"))) {
 706 		open_client (m, E_CLIENT_SOURCE_TYPE_TASKS);
 707 	}
 708 
 709 	if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-journal"))) {
 710 		open_client (m, E_CLIENT_SOURCE_TYPE_MEMOS);
 711 	}
 712 
 713 	if (!m->waiting_open)
 714 		mail_msg_unordered_push (m);
 715 }
 716 
 717 static gchar *
 718 pst_import_describe (PstImporter *m,
 719                      gint complete)
 720 {
 721 	return g_strdup (_("Importing Outlook data"));
 722 }
 723 
 724 static void
 725 pst_import_import (PstImporter *m,
 726                    GCancellable *cancellable,
 727                    GError **error)
 728 {
 729 	pst_import_file (m);
 730 }
 731 
 732 static void
 733 count_items (PstImporter *m,
 734              pst_desc_tree *topitem)
 735 {
 736 	pst_desc_tree *d_ptr;
 737 
 738 	m->position = 3;
 739 	m->total = 5;
 740 	d_ptr = topitem->child;
 741 
 742 	/* Walk through folder tree */
 743 	while (d_ptr != NULL) {
 744 		m->total++;
 745 
 746 		if (d_ptr->child != NULL) {
 747 			d_ptr = d_ptr->child;
 748 		} else if (d_ptr->next != NULL) {
 749 			d_ptr = d_ptr->next;
 750 		} else {
 751 			while (d_ptr != topitem && d_ptr->next == NULL) {
 752 				d_ptr = d_ptr->parent;
 753 			}
 754 
 755 			if (d_ptr == topitem)
 756 				break;
 757 
 758 			d_ptr = d_ptr->next;
 759 		}
 760 	}
 761 }
 762 
 763 static void
 764 pst_import_file (PstImporter *m)
 765 {
 766 	EShell *shell;
 767 	EShellBackend *shell_backend;
 768 	EMailSession *session;
 769 	gint ret;
 770 	gchar *filename;
 771 	pst_item *item = NULL;
 772 	pst_desc_tree *d_ptr;
 773 
 774 	/* XXX Dig up the EMailSession from the default EShell.
 775 	 *     Since the EImport framework doesn't allow for user
 776 	 *     data, I don't see how else to get to it. */
 777 	shell = e_shell_get_default ();
 778 	shell_backend = e_shell_get_backend_by_name (shell, "mail");
 779 	session = e_mail_backend_get_session (E_MAIL_BACKEND (shell_backend));
 780 
 781 	filename = g_filename_from_uri (((EImportTargetURI *) m->target)->uri_src, NULL, NULL);
 782 	m->folder_uri = g_strdup (((EImportTargetURI *) m->target)->uri_dest); /* Destination folder, was set in our widget */
 783 
 784 	camel_operation_push_message (m->cancellable, _("Importing '%s'"), filename);
 785 
 786 	if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-mail"))) {
 787 		e_mail_session_uri_to_folder_sync (
 788 			session, m->folder_uri, CAMEL_STORE_FOLDER_CREATE,
 789 			m->cancellable, &m->base.error);
 790 	}
 791 
 792 	ret = pst_init (&m->pst, filename);
 793 
 794 	if (ret < 0) {
 795 		g_free (filename);
 796 		camel_operation_pop_message (m->cancellable);
 797 		return;
 798 	}
 799 
 800 	g_free (filename);
 801 
 802 	camel_operation_progress (m->cancellable, 1);
 803 
 804 	if ((item = pst_parse_item (&m->pst, m->pst.d_head, NULL)) == NULL) {
 805 		pst_error_msg ("Could not get root record");
 806 		return;
 807 	}
 808 
 809 	camel_operation_progress (m->cancellable, 2);
 810 
 811 	if ((d_ptr = pst_getTopOfFolders (&m->pst, item)) == NULL) {
 812 		pst_error_msg ("Top of folders record not found. Cannot continue");
 813 		return;
 814 	}
 815 
 816 	camel_operation_progress (m->cancellable, 3);
 817 	count_items (m, d_ptr);
 818 	pst_import_folders (m, d_ptr);
 819 
 820 	camel_operation_progress (m->cancellable, 100);
 821 
 822 	camel_operation_pop_message (m->cancellable);
 823 
 824 	pst_freeItem (item);
 825 
 826 }
 827 
 828 static void
 829 pst_import_folders (PstImporter *m,
 830                     pst_desc_tree *topitem)
 831 {
 832 	GHashTable *node_to_folderuri; /* pointers of hierarchy nodes, to them associated folder uris */
 833 	pst_desc_tree *d_ptr;
 834 
 835 	node_to_folderuri = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
 836 	d_ptr = topitem->child;
 837 
 838 	if (topitem)
 839 		g_hash_table_insert (node_to_folderuri, topitem, g_strdup (m->folder_uri));
 840 
 841 	/* Walk through folder tree */
 842 	while (d_ptr != NULL && (g_cancellable_is_cancelled (m->cancellable) == FALSE)) {
 843 		gchar *previous_folder = NULL;
 844 
 845 		m->position++;
 846 		camel_operation_progress (m->cancellable, 100 * m->position / m->total);
 847 
 848 		pst_process_item (m, d_ptr, &previous_folder);
 849 
 850 		if (d_ptr->child != NULL) {
 851 			if (m->folder) {
 852 				g_object_unref (m->folder);
 853 				m->folder = NULL;
 854 			}
 855 
 856 			g_return_if_fail (m->folder_uri != NULL);
 857 			g_hash_table_insert (node_to_folderuri, d_ptr, g_strdup (m->folder_uri));
 858 
 859 			d_ptr = d_ptr->child;
 860 		} else if (d_ptr->next != NULL) {
 861 			/* for cases where there is an empty folder node, with no subnodes */
 862 			if (previous_folder) {
 863 				g_free (m->folder_uri);
 864 				m->folder_uri = previous_folder;
 865 				previous_folder = NULL;
 866 			}
 867 
 868 			d_ptr = d_ptr->next;
 869 		} else {
 870 			while (d_ptr != topitem && d_ptr->next == NULL) {
Access to field 'next' results in a dereference of a null pointer (loaded from variable 'd_ptr')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Access to field 'next' results in a dereference of a null pointer (loaded from variable 'd_ptr')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

871 if (m->folder) { 872 g_object_unref (m->folder); 873 m->folder = NULL; 874 } 875 876 g_free (m->folder_uri); 877 m->folder_uri = NULL; 878 879 d_ptr = d_ptr->parent; 880 881 if (d_ptr && d_ptr != topitem) { 882 m->folder_uri = g_strdup (g_hash_table_lookup (node_to_folderuri, d_ptr->parent)); 883 g_return_if_fail (m->folder_uri != NULL); 884 } 885 } 886 887 if (d_ptr == topitem) { 888 g_free (previous_folder); 889 break; 890 } 891 892 d_ptr = d_ptr->next; 893 } 894 895 g_free (previous_folder); 896 } 897 898 g_hash_table_destroy (node_to_folderuri); 899 } 900 901 static void 902 pst_process_item (PstImporter *m, 903 pst_desc_tree *d_ptr, 904 gchar **previous_folder) 905 { 906 pst_item *item = NULL; 907 908 if (d_ptr->desc == NULL) 909 return; 910 911 item = pst_parse_item (&m->pst, d_ptr, NULL); 912 913 if (item == NULL) 914 return; 915 916 if (item->message_store != NULL) { 917 pst_error_msg ("A second message_store has been found - ignored"); 918 pst_freeItem (item); 919 return; 920 } 921 922 if (item->folder != NULL) { 923 if (previous_folder) 924 *previous_folder = g_strdup (m->folder_uri); 925 pst_process_folder (m, item); 926 } else { 927 switch (item->type) { 928 case PST_TYPE_CONTACT: 929 if (item->contact && m->addressbook && GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-addr"))) 930 pst_process_contact (m, item); 931 break; 932 case PST_TYPE_APPOINTMENT: 933 if (item->appointment && m->calendar && GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-appt"))) 934 pst_process_appointment (m, item); 935 break; 936 case PST_TYPE_TASK: 937 if (item->appointment && m->tasks && GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-task"))) 938 pst_process_task (m, item); 939 break; 940 case PST_TYPE_JOURNAL: 941 if (item->appointment && m->journal && GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-journal"))) 942 pst_process_journal (m, item); 943 break; 944 case PST_TYPE_NOTE: 945 case PST_TYPE_SCHEDULE: 946 case PST_TYPE_REPORT: 947 if (item->email && GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-mail"))) 948 pst_process_email (m, item); 949 break; 950 } 951 952 m->current_item++; 953 } 954 955 pst_freeItem (item); 956 } 957 958 /** 959 * string_to_utf8: 960 * @string: String from PST file 961 * 962 * Convert string to utf8. Currently we just use the locale, but maybe 963 * there is encoding information hidden somewhere in the PST file? 964 * 965 * Returns: utf8 representation (caller should free), or NULL for error. 966 */ 967 gchar * 968 string_to_utf8 (const gchar *string) 969 { 970 gchar *utf8; 971 972 if (g_utf8_validate (string, -1, NULL)) 973 return g_strdup (string); 974 975 utf8 = g_locale_to_utf8 (string, -1, NULL, NULL, NULL); 976 977 return utf8; 978 } 979 980 /** 981 * foldername_to_utf8: 982 * @foldername: from PST file 983 * 984 * Convert foldername to utf8 and escape characters if needed 985 * 986 * Returns: converted folder name, or NULL for error. Caller should free 987 */ 988 gchar * 989 foldername_to_utf8 (const gchar *pstname) 990 { 991 gchar *utf8name, *folder_name; 992 993 utf8name = string_to_utf8 (pstname); 994 995 if (utf8name == NULL) { 996 folder_name = camel_url_encode (pstname, NULL); 997 g_warning ("foldername_to_utf8: Cannot convert to utf8! foldername=%s", folder_name); 998 } else { 999 /* Encode using the current locale */ 1000 folder_name = camel_url_encode (utf8name, NULL); 1001 g_free (utf8name); 1002 } 1003 1004 g_strdelimit (folder_name, "/", '_'); 1005 g_strescape (folder_name, NULL); 1006 1007 return folder_name; 1008 } 1009 1010 static void 1011 pst_process_folder (PstImporter *m, 1012 pst_item *item) 1013 { 1014 gchar *uri; 1015 g_free (m->folder_name); 1016 1017 if (item->file_as.str != NULL) { 1018 m->folder_name = foldername_to_utf8 (item->file_as.str); 1019 } else { 1020 g_critical ("Folder: No name! item->file_as=%s", item->file_as.str); 1021 m->folder_name = g_strdup ("unknown_name"); 1022 } 1023 1024 uri = g_strjoin ("/", m->folder_uri, m->folder_name, NULL); 1025 g_free (m->folder_uri); 1026 m->folder_uri = uri; 1027 1028 if (m->folder) { 1029 g_object_unref (m->folder); 1030 m->folder = NULL; 1031 } 1032 1033 m->folder_count = item->folder->item_count; 1034 m->current_item = 0; 1035 } 1036 1037 /** 1038 * pst_create_folder: 1039 * @m: PstImporter set to current folder 1040 * 1041 * Create current folder in mail hierarchy. Parent folders will also be 1042 * created. 1043 */ 1044 static void 1045 pst_create_folder (PstImporter *m) 1046 { 1047 EShell *shell; 1048 EShellBackend *shell_backend; 1049 EMailSession *session; 1050 const gchar *parent; 1051 gchar *dest, *dest_end, *pos; 1052 gint dest_len; 1053 1054 /* XXX Dig up the EMailSession from the default EShell. 1055 * Since the EImport framework doesn't allow for user 1056 * data, I don't see how else to get to it. */ 1057 shell = e_shell_get_default (); 1058 shell_backend = e_shell_get_backend_by_name (shell, "mail"); 1059 session = e_mail_backend_get_session (E_MAIL_BACKEND (shell_backend)); 1060 1061 parent = ((EImportTargetURI *) m->target)->uri_dest; 1062 dest = g_strdup (m->folder_uri); 1063 1064 g_return_if_fail (g_str_has_prefix (dest, parent)); 1065 1066 if (m->folder) { 1067 g_object_unref (m->folder); 1068 m->folder = NULL; 1069 } 1070 1071 dest_len = strlen (dest); 1072 dest_end = dest + dest_len; 1073 1074 pos = dest + strlen (parent); 1075 1076 while (pos != NULL && pos < dest_end) { 1077 pos = g_strstr_len (pos + 1, dest_end - pos, "/"); 1078 if (pos != NULL) { 1079 CamelFolder *folder; 1080 1081 *pos = '\0'; 1082 1083 folder = e_mail_session_uri_to_folder_sync ( 1084 session, dest, CAMEL_STORE_FOLDER_CREATE, 1085 m->cancellable, &m->base.error); 1086 if (folder) 1087 g_object_unref (folder); 1088 else 1089 break; 1090 *pos = '/'; 1091 } 1092 } 1093 1094 g_free (dest); 1095 1096 if (!m->base.error) 1097 m->folder = e_mail_session_uri_to_folder_sync ( 1098 session, m->folder_uri, CAMEL_STORE_FOLDER_CREATE, 1099 m->cancellable, &m->base.error); 1100 } 1101 1102 /** 1103 * attachment_to_part: 1104 * @m: a #PstImporter 1105 * @attach: attachment to convert 1106 * 1107 * Create a #CamelMimePart from given PST attachment 1108 * 1109 * Returns: #CamelMimePart containing data and mime type 1110 */ 1111 static CamelMimePart * 1112 attachment_to_part (PstImporter *m, 1113 pst_item_attach *attach) 1114 { 1115 CamelMimePart *part; 1116 const gchar *mimetype; 1117 1118 part = camel_mime_part_new (); 1119 1120 if (attach->filename2.str || attach->filename1.str) { 1121 camel_mime_part_set_filename (part, (attach->filename2.str ? attach->filename2.str : attach->filename1.str)); 1122 camel_mime_part_set_disposition (part, "attachment"); 1123 camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64); 1124 } else { 1125 camel_mime_part_set_disposition (part, "inline"); 1126 } 1127 1128 if (attach->mimetype.str != NULL) { 1129 mimetype = attach->mimetype.str; 1130 } else { 1131 mimetype = "application/octet-stream"; 1132 } 1133 1134 if (attach->data.data != NULL) { 1135 camel_mime_part_set_content (part, attach->data.data, attach->data.size, mimetype); 1136 } else { 1137 pst_binary attach_rc; 1138 attach_rc = pst_attach_to_mem (&m->pst, attach); 1139 1140 camel_mime_part_set_content (part, (gchar *) attach_rc.data, attach_rc.size, mimetype); 1141 free (attach_rc.data); 1142 } 1143 1144 return part; 1145 } 1146 1147 static void 1148 dequote_string (gchar *str) 1149 { 1150 if (str[0] == '\'' || str[0] == '\"') { 1151 gint len = strlen (str); 1152 1153 if (len > 1 && (str[len - 1] == '\'' || str[len - 1] == '\"')) { 1154 str[0] = ' '; 1155 str[len - 1] = ' '; 1156 g_strstrip (str); 1157 } 1158 } 1159 } 1160 1161 static gboolean 1162 lookup_address (pst_item *item, 1163 const gchar *str, 1164 gboolean is_unique, 1165 CamelAddress *addr) 1166 { 1167 gboolean res = FALSE; 1168 gchar *address; 1169 1170 if (!item || !str || !*str || !addr) 1171 return FALSE; 1172 1173 address = g_strdup (str); 1174 dequote_string (address); 1175 1176 if (item->contact && item->file_as.str && 1177 (is_unique || g_str_equal (item->file_as.str, str)) && 1178 item->contact->address1.str && 1179 item->contact->address1_transport.str && 1180 g_ascii_strcasecmp (item->contact->address1_transport.str, "SMTP") == 0 && 1181 !g_str_equal (address, item->contact->address1.str)) { 1182 gchar *tmp = address; 1183 1184 address = g_strconcat ("\"", address, "\" <", item->contact->address1.str, ">", NULL); 1185 1186 g_free (tmp); 1187 } 1188 1189 res = camel_address_decode (addr, address) > 0; 1190 1191 g_free (address); 1192 1193 return res; 1194 } 1195 1196 static const gchar * 1197 strip_smtp (const gchar *str) 1198 { 1199 if (str && g_ascii_strncasecmp (str, "SMTP:", 5) == 0) 1200 return str + 5; 1201 1202 return str; 1203 } 1204 1205 static void 1206 pst_process_email (PstImporter *m, 1207 pst_item *item) 1208 { 1209 CamelMimeMessage *msg; 1210 CamelInternetAddress *addr; 1211 CamelMultipart *mp; 1212 CamelMimePart *part; 1213 CamelMessageInfo *info; 1214 pst_item_attach *attach; 1215 gboolean has_attachments; 1216 gchar *comp_str = NULL; 1217 gboolean success; 1218 1219 if (m->folder == NULL) { 1220 pst_create_folder (m); 1221 if (!m->folder) 1222 return; 1223 } 1224 1225 /* stops on the first valid attachment */ 1226 for (attach = item->attach; attach; attach = attach->next) { 1227 if (attach->data.data || attach->i_id) 1228 break; 1229 } 1230 1231 has_attachments = attach != NULL; 1232 1233 if (item->type == PST_TYPE_SCHEDULE && item->appointment) { 1234 ECalComponent *comp; 1235 icalcomponent *vcal; 1236 icalproperty *prop; 1237 icalvalue *value; 1238 icalproperty_method method; 1239 1240 comp = e_cal_component_new (); 1241 e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT); 1242 fill_calcomponent (m, item, comp, "meeting-request"); 1243 1244 vcal = e_cal_util_new_top_level (); 1245 1246 method = ICAL_METHOD_PUBLISH; 1247 if (item->ascii_type) { 1248 if (g_str_has_prefix (item->ascii_type, "IPM.Schedule.Meeting.Request")) 1249 method = ICAL_METHOD_REQUEST; 1250 else if (g_str_has_prefix (item->ascii_type, "IPM.Schedule.Meeting.Canceled")) 1251 method = ICAL_METHOD_CANCEL; 1252 else if (g_str_has_prefix (item->ascii_type, "IPM.Schedule.Meeting.Resp.")) 1253 method = ICAL_METHOD_REPLY; 1254 } 1255 1256 prop = icalproperty_new (ICAL_METHOD_PROPERTY); 1257 value = icalvalue_new_method (method); 1258 icalproperty_set_value (prop, value); 1259 icalcomponent_add_property (vcal, prop); 1260 1261 icalcomponent_add_component (vcal, icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp))); 1262 1263 comp_str = icalcomponent_as_ical_string_r (vcal); 1264 1265 icalcomponent_free (vcal); 1266 g_object_unref (comp); 1267 1268 if (comp_str && !*comp_str) { 1269 g_free (comp_str); 1270 comp_str = NULL; 1271 } 1272 } 1273 1274 camel_folder_freeze (m->folder); 1275 1276 msg = camel_mime_message_new (); 1277 1278 if (item->subject.str != NULL) { 1279 gchar *subj; 1280 1281 subj = string_to_utf8 (item->subject.str); 1282 if (subj == NULL) { 1283 g_warning ("Could not convert email subject to utf8: %s", item->subject.str); 1284 camel_mime_message_set_subject (msg, "(lost subject)"); 1285 } else { 1286 camel_mime_message_set_subject (msg, subj); 1287 g_free (subj); 1288 } 1289 } 1290 1291 addr = camel_internet_address_new (); 1292 1293 if (item->email->outlook_sender_name.str != NULL && item->email->outlook_sender.str != NULL) { 1294 camel_internet_address_add (addr, item->email->outlook_sender_name.str, strip_smtp (item->email->outlook_sender.str)); 1295 } else if (item->email->outlook_sender_name.str != NULL) { 1296 camel_address_decode (CAMEL_ADDRESS (addr), strip_smtp (item->email->outlook_sender_name.str)); 1297 } else if (item->email->outlook_sender.str != NULL) { 1298 camel_address_decode (CAMEL_ADDRESS (addr), strip_smtp (item->email->outlook_sender.str)); 1299 } else { 1300 /* Evo prints a warning if no from is set, so supply an empty address */ 1301 camel_internet_address_add (addr, "", ""); 1302 } 1303 1304 camel_mime_message_set_from (msg, addr); 1305 g_object_unref (addr); 1306 1307 if (item->email->sent_date != NULL) { 1308 camel_mime_message_set_date (msg, pst_fileTimeToUnixTime (item->email->sent_date), 0); 1309 } 1310 1311 if (item->email->messageid.str != NULL) { 1312 camel_mime_message_set_message_id (msg, item->email->messageid.str); 1313 } 1314 1315 if (item->email->header.str != NULL) { 1316 /* Use mime parser to read headers */ 1317 CamelStream *stream; 1318 /*g_debug (" Email headers length=%zd", strlen (item->email->header));*/ 1319 /*g_message (" Email headers... %s...", item->email->header);*/ 1320 1321 stream = camel_stream_mem_new_with_buffer (item->email->header.str, strlen (item->email->header.str)); 1322 if (!camel_data_wrapper_construct_from_stream_sync ((CamelDataWrapper *) msg, stream, NULL, NULL)) 1323 g_warning ("Error reading headers, skipped"); 1324 1325 } else { 1326 1327 if (item->email->sentto_address.str != NULL) { 1328 addr = camel_internet_address_new (); 1329 1330 if (lookup_address (item, item->email->sentto_address.str, item->email->cc_address.str == NULL, CAMEL_ADDRESS (addr))) 1331 camel_mime_message_set_recipients (msg, "To", addr); 1332 1333 g_object_unref (addr); 1334 } 1335 1336 if (item->email->cc_address.str != NULL) { 1337 addr = camel_internet_address_new (); 1338 1339 if (lookup_address (item, item->email->cc_address.str, item->email->sentto_address.str == NULL, CAMEL_ADDRESS (addr))) 1340 camel_mime_message_set_recipients (msg, "CC", addr); 1341 1342 g_object_unref (addr); 1343 } 1344 } 1345 1346 mp = camel_multipart_new (); 1347 1348 if (has_attachments) { 1349 1350 camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (mp), "multipart/mixed"); 1351 1352 } else if (item->email->htmlbody.str && item->body.str) { 1353 1354 camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (mp), "multipart/alternate"); 1355 1356 } else if (item->email->htmlbody.str) { 1357 1358 camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (mp), "text/html"); 1359 1360 } 1361 1362 camel_multipart_set_boundary (mp, NULL); 1363 1364 if (item->body.str != NULL) { 1365 /* Read internet headers */ 1366 1367 /*g_debug (" Email body length=%zd", strlen (item->email->body)); 1368 g_message (" Email body %100s...", item->email->body);*/ 1369 1370 part = camel_mime_part_new (); 1371 camel_mime_part_set_content (part, item->body.str, strlen (item->body.str), "text/plain"); 1372 camel_multipart_add_part (mp, part); 1373 g_object_unref (part); 1374 } 1375 1376 if (item->email->htmlbody.str != NULL) { 1377 /*g_debug (" HTML body length=%zd", strlen (item->email->htmlbody));*/ 1378 part = camel_mime_part_new (); 1379 camel_mime_part_set_content (part, item->email->htmlbody.str, strlen (item->email->htmlbody.str), "text/html"); 1380 camel_multipart_add_part (mp, part); 1381 g_object_unref (part); 1382 } 1383 1384 if (comp_str) { 1385 part = camel_mime_part_new (); 1386 camel_mime_part_set_content (part, comp_str, strlen (comp_str), "text/calendar"); 1387 camel_multipart_add_part (mp, part); 1388 g_object_unref (part); 1389 } 1390 1391 for (attach = item->attach; attach; attach = attach->next) { 1392 if (attach->data.data || attach->i_id) { 1393 part = attachment_to_part (m, attach); 1394 camel_multipart_add_part (mp, part); 1395 g_object_unref (part); 1396 } 1397 } 1398 1399 /*camel_mime_message_dump (msg, TRUE);*/ 1400 1401 if (item->email->htmlbody.str || item->attach) { 1402 camel_medium_set_content (CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER (mp)); 1403 } else if (item->body.str) { 1404 camel_mime_part_set_content (CAMEL_MIME_PART (msg), item->body.str, strlen (item->body.str), "text/plain"); 1405 } else { 1406 g_warning ( 1407 "Email without body. Subject:%s", 1408 (item->subject.str ? item->subject.str : "(empty)")); 1409 camel_mime_part_set_content (CAMEL_MIME_PART (msg), "\n", 1, "text/plain"); 1410 } 1411 1412 info = camel_message_info_new (NULL); 1413 1414 /* Read message flags (see comments in libpst.c */ 1415 if (item->flags & 0x01) 1416 camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0); 1417 1418 if (item->email->importance == 2) 1419 camel_message_info_set_flags (info, CAMEL_MESSAGE_FLAGGED, ~0); 1420 1421 if (item->flags & 0x08) 1422 camel_message_info_set_flags (info, CAMEL_MESSAGE_DRAFT, ~0); 1423 1424 /* FIXME Not passing a GCancellable or GError here. */ 1425 success = camel_folder_append_message_sync ( 1426 m->folder, msg, info, NULL, NULL, NULL); 1427 camel_message_info_free (info); 1428 g_object_unref (msg); 1429 1430 /* FIXME Not passing a GCancellable or GError here. */ 1431 camel_folder_synchronize_sync (m->folder, FALSE, NULL, NULL); 1432 camel_folder_thaw (m->folder); 1433 1434 g_free (comp_str); 1435 1436 if (!success) { 1437 g_debug ("%s: Exception!", G_STRFUNC); 1438 return; 1439 } 1440 1441 } 1442 1443 static void 1444 contact_set_string (EContact *contact, 1445 EContactField id, 1446 gchar *string) 1447 { 1448 if (string != NULL) { 1449 e_contact_set (contact, id, string); 1450 } 1451 } 1452 1453 static void 1454 unknown_field (EContact *contact, 1455 GString *notes, 1456 const gchar *name, 1457 gchar *string) 1458 { 1459 /* Field could not be mapped directly so add to notes field */ 1460 if (string != NULL) { 1461 g_string_append_printf (notes, "%s: %s\n", name, string); 1462 } 1463 } 1464 1465 static void 1466 contact_set_address (EContact *contact, 1467 EContactField id, 1468 gchar *address, 1469 gchar *city, 1470 gchar *country, 1471 gchar *po_box, 1472 gchar *postal_code, 1473 gchar *state, 1474 gchar *street) 1475 { 1476 EContactAddress *eaddress; 1477 1478 if (address || city || country || po_box || postal_code || state || street) { 1479 eaddress = g_new0 (EContactAddress, 1); 1480 if (po_box) { 1481 eaddress->po = g_strdup (po_box); 1482 } 1483 /* eaddress->ext = */ 1484 1485 if (street) { 1486 eaddress->street = g_strdup (street); 1487 } 1488 1489 if (city) { 1490 eaddress->locality = g_strdup (city); 1491 } 1492 1493 if (state) { 1494 eaddress->region = g_strdup (state); 1495 } 1496 1497 if (postal_code) { 1498 eaddress->code = g_strdup (postal_code); 1499 } 1500 1501 if (country) { 1502 eaddress->country = g_strdup (country); 1503 } 1504 1505 e_contact_set (contact, id, eaddress); 1506 } 1507 } 1508 1509 void 1510 contact_set_date (EContact *contact, 1511 EContactField id, 1512 FILETIME *date) 1513 { 1514 if (date && (date->dwLowDateTime || date->dwHighDateTime)) { 1515 time_t t1; 1516 struct tm tm; 1517 EContactDate *bday; 1518 bday = e_contact_date_new (); 1519 1520 t1 = pst_fileTimeToUnixTime (date); 1521 gmtime_r (&t1, &tm); 1522 1523 bday->year = tm.tm_year + 1900; 1524 bday->month = tm.tm_mon + 1; 1525 bday->day = tm.tm_mday; 1526 1527 e_contact_set (contact, id, bday); 1528 } 1529 } 1530 1531 static void 1532 pst_process_contact (PstImporter *m, 1533 pst_item *item) 1534 { 1535 pst_item_contact *c; 1536 EContact *ec; 1537 GString *notes; 1538 gchar *uid = NULL; 1539 GError *error = NULL; 1540 1541 c = item->contact; 1542 notes = g_string_sized_new (2048); 1543 1544 ec = e_contact_new (); 1545 /* pst's fullname field only contains first, middle, surname */ 1546 if (c->display_name_prefix.str || c->suffix.str) { 1547 GString *name = g_string_sized_new (128); 1548 1549 if (c->display_name_prefix.str) { 1550 g_string_assign (name, c->display_name_prefix.str); 1551 } 1552 1553 if (c->first_name.str) { 1554 g_string_append_printf (name, "%s%s", (name->len ? " " : ""), c->first_name.str); 1555 } 1556 1557 if (c->middle_name.str) { 1558 g_string_append_printf (name, "%s%s", (name->len ? " " : ""), c->middle_name.str); 1559 } 1560 1561 if (c->surname.str) { 1562 g_string_append_printf (name, "%s%s", (name->len ? " " : ""), c->surname.str); 1563 } 1564 1565 if (c->surname.str) { 1566 g_string_append_printf (name, "%s%s", (name->len ? " " : ""), c->surname.str); 1567 } 1568 1569 contact_set_string (ec, E_CONTACT_FULL_NAME, name->str); 1570 g_string_free (name, TRUE); 1571 1572 } else { 1573 contact_set_string (ec, E_CONTACT_FULL_NAME, c->fullname.str); 1574 } 1575 1576 /* unknown_field (ec, notes, "initials", c->initials); */ 1577 1578 contact_set_string (ec, E_CONTACT_NICKNAME, c->nickname.str); 1579 1580 contact_set_string (ec, E_CONTACT_ORG, c->company_name.str); 1581 contact_set_string (ec, E_CONTACT_ORG_UNIT, c->department.str); 1582 contact_set_string (ec, E_CONTACT_TITLE, c->job_title.str); 1583 1584 contact_set_address ( 1585 ec,E_CONTACT_ADDRESS_WORK, 1586 c->business_address.str, c->business_city.str, c->business_country.str, 1587 c->business_po_box.str, c->business_postal_code.str, c->business_state.str, c->business_street.str); 1588 1589 contact_set_address ( 1590 ec,E_CONTACT_ADDRESS_HOME, 1591 c->home_address.str, c->home_city.str, c->home_country.str, 1592 c->home_po_box.str, c->home_postal_code.str, c->home_state.str, c->home_street.str); 1593 1594 contact_set_address ( 1595 ec,E_CONTACT_ADDRESS_OTHER, 1596 c->other_address.str, c->other_city.str, c->other_country.str, 1597 c->other_po_box.str, c->other_postal_code.str, c->other_state.str, c->other_street.str); 1598 1599 contact_set_string (ec, E_CONTACT_PHONE_ASSISTANT, c->assistant_phone.str); 1600 contact_set_string (ec, E_CONTACT_PHONE_BUSINESS_FAX, c->business_fax.str); 1601 contact_set_string (ec, E_CONTACT_PHONE_BUSINESS, c->business_phone.str); 1602 contact_set_string (ec, E_CONTACT_PHONE_BUSINESS_2, c->business_phone2.str); 1603 contact_set_string (ec, E_CONTACT_PHONE_CALLBACK, c->callback_phone.str); 1604 contact_set_string (ec, E_CONTACT_PHONE_CAR, c->car_phone.str); 1605 contact_set_string (ec, E_CONTACT_PHONE_COMPANY, c->company_main_phone.str); 1606 contact_set_string (ec, E_CONTACT_PHONE_HOME_FAX, c->home_fax.str); 1607 contact_set_string (ec, E_CONTACT_PHONE_HOME, c->home_phone.str); 1608 contact_set_string (ec, E_CONTACT_PHONE_HOME_2, c->home_phone2.str); 1609 contact_set_string (ec, E_CONTACT_PHONE_ISDN, c->isdn_phone.str); 1610 contact_set_string (ec, E_CONTACT_PHONE_MOBILE, c->mobile_phone.str); 1611 contact_set_string (ec, E_CONTACT_PHONE_OTHER_FAX, c->primary_fax.str); /* ? */ 1612 contact_set_string (ec, E_CONTACT_PHONE_PAGER, c->pager_phone.str); 1613 contact_set_string (ec, E_CONTACT_PHONE_PRIMARY, c->primary_phone.str); 1614 contact_set_string (ec, E_CONTACT_PHONE_RADIO, c->radio_phone.str); 1615 contact_set_string (ec, E_CONTACT_PHONE_TTYTDD, c->ttytdd_phone.str); 1616 contact_set_string (ec, E_CONTACT_PHONE_TELEX, c->telex.str); 1617 unknown_field (ec, notes, "account_name", c->account_name.str); 1618 contact_set_date (ec, E_CONTACT_ANNIVERSARY, c->wedding_anniversary); 1619 contact_set_string (ec, E_CONTACT_ASSISTANT, c->assistant_name.str); 1620 unknown_field (ec, notes, "billing_information", c->billing_information.str); 1621 contact_set_date (ec, E_CONTACT_BIRTH_DATE, c->birthday); 1622 /* contact_set_string (ec, E_CONTACT_CATEGORIES, c->??); */ 1623 1624 contact_set_string (ec, E_CONTACT_EMAIL_1 , c->address1.str); 1625 contact_set_string (ec, E_CONTACT_EMAIL_2 , c->address2.str); 1626 contact_set_string (ec, E_CONTACT_EMAIL_3 , c->address3.str); 1627 1628 /*unknown_field (ec, notes, "address1_desc" , c->address1_desc); 1629 unknown_field (ec, notes, "address1_transport" , c->address1_transport); 1630 unknown_field (ec, notes, "address2_desc" , c->address2_desc); 1631 unknown_field (ec, notes, "address2_transport" , c->address2_transport); 1632 unknown_field (ec, notes, "address3_desc" , c->address3_desc); 1633 unknown_field (ec, notes, "address3_transport" , c->address3_transport);*/ 1634 1635 /*unknown_field (ec, notes, "def_postal_address", c->def_postal_address);*/ 1636 1637 /* unknown_field (ec, ??, c->gender); */ 1638 unknown_field (ec, notes, "gov_id", c->gov_id.str); 1639 unknown_field (ec, notes, "customer_id", c->customer_id.str); 1640 unknown_field (ec, notes, "hobbies", c->hobbies.str); 1641 unknown_field (ec, notes, "followup", c->followup.str); 1642 1643 contact_set_string (ec, E_CONTACT_FREEBUSY_URL , c->free_busy_address.str); 1644 1645 unknown_field (ec, notes, "keyword", c->keyword.str); 1646 unknown_field (ec, notes, "language", c->language.str); 1647 unknown_field (ec, notes, "location", c->location.str); 1648 contact_set_string (ec, E_CONTACT_OFFICE, c->office_loc.str); 1649 unknown_field (ec, notes, "computer_name", c->computer_name.str); 1650 unknown_field (ec, notes, "ftp_site", c->ftp_site.str); 1651 1652 contact_set_string (ec, E_CONTACT_MANAGER , c->manager_name.str); 1653 unknown_field (ec, notes, "mileage", c->mileage.str); 1654 unknown_field (ec, notes, "org_id", c->org_id.str); 1655 contact_set_string (ec, E_CONTACT_ROLE, c->profession.str); 1656 1657 contact_set_string (ec, E_CONTACT_SPOUSE , c->spouse_name.str); 1658 1659 if (c->personal_homepage.str) { 1660 contact_set_string (ec, E_CONTACT_HOMEPAGE_URL , c->personal_homepage.str); 1661 if (c->business_homepage.str) { 1662 unknown_field (ec, notes, "business_homepage", c->business_homepage.str); 1663 } 1664 } else if (c->business_homepage.str) { 1665 contact_set_string (ec, E_CONTACT_HOMEPAGE_URL , c->business_homepage.str); 1666 } 1667 1668 if (item->comment.str) { 1669 g_string_append_printf (notes, "%s\n", item->comment.str); 1670 } 1671 1672 if (item->email && item->body.str) { 1673 g_string_append_printf (notes, "%s\n", item->body.str); 1674 } 1675 1676 contact_set_string (ec, E_CONTACT_NOTE, notes->str); 1677 g_string_free (notes, TRUE); 1678 1679 if (!e_book_client_add_contact_sync (m->addressbook, ec, &uid, NULL, &error)) 1680 uid = NULL; 1681 1682 g_object_unref (ec); 1683 g_free (uid); 1684 1685 if (error != NULL) { 1686 g_warning ( 1687 "%s: Failed to add contact: %s", 1688 G_STRFUNC, error->message); 1689 g_error_free (error); 1690 } 1691 } 1692 1693 /** 1694 * get_ical_date: 1695 * @date: time value from libpst 1696 * @is_date: treat as date only (all day event)? 1697 * 1698 * Convert pst time to icaltimetype 1699 * 1700 * Returns: converted date 1701 */ 1702 struct icaltimetype 1703 get_ical_date (FILETIME *date, 1704 gboolean is_date) 1705 { 1706 if (date && (date->dwLowDateTime || date->dwHighDateTime)) { 1707 time_t t; 1708 1709 t = pst_fileTimeToUnixTime (date); 1710 return icaltime_from_timet_with_zone (t, is_date, NULL); 1711 } else { 1712 return icaltime_null_date (); 1713 } 1714 } 1715 1716 static void 1717 set_cal_attachments (ECalClient *cal, 1718 ECalComponent *ec, 1719 PstImporter *m, 1720 pst_item_attach *attach) 1721 { 1722 GSList *list = NULL; 1723 const gchar *uid; 1724 gchar *store_dir; 1725 1726 if (attach == NULL) { 1727 return; 1728 } 1729 1730 e_cal_component_get_uid (ec, &uid); 1731 store_dir = g_filename_from_uri (e_cal_client_get_local_attachment_store (cal), NULL, NULL); 1732 1733 while (attach != NULL) { 1734 const gchar * orig_filename; 1735 gchar *filename, *tmp, *path, *dirname, *uri; 1736 CamelMimePart *part; 1737 CamelDataWrapper *content; 1738 CamelStream *stream; 1739 struct stat st; 1740 1741 part = attachment_to_part (m, attach); 1742 1743 orig_filename = camel_mime_part_get_filename (part); 1744 1745 if (orig_filename == NULL) { 1746 g_warning ("Ignoring unnamed attachment"); 1747 attach = attach->next; 1748 continue; /* Ignore unnamed attachments */ 1749 } 1750 1751 tmp = camel_file_util_safe_filename (orig_filename); 1752 filename = g_strdup_printf ("%s-%s", uid, tmp); 1753 path = g_build_filename (store_dir, filename, NULL); 1754 1755 g_free (tmp); 1756 g_free (filename); 1757 1758 dirname = g_path_get_dirname (path); 1759 if (g_mkdir_with_parents (dirname, 0777) == -1) { 1760 g_warning ("Could not create directory %s: %s", dirname, g_strerror (errno)); 1761 g_free (dirname); 1762 attach = attach->next; 1763 continue; 1764 } 1765 g_free (dirname); 1766 1767 if (g_access (path, F_OK) == 0) { 1768 if (g_access (path, W_OK) != 0) { 1769 g_warning ("Could not write file %s - file exists", path); 1770 attach = attach->next; 1771 continue; 1772 } 1773 } 1774 1775 if (g_stat (path, &st) != -1 && !S_ISREG (st.st_mode)) { 1776 g_warning ("Could not write file %s - not a file", path); 1777 attach = attach->next; 1778 continue; 1779 } 1780 1781 if (!(stream = camel_stream_fs_new_with_name (path, O_WRONLY | O_CREAT | O_TRUNC, 0666, NULL))) { 1782 g_warning ("Could not create stream for file %s - %s", path, g_strerror (errno)); 1783 attach = attach->next; 1784 continue; 1785 } 1786 1787 content = camel_medium_get_content (CAMEL_MEDIUM (part)); 1788 1789 if (camel_data_wrapper_decode_to_stream_sync (content, stream, NULL, NULL) == -1 1790 || camel_stream_flush (stream, NULL, NULL) == -1) 1791 { 1792 g_warning ("Could not write attachment to %s: %s", path, g_strerror (errno)); 1793 g_object_unref (stream); 1794 attach = attach->next; 1795 continue; 1796 } 1797 1798 g_object_unref (stream); 1799 1800 uri = g_filename_to_uri (path, NULL, NULL); 1801 list = g_slist_append (list, g_strdup (uri)); 1802 g_free (uri); 1803 1804 g_object_unref (part); 1805 g_free (path); 1806 1807 attach = attach->next; 1808 1809 } 1810 1811 g_free (store_dir); 1812 1813 e_cal_component_set_attachment_list (ec, list); 1814 } 1815 1816 static void 1817 fill_calcomponent (PstImporter *m, 1818 pst_item *item, 1819 ECalComponent *ec, 1820 const gchar *type) 1821 { 1822 pst_item_appointment *a; 1823 pst_item_email *e; 1824 1825 ECalComponentText text; 1826 struct icaltimetype tt_start, tt_end; 1827 ECalComponentDateTime dt_start, dt_end; 1828 1829 a = item->appointment; 1830 e = item->email; 1831 1832 g_return_if_fail (item->appointment != NULL); 1833 1834 if (item->create_date) { 1835 struct icaltimetype tt; 1836 tt = get_ical_date (item->create_date, FALSE); 1837 e_cal_component_set_created (ec, &tt); 1838 } 1839 if (item->modify_date) { 1840 struct icaltimetype tt; 1841 tt = get_ical_date (item->modify_date, FALSE); 1842 e_cal_component_set_last_modified (ec, &tt); 1843 } 1844 1845 if (e) { 1846 if (item->subject.str || e->processed_subject.str) { 1847 if (item->subject.str) { 1848 text.value = item->subject.str; 1849 } else if (e->processed_subject.str) { 1850 text.value = e->processed_subject.str; 1851 } 1852 1853 text.altrep = NULL; /* email->proc_subject? */ 1854 e_cal_component_set_summary (ec, &text); 1855 } 1856 if (item->body.str) { 1857 GSList l; 1858 text.value = item->body.str; 1859 text.altrep = NULL; 1860 l.data = &text; 1861 l.next = NULL; 1862 e_cal_component_set_description_list (ec, &l); 1863 } 1864 } else { 1865 g_warning ("%s without subject / body!", type); 1866 } 1867 1868 if (a->location.str) { 1869 e_cal_component_set_location (ec, a->location.str); 1870 } 1871 1872 if (a->start) { 1873 tt_start = get_ical_date (a->start, a->all_day); 1874 dt_start.value = &tt_start; 1875 dt_start.tzid = a->timezonestring.str; 1876 e_cal_component_set_dtstart (ec, &dt_start); 1877 } 1878 1879 if (a->end) { 1880 tt_end = get_ical_date (a->end, a->all_day); 1881 dt_end.value = &tt_end; 1882 dt_end.tzid = a->timezonestring.str; 1883 e_cal_component_set_dtend (ec, &dt_end); 1884 } 1885 1886 switch (a->showas) { 1887 case PST_FREEBUSY_TENTATIVE: 1888 e_cal_component_set_status (ec, ICAL_STATUS_TENTATIVE); 1889 break; 1890 case PST_FREEBUSY_FREE: 1891 /* mark as transparent and as confirmed */ 1892 e_cal_component_set_transparency (ec, E_CAL_COMPONENT_TRANSP_TRANSPARENT); 1893 case PST_FREEBUSY_BUSY: 1894 case PST_FREEBUSY_OUT_OF_OFFICE: 1895 e_cal_component_set_status (ec, ICAL_STATUS_CONFIRMED); 1896 break; 1897 } 1898 switch (a->label) { 1899 case PST_APP_LABEL_NONE: 1900 break; 1901 case PST_APP_LABEL_IMPORTANT: 1902 e_cal_component_set_categories (ec, "Important"); break; 1903 case PST_APP_LABEL_BUSINESS: 1904 e_cal_component_set_categories (ec, "Business"); break; 1905 case PST_APP_LABEL_PERSONAL: 1906 e_cal_component_set_categories (ec, "Personal"); break; 1907 case PST_APP_LABEL_VACATION: 1908 e_cal_component_set_categories (ec, "Vacation"); break; 1909 case PST_APP_LABEL_MUST_ATTEND: 1910 e_cal_component_set_categories (ec, "Must-attend"); break; 1911 case PST_APP_LABEL_TRAVEL_REQ: 1912 e_cal_component_set_categories (ec, "Travel-required"); break; 1913 case PST_APP_LABEL_NEEDS_PREP: 1914 e_cal_component_set_categories (ec, "Needs-preparation"); break; 1915 case PST_APP_LABEL_BIRTHDAY: 1916 e_cal_component_set_categories (ec, "Birthday"); break; 1917 case PST_APP_LABEL_ANNIVERSARY: 1918 e_cal_component_set_categories (ec, "Anniversary"); break; 1919 case PST_APP_LABEL_PHONE_CALL: 1920 e_cal_component_set_categories (ec, "Phone-call"); break; 1921 } 1922 1923 if (a->alarm || a->alarm_minutes) { 1924 ECalComponentAlarm *alarm; 1925 ECalComponentAlarmTrigger trigger; 1926 1927 alarm = e_cal_component_alarm_new (); 1928 1929 if (a->alarm_minutes) { 1930 trigger.type = E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START; 1931 trigger.u.rel_duration = icaldurationtype_from_int (- (a->alarm_minutes) * 60); 1932 e_cal_component_alarm_set_trigger (alarm, trigger); 1933 } 1934 1935 if (a->alarm) { 1936 if (a->alarm_filename.str) { 1937 e_cal_component_alarm_set_action (alarm, E_CAL_COMPONENT_ALARM_AUDIO); 1938 } else { 1939 e_cal_component_alarm_set_action (alarm, E_CAL_COMPONENT_ALARM_DISPLAY); 1940 } 1941 } 1942 1943 e_cal_component_add_alarm (ec, alarm); 1944 e_cal_component_alarm_free (alarm); 1945 1946 } 1947 1948 if (a->recurrence_description.str != PST_APP_RECUR_NONE) { 1949 struct icalrecurrencetype r; 1950 GSList recur_list; 1951 1952 icalrecurrencetype_clear (&r); 1953 r.interval = 1; /* Interval not implemented in libpst */ 1954 if (a->recurrence_end) { 1955 r.until = get_ical_date (a->recurrence_end, FALSE); 1956 } 1957 1958 switch (a->recurrence_type) { 1959 case PST_APP_RECUR_DAILY: 1960 r.freq = ICAL_DAILY_RECURRENCE; break; 1961 case PST_APP_RECUR_WEEKLY: 1962 r.freq = ICAL_WEEKLY_RECURRENCE; break; 1963 case PST_APP_RECUR_MONTHLY: 1964 r.freq = ICAL_MONTHLY_RECURRENCE; break; 1965 case PST_APP_RECUR_YEARLY: 1966 r.freq = ICAL_YEARLY_RECURRENCE; break; 1967 default: 1968 r.freq = ICAL_NO_RECURRENCE; 1969 } 1970 1971 recur_list.data = &r; 1972 recur_list.next = NULL; 1973 e_cal_component_set_rrule_list (ec, &recur_list); 1974 } 1975 1976 if (item->type == PST_TYPE_SCHEDULE && item->email && item->ascii_type) { 1977 const gchar *organizer, *organizer_addr, *attendee, *attendee_addr; 1978 1979 if (g_str_has_prefix (item->ascii_type, "IPM.Schedule.Meeting.Resp.")) { 1980 organizer = item->email->outlook_recipient_name.str; 1981 organizer_addr = item->email->outlook_recipient.str; 1982 attendee = item->email->outlook_sender_name.str; 1983 attendee_addr = item->email->outlook_sender.str; 1984 } else { 1985 organizer = item->email->outlook_sender_name.str; 1986 organizer_addr = item->email->outlook_sender.str; 1987 attendee = item->email->outlook_recipient_name.str; 1988 attendee_addr = item->email->outlook_recipient.str; 1989 } 1990 1991 if (organizer || organizer_addr) { 1992 ECalComponentOrganizer org = { 0 }; 1993 1994 org.value = organizer_addr; 1995 org.cn = organizer; 1996 1997 e_cal_component_set_organizer (ec, &org); 1998 } 1999 2000 if (attendee || attendee_addr) { 2001 ECalComponentAttendee att = { 0 }; 2002 GSList *attendees; 2003 2004 att.value = attendee_addr; 2005 att.cn = attendee; 2006 att.cutype = ICAL_CUTYPE_INDIVIDUAL; 2007 att.status = ICAL_PARTSTAT_NEEDSACTION; 2008 att.role = ICAL_ROLE_REQPARTICIPANT; 2009 att.rsvp = TRUE; 2010 2011 attendees = g_slist_append (NULL, &att); 2012 e_cal_component_set_attendee_list (ec, attendees); 2013 g_slist_free (attendees); 2014 } 2015 } 2016 2017 e_cal_component_commit_sequence (ec); 2018 } 2019 2020 static void 2021 pst_process_component (PstImporter *m, 2022 pst_item *item, 2023 const gchar *comp_type, 2024 ECalComponentVType vtype, 2025 ECalClient *cal) 2026 { 2027 ECalComponent *ec; 2028 gchar *uid = NULL; 2029 GError *error = NULL; 2030 2031 g_return_if_fail (item->appointment != NULL); 2032 2033 ec = e_cal_component_new (); 2034 e_cal_component_set_new_vtype (ec, vtype); 2035 2036 fill_calcomponent (m, item, ec, comp_type); 2037 set_cal_attachments (cal, ec, m, item->attach); 2038 2039 if (!e_cal_client_create_object_sync (cal, e_cal_component_get_icalcomponent (ec), &uid, NULL, &error)) { 2040 uid = NULL; 2041 g_warning ("Creation of %s failed: %s", comp_type, error ? error->message : "Unknown error"); 2042 } 2043 2044 g_object_unref (ec); 2045 g_free (uid); 2046 if (error) 2047 g_error_free (error); 2048 } 2049 2050 static void 2051 pst_process_appointment (PstImporter *m, 2052 pst_item *item) 2053 { 2054 pst_process_component (m, item, "appointment", E_CAL_COMPONENT_EVENT, m->calendar); 2055 } 2056 2057 static void 2058 pst_process_task (PstImporter *m, 2059 pst_item *item) 2060 { 2061 pst_process_component (m, item, "task", E_CAL_COMPONENT_TODO, m->tasks); 2062 } 2063 2064 static void 2065 pst_process_journal (PstImporter *m, 2066 pst_item *item) 2067 { 2068 pst_process_component (m, item, "journal", E_CAL_COMPONENT_JOURNAL, m->journal); 2069 } 2070 2071 /* Print an error message - maybe later bring up an error dialog? */ 2072 static void 2073 pst_error_msg (const gchar *fmt, 2074 ...) 2075 { 2076 va_list ap; 2077 2078 va_start (ap, fmt); 2079 g_critical (fmt, ap); 2080 va_end (ap); 2081 } 2082 2083 static void 2084 pst_import_imported (PstImporter *m) 2085 { 2086 e_import_complete (m->target->import, (EImportTarget *) m->target); 2087 } 2088 2089 static void 2090 pst_import_free (PstImporter *m) 2091 { 2092 /* pst_close (&m->pst); */ 2093 if (m->addressbook) 2094 g_object_unref (m->addressbook); 2095 if (m->calendar) 2096 g_object_unref (m->calendar); 2097 if (m->tasks) 2098 g_object_unref (m->tasks); 2099 if (m->journal) 2100 g_object_unref (m->journal); 2101 2102 g_object_unref (m->cancellable); 2103 2104 g_free (m->status_what); 2105 g_mutex_free (m->status_lock); 2106 2107 g_source_remove (m->status_timeout_id); 2108 m->status_timeout_id = 0; 2109 2110 g_free (m->folder_name); 2111 g_free (m->folder_uri); 2112 2113 g_object_unref (m->import); 2114 } 2115 2116 static MailMsgInfo pst_import_info = { 2117 sizeof (PstImporter), 2118 (MailMsgDescFunc) pst_import_describe, 2119 (MailMsgExecFunc) pst_import_import, 2120 (MailMsgDoneFunc) pst_import_imported, 2121 (MailMsgFreeFunc) pst_import_free, 2122 }; 2123 2124 static gboolean 2125 pst_status_timeout (gpointer data) 2126 { 2127 PstImporter *importer = data; 2128 gint pc; 2129 gchar *what; 2130 2131 if (importer->status_what) { 2132 g_mutex_lock (importer->status_lock); 2133 what = importer->status_what; 2134 importer->status_what = NULL; 2135 pc = importer->status_pc; 2136 g_mutex_unlock (importer->status_lock); 2137 2138 e_import_status (importer->target->import, (EImportTarget *) importer->target, what, pc); 2139 } 2140 2141 return TRUE; 2142 } 2143 2144 static void 2145 pst_status (CamelOperation *op, 2146 const gchar *what, 2147 gint pc, 2148 gpointer data) 2149 { 2150 PstImporter *importer = data; 2151 2152 g_mutex_lock (importer->status_lock); 2153 g_free (importer->status_what); 2154 importer->status_what = g_strdup (what); 2155 importer->status_pc = pc; 2156 g_mutex_unlock (importer->status_lock); 2157 } 2158 2159 static void 2160 pst_import (EImport *ei, 2161 EImportTarget *target) 2162 { 2163 PstImporter *m; 2164 2165 m = mail_msg_new (&pst_import_info); 2166 g_datalist_set_data (&target->data, "pst-msg", m); 2167 m->import = ei; 2168 g_object_ref (m->import); 2169 m->target = target; 2170 2171 m->folder_name = NULL; 2172 m->folder_uri = NULL; 2173 2174 m->addressbook = NULL; 2175 m->calendar = NULL; 2176 m->tasks = NULL; 2177 m->journal = NULL; 2178 m->waiting_open = 0; 2179 2180 m->status_timeout_id = g_timeout_add (100, pst_status_timeout, m); 2181 /*m->status_timeout_id = NULL;*/ 2182 m->status_lock = g_mutex_new (); 2183 m->cancellable = camel_operation_new (); 2184 2185 g_signal_connect ( 2186 m->cancellable, "status", 2187 G_CALLBACK (pst_status), m); 2188 2189 pst_prepare_run (m); 2190 } 2191 2192 /* Start the main import operation */ 2193 void 2194 org_credativ_evolution_readpst_import (EImport *ei, 2195 EImportTarget *target, 2196 EImportImporter *im) 2197 { 2198 if (GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-mail")) 2199 || GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-addr")) 2200 || GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-appt")) 2201 || GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-task")) 2202 || GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-journal"))) { 2203 pst_import (ei, target); 2204 } else { 2205 e_import_complete (target->import, target); 2206 } 2207 } 2208 2209 void 2210 org_credativ_evolution_readpst_cancel (EImport *ei, 2211 EImportTarget *target, 2212 EImportImporter *im) 2213 { 2214 PstImporter *m = g_datalist_get_data (&target->data, "pst-msg"); 2215 2216 if (m) { 2217 g_cancellable_cancel (m->cancellable); 2218 } 2219 } 2220 2221 gint 2222 e_plugin_lib_enable (EPlugin *ep, 2223 gint enable) 2224 { 2225 return 0; 2226 } 2227 2228 /** 2229 * pst_init: 2230 * @pst: pst_file structure to be used by libpst 2231 * @filename: path to file 2232 * 2233 * Open PST file and determine root folder name 2234 * 2235 * Returns: 0 for sucess, -1 for failure 2236 */ 2237 gint 2238 pst_init (pst_file *pst, 2239 gchar *filename) 2240 { 2241 2242 #if 0 2243 gchar *d_log = "readpst.log"; 2244 /* initialize log file */ 2245 DEBUG_INIT (d_log); 2246 DEBUG_REGISTER_CLOSE (); 2247 #endif 2248 2249 if (pst_open (pst, filename, NULL) < 0) { 2250 pst_error_msg ("Error opening PST file %s", filename); 2251 return -1; 2252 } 2253 2254 if (pst_load_index (pst) < 0) { 2255 pst_error_msg ("Error loading indexes"); 2256 return -1; 2257 } 2258 2259 if (pst_load_extended_attributes (pst) < 0) { 2260 pst_error_msg ("Error loading file items"); 2261 return -1; 2262 } 2263 2264 return 0; 2265 } 2266 2267 /** 2268 * get_pst_rootname: 2269 * @pst: pst_file structure to be used by libpst 2270 * @filename: if non %NULL, fallback to this name if folder name is not 2271 * available 2272 * 2273 * Open determine root folder name of PST file 2274 * 2275 * Returns: pointer to name of root folder (should be freed by caller), 2276 * or %NULL if error 2277 */ 2278 gchar * 2279 get_pst_rootname (pst_file *pst, 2280 gchar *filename) 2281 { 2282 pst_item *item = NULL; 2283 gchar *rootname = NULL; 2284 2285 if ((item = pst_parse_item (pst, pst->d_head, NULL)) == NULL) { 2286 pst_error_msg ("Could not get root record"); 2287 return NULL; 2288 } 2289 2290 if (item->message_store == NULL) { 2291 pst_error_msg ("Could not get root message store"); 2292 pst_freeItem (item); 2293 return NULL; 2294 } 2295 2296 /* default the file_as to the same as the main filename if it doesn't exist */ 2297 if (item->file_as.str == NULL) { 2298 if (filename == NULL) { 2299 pst_freeItem (item); 2300 return NULL; 2301 } 2302 rootname = g_path_get_basename (filename); 2303 } else { 2304 rootname = g_strdup (item->file_as.str); 2305 } 2306 2307 pst_freeItem (item); 2308 2309 return rootname; 2310 }