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) {
(emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
(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 }