diff --git a/evolution-2.23.92+r36353.tar.bz2 b/evolution-2.23.92+r36353.tar.bz2 new file mode 100644 index 0000000..b5b24ea --- /dev/null +++ b/evolution-2.23.92+r36353.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c8929d20bb91b090c036883deae7f05db9442397a02ffbd97956626dd8dffd0b +size 31402985 diff --git a/evolution-2.23.92.tar.bz2 b/evolution-2.23.92.tar.bz2 deleted file mode 100644 index 0494752..0000000 --- a/evolution-2.23.92.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:033922a68e00a715f613c43a29818c974f38ffaaf618b46d69c25e215ebd176e -size 31298241 diff --git a/evolution.changes b/evolution.changes index 1d49f62..1f04745 100644 --- a/evolution.changes +++ b/evolution.changes @@ -1,3 +1,13 @@ +------------------------------------------------------------------- +Thu Sep 25 16:01:12 CEST 2008 - abharath@suse.de + +- Added Pst-Import plugin support. + +------------------------------------------------------------------- +Tue Sep 16 18:18:12 CDT 2008 - maw@suse.de + +- Updated the source tarball to svn r36353. + ------------------------------------------------------------------- Mon Sep 8 14:45:12 CDT 2008 - maw@suse.de diff --git a/evolution.spec b/evolution.spec index e8e743f..be456e5 100644 --- a/evolution.spec +++ b/evolution.spec @@ -1,5 +1,5 @@ # -# spec file for package evolution (Version 2.23.92) +# spec file for package evolution (Version 2.23.92+r36353) # # Copyright (c) 2008 SUSE LINUX Products GmbH, Nuernberg, Germany. # @@ -45,15 +45,16 @@ BuildRequires: scrollkeeper BuildRequires: shared-mime-info BuildRequires: update-desktop-files BuildRequires: sqlite3-devel +BuildRequires: libpst-devel License: GPL v2 or later Group: Productivity/Networking/Email/Clients Obsoletes: evoltn Provides: evoltn AutoReqProv: on -# This should be updated upon major version changes, and used in place of -# BASE_VERSION (as defined in configure.in). +#This should be updated upon major version changes; it should match +# BASE_VERSION as defined in configure.in. %define evolution_base_version 2.24 -Version: 2.23.92 +Version: 2.23.92+r36353 Release: 1 Summary: The Integrated GNOME Mail, Calendar, and Address Book Suite Source0: %{name}-%{version}.tar.bz2 @@ -81,6 +82,7 @@ Patch9: fix-sendrecv.diff Patch10: build-fixes.diff # PATCH-FIX-UPSTREAM SVN po update Patch12: evolution-po-update.patch +Patch13: pst-import.patch Url: http://gnome.org/projects/evolution/ BuildRoot: %{_tmppath}/%{name}-%{version}-build Requires: yelp @@ -300,7 +302,7 @@ Authors: %lang_package %prep -%setup -q +%setup -q -n %{name}-2.23.92 # %patch1 -p0 %if %suse_version > 1000 # FIXME: somebody with time should fix this patch up and make it apply once more @@ -314,6 +316,7 @@ Authors: %patch9 #%patch10 #%patch12 +%patch13 %build autoreconf -f -i @@ -425,11 +428,15 @@ fi %{_libdir}/evolution/*/conduits/*.so %changelog +* Thu Sep 25 2008 abharath@suse.de +- Added Pst-Import plugin support. +* Wed Sep 17 2008 maw@suse.de +- Updated the source tarball to svn r36353. * Mon Sep 08 2008 maw@suse.de - Update to version 2.23.92: + Bug fixed: bgo#549968 + Updated translations. -* Tue Sep 02 2008 maw@suse.de +* Wed Sep 03 2008 maw@suse.de - Update to version 2.23.91: + Bugs fixed: bgo#458512, bgo#509647, bgo#523327, bgo#525555, bgo#534762, bgo#544430, bgo#546926, bgo#547822, bgo#547822, @@ -477,7 +484,7 @@ fi bgo#544994, bgo#545300, bgo#545303, bgo#545436, bgo#545558, bgo#545568, bgo#545820, and bgo#546057 + Updated translations. -* Fri Jun 20 2008 maw@suse.de +* Sat Jun 21 2008 maw@suse.de - Update to version 2.23.4: + Quota support to IMAP/POP accounts + Configurable Proxy settings for Evolution @@ -536,7 +543,7 @@ fi bug-394641_evo-CVE-2008-1109.diff - bnc#395708 - bgo-395708_prefer-plain.patch - Outlook meeting invites look as text messages - bnc#394441 - bnc-394441-exchange-addbook-crash.diff - Addressbook crash -* Tue May 20 2008 msuman@suse.de +* Wed May 21 2008 msuman@suse.de - Added + bgo-534012-backup-permission.patch (Sankar P) + bgo-533820-fix-crash-on-border-clicking-meetings.diff (Chenthill P) (bnc#391993) @@ -594,7 +601,7 @@ fi * Wed Apr 09 2008 msuman@suse.de - Configurable proxy settings for Evolution (Varadhan) + Added patch: bnc-188523-evo-fix-authenticated-proxy-support.diff (bnc#188523) -* Thu Mar 13 2008 maw@suse.de +* Fri Mar 14 2008 maw@suse.de - Update to version 2.22.0: + Bigs fixed: bnc#282466, bgo#351672m and bgo#520745 + Updated translations. @@ -710,7 +717,7 @@ fi bnc-308959-mail-attachment-icon.patch, evolution-stringcompare.patch, and bnc-302017-print-100pc.diff. -* Tue Dec 04 2007 maw@suse.de +* Wed Dec 05 2007 maw@suse.de - Build with openldap2-devel, not openldap2. * Tue Nov 13 2007 psankar@suse.de - bnc-308959-mail-attachment-icon.patch: Fixes mail attachment icon @@ -773,7 +780,7 @@ fi * Tue Aug 21 2007 sbrabec@suse.cz - Fixed crash on appointments with no no SENTBY parameter (#301835, patch from Suman Manjunath). -* Fri Aug 17 2007 jberkman@novell.com +* Sat Aug 18 2007 jberkman@novell.com - fix infinite recursion when used with smartcard auth patches * Mon Aug 06 2007 maw@suse.de - Split off a -lang subpackage. @@ -1061,7 +1068,7 @@ fi * Thu Mar 22 2007 maw@suse.de - Update to version 2.10.0 - Update the required intltool version. -* Mon Mar 12 2007 maw@suse.de +* Tue Mar 13 2007 maw@suse.de - Update to version 2.9.91 - Remove upstreamed bnc-214647-add-prefer-plain-plugin.patch - fix-security-gtkhtml-moreui.diff is now much smaller @@ -1073,7 +1080,7 @@ fi standard libraries, not modules. * Tue Jan 09 2007 sbrabec@suse.cz - More spec file cleanups. -* Wed Dec 13 2006 maw@suse.de +* Thu Dec 14 2006 maw@suse.de - Move to /usr - Some specfile cleanup. * Tue Nov 21 2006 vvaradhan@novell.com @@ -1106,7 +1113,7 @@ fi * Sat Oct 28 2006 kharish@suse.de - Add bnc-214647-add-prefer-plain-plugin.patch to include prefer-plain plugin in the build by default. -* Mon Oct 02 2006 jhargadon@suse.de +* Tue Oct 03 2006 jhargadon@suse.de - update to version 2.8.1 - translation updates - many bug fixes @@ -1201,14 +1208,14 @@ fi 168697 - Fixes a alarm crash (Srini) 171592 - Fixes a alarm crash (Srini) 170076 - Fixes a wrong mime lookup for a attachment (Srini) -* Tue May 02 2006 fejj@suse.de +* Wed May 03 2006 fejj@suse.de - Added bnc-167638.patch: Fixes the long Evolution quit times when the user tries to close Evolution when it is in the middle of syncing stuff to an IMAP/GW server. * Tue May 02 2006 pchenthill@novell.com - Update the patch bnc-158107-no-notification-canceled-mtgs.patch Fixes https://bugzilla.novell.com/show_bug.cgi?id=171531 -* Wed Apr 26 2006 dobey@suse.de +* Thu Apr 27 2006 dobey@suse.de - Update trach icon patch to deal with more instances Fixes https://bugzilla.novell.com/show_bug.cgi?id=160837 * Mon Apr 24 2006 sragavan@novell.com @@ -1227,7 +1234,7 @@ fi 325960 - Fix to show subscribed and public folders without restarting evolution (Sushma) - fix-exchange-menuitem.diff: Changed a menu item name in exchange plugin. (Srini) - fix-sendrecv.diff: Change 'Send Receive' button to 'Get Mail' (Srini) -* Wed Apr 19 2006 fejj@suse.de +* Thu Apr 20 2006 fejj@suse.de - Added bnc-159736-dbus-restart.patch to the build which replaces survive-dbus-restarts.patch (it solves the same problem plus more instances of the same) @@ -1263,7 +1270,7 @@ fi - Fixes (bnc) 160049 changed G/W password - no calendar prompt ... 158107 No notification of cancelled meetings -* Thu Mar 23 2006 vvaradhan@novell.com +* Fri Mar 24 2006 vvaradhan@novell.com - Fixes (bnc) 150427 evo 1.6 hang on calendar 153807 msg composer seems to lower instead of raise @@ -1455,18 +1462,18 @@ fi - Remove upstreamed patches and regenerated new ones - Remove NM-devel dependency from configure.in and make the code work with dbus interface itself. -* Fri Feb 17 2006 sreeves@suse.de +* Sat Feb 18 2006 sreeves@suse.de - Update .desktop file (Name, GenericName, Comment, DocPath) * Tue Feb 14 2006 aj@suse.de - Reduce BuildRequires. - Do not build with NetworkManager. -* Sun Feb 12 2006 ro@suse.de +* Mon Feb 13 2006 ro@suse.de - silence enough compiler warnings to make it build -* Sun Feb 12 2006 ro@suse.de +* Mon Feb 13 2006 ro@suse.de - fix compile flags "--fPIC" to "-fPIC" * Fri Feb 10 2006 vvaradhan@novell.com - Update to 2.5.90 -* Thu Jan 26 2006 mls@suse.de +* Fri Jan 27 2006 mls@suse.de - converted neededforbuild to BuildRequires * Wed Jan 25 2006 meissner@suse.de - fixed use of stack-protector in regards to older products/PLUS. @@ -1546,29 +1553,29 @@ fi - Fixed Send as iCalendar (#72795). * Tue Mar 15 2005 sbrabec@suse.cz - Fixed Czech translation. -* Thu Mar 10 2005 gekker@suse.de +* Fri Mar 11 2005 gekker@suse.de - Add Email to %%suse_update_desktop_file (65804). -* Tue Mar 08 2005 gekker@suse.de +* Wed Mar 09 2005 gekker@suse.de - Update to version 2.2.0 (GNOME 2.10). * Wed Mar 02 2005 gekker@suse.de - Update to version 2.1.6 -* Wed Feb 09 2005 gekker@suse.de +* Thu Feb 10 2005 gekker@suse.de - Update to version 2.1.5 * Sat Feb 05 2005 gekker@suse.de -Update to version 2.1.4 -* Thu Jan 20 2005 ro@suse.de +* Fri Jan 21 2005 ro@suse.de - fixed file list * Sat Jan 15 2005 clahey@suse.de - Updated to version 2.1.3. -* Mon Jan 10 2005 ro@suse.de +* Tue Jan 11 2005 ro@suse.de - added directories to filelist * Fri Jan 07 2005 gekker@suse.de - Update to version 2.1.2 * Tue Dec 07 2004 gekker@suse.de - update to version 2.0.3 (Ximian 70057) -* Mon Nov 29 2004 ro@suse.de +* Tue Nov 30 2004 ro@suse.de - adapted evolution-2.0.1-de-po.patch -* Mon Nov 29 2004 gekker@suse.de +* Tue Nov 30 2004 gekker@suse.de - Update version to 2.0.2 - Remove patches that are upstream - Change the no-groupwise-docs patch to actually apply @@ -1579,9 +1586,9 @@ fi * Thu Oct 07 2004 dobey@suse.de - Update default Inbox patch to not mention Groupwise support http://bugzilla.ximian.com/show_bugs.cgi?id=67643 -* Mon Oct 04 2004 dobey@suse.de +* Tue Oct 05 2004 dobey@suse.de - Add patch to fix bug 67513 in bugzilla.ximian.com -* Wed Sep 29 2004 dobey@suse.de +* Thu Sep 30 2004 dobey@suse.de - Add patch various bug fixes since 2.0.1 - Add patch to disable groupwise docs * Tue Sep 28 2004 dobey@suse.de @@ -1589,7 +1596,7 @@ fi * Mon Sep 27 2004 ke@suse.de - Fix German translation: keep the "DN" string for Distinguished Name [#44959]. -* Fri Sep 24 2004 dobey@suse.de +* Sat Sep 25 2004 dobey@suse.de - Update to version 2.0.1 - Add shared-mime-info to Prereq * Wed Sep 15 2004 dobey@suse.de @@ -1607,16 +1614,16 @@ fi - Cache evolution help files and show evolution in khelpcenter. * Wed Aug 18 2004 dobey@suse.de - Comment out %%debug_package -* Tue Aug 17 2004 dobey@suse.de +* Wed Aug 18 2004 dobey@suse.de - Add MozillaFirefox libdir to rpath -* Fri Aug 13 2004 dobey@suse.de +* Sat Aug 14 2004 dobey@suse.de - Update to version 1.5.93 - Split pilot conduits out into evolution-pilot package - Update dependencies for new versions - Remove 64-bit patches that are now in CVS - Remove patch for com_err.h checks as it is in CVS now - Add patch for default Inbox and Welcome message -* Mon Aug 09 2004 adrian@suse.de +* Tue Aug 10 2004 adrian@suse.de - move evolution menu entry out of the More menu. * Mon Aug 09 2004 dobey@suse.de - Update dependencies to pull in new versions @@ -1630,29 +1637,29 @@ fi - Updated to version 1.5.92.1 - Add patch for more 64bit cleanliness issues - Add dependencies for spamassassin and other evo packages -* Wed Jul 28 2004 dobey@suse.de +* Thu Jul 29 2004 dobey@suse.de - Updated to version 1.5.91 -* Thu Jul 15 2004 clahey@suse.de +* Fri Jul 16 2004 clahey@suse.de - Updated about box. -* Tue Jul 13 2004 clahey@suse.de +* Wed Jul 14 2004 clahey@suse.de - Updated to version 1.5.90. * Mon Jun 21 2004 clahey@suse.de - Updated to version 1.5.9.2. Added spamassassin. -* Fri Jun 11 2004 clahey@suse.de +* Sat Jun 12 2004 clahey@suse.de - Added rpath stuff for mozilla. * Thu Jun 10 2004 clahey@suse.de - Fixed a non-void warning. * Wed Jun 09 2004 clahey@suse.de - Updated to version 1.5.9.1. Added SSL. Fixed warnings. -* Thu Jun 03 2004 mibarra@suse.de +* Fri Jun 04 2004 mibarra@suse.de - Uodated to version 1.5.9 * Thu May 27 2004 mibarra@suse.de - Enabled default binary at configure time, this means evolution binary will be named 'evolution' instead of 'evolution-1.5'. -* Tue May 25 2004 mibarra@suse.de +* Wed May 26 2004 mibarra@suse.de - Fixed some 64bits compiler warnings. -* Fri May 21 2004 mibarra@suse.de +* Sat May 22 2004 mibarra@suse.de - Updated to 1.5.8. - Added gnome-icon-theme to # neededforbuild * Tue May 18 2004 clahey@suse.de @@ -1677,7 +1684,7 @@ fi - Fixed gconf schemas installation (#33114). * Mon Mar 08 2004 hhetter@suse.de - updated to version 1.4.6 -* Thu Feb 19 2004 ro@suse.de +* Fri Feb 20 2004 ro@suse.de - use -lpthread with libdb3 where needed * Fri Jan 09 2004 adrian@suse.de - remove unneeded %%run_ldconfig @@ -1690,7 +1697,7 @@ fi - Fix use of build root. * Mon Sep 22 2003 sbrabec@suse.cz - Obsolete bonobo-conf. -* Sun Sep 14 2003 adrian@suse.de +* Mon Sep 15 2003 adrian@suse.de - Add Email Category * Tue Sep 09 2003 sbrabec@suse.cz - Fixed default charset bug (bug #29851, Ximian bug #47638). @@ -1705,9 +1712,9 @@ fi - updated to version 1.4.4 (GTK2/GNOME2 ported) * Mon Jul 14 2003 sbrabec@suse.cz - GNOME prefix change to /opt/gnome. -* Sun Jun 29 2003 ro@suse.de +* Mon Jun 30 2003 ro@suse.de - added directories to filelist -* Wed Jun 04 2003 ro@suse.de +* Thu Jun 05 2003 ro@suse.de - remove unpackaged files from buildroot * Mon Mar 24 2003 hhetter@suse.de - updated to security bugfix release 1.2.3 @@ -1735,11 +1742,11 @@ fi * Thu Aug 22 2002 hhetter@suse.de - build with rpath /opt/mozilla/%%_lib to correctly link wombat (Bug Id#18195) -* Fri Jul 26 2002 adrian@suse.de +* Sat Jul 27 2002 adrian@suse.de - fix neededforbuild * Tue Jul 16 2002 hhetter@suse.de - updated to bugfix release 1.0.8 -* Tue Jun 25 2002 ro@suse.de +* Wed Jun 26 2002 ro@suse.de - build libibex.a with -fPIC, it's linked into a shared library * Mon Jun 17 2002 jordi@suse.de - Updated to version 1.0.7 @@ -1748,7 +1755,7 @@ fi * Thu Jun 06 2002 hhetter@suse.de - more %%_lib fixes - use new mozilla's libdir -* Wed Jun 05 2002 ro@suse.de +* Thu Jun 06 2002 ro@suse.de - use libdir * Tue May 28 2002 hhetter@suse.de - use new mozilla-nss include paths @@ -1760,7 +1767,7 @@ fi - update to version 1.0.5 - build and link with db 3.1.17, required by evolution contacts -* Tue Apr 23 2002 ro@suse.de +* Wed Apr 24 2002 ro@suse.de - fix build with latest autoconf (AM_CONDITIONAL must appear in mainline) * Tue Mar 26 2002 hhetter@suse.de @@ -1769,7 +1776,7 @@ fi * Mon Feb 18 2002 hhetter@suse.de - updated to stable bugfix version 1.0.2 - build with automake 1.5 and current db -* Thu Jan 31 2002 ro@suse.de +* Fri Feb 01 2002 ro@suse.de - changed neededforbuild to * Wed Jan 30 2002 hhetter@suse.de - build with db 4.0.14 @@ -1781,7 +1788,7 @@ fi - libtoolize /libical too - build with db3 again - build with automake 1.5 -* Wed Nov 21 2001 ro@suse.de +* Thu Nov 22 2001 ro@suse.de - xml-i18n-toolize * Wed Nov 21 2001 ro@suse.de - changed neededforbuild to @@ -1824,7 +1831,7 @@ fi * Fri Mar 16 2001 egger@suse.de - Insert extra make to prevent propagation of BuildRoot dirs into the executable. -* Thu Mar 15 2001 egger@suse.de +* Fri Mar 16 2001 egger@suse.de - Updated to version 0.9. * Wed Mar 14 2001 ro@suse.de - added xf86 to neededforbuild @@ -1835,26 +1842,26 @@ fi - First version that works with SuSE, yay! * Thu Nov 09 2000 ro@suse.de - fixed neededforbuild again -* Wed Nov 08 2000 ro@suse.de +* Thu Nov 09 2000 ro@suse.de - typo fixed * Wed Nov 08 2000 ro@suse.de - fixed neededforbuild -* Tue Oct 31 2000 egger@suse.de +* Wed Nov 01 2000 egger@suse.de - Updated specfile to new long packagenames. - Reworked specfile. - Probably needs some more work; I'm taking care of that. -* Sun Oct 01 2000 egger@suse.de +* Mon Oct 02 2000 egger@suse.de - Fixed it a little more.... * Mon Sep 25 2000 egger@suse.de - Removed a thinko.... -* Sun Sep 24 2000 egger@suse.de +* Mon Sep 25 2000 egger@suse.de - Restructuring of the package. - Use the splitted packages oafdev and bonobod. - Buildproofed on i386. -* Thu Sep 21 2000 egger@suse.de +* Fri Sep 22 2000 egger@suse.de - Use BuildRoot. - Buildproofed on i386. -* Tue Sep 19 2000 egger@suse.de +* Wed Sep 20 2000 egger@suse.de - First compilable version of it using version 0.5.1 - Buildproofed on i386. * Fri Sep 01 2000 egger@suse.de diff --git a/pst-import.patch b/pst-import.patch new file mode 100644 index 0000000..b56cf36 --- /dev/null +++ b/pst-import.patch @@ -0,0 +1,1934 @@ +Index: plugins/pst-import/pst-importer.c +=================================================================== +--- plugins/pst-import/pst-importer.c (revision 0) ++++ plugins/pst-import/pst-importer.c (revision 0) +@@ -0,0 +1,1813 @@ ++/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ ++/* pst-importer.c ++ * ++ * Copyright (C) 2006 Chris Halls ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of version 2 of the GNU General Public ++ * License as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public ++ * License along with this program; if not, write to the ++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: Chris Halls ++ Bharath Acharya ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#define G_LOG_DOMAIN "eplugin-readpst" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++typedef struct _PstImporter PstImporter; ++ ++int pst_init (pst_file *pst, char *filename); ++gchar *get_pst_rootname (pst_file *pst, gchar *filename); ++static void pst_error_msg (const char *fmt, ...); ++static void pst_import_folders (PstImporter *m, pst_desc_ll *topitem); ++static void pst_process_item (PstImporter *m, pst_desc_ll *d_ptr); ++static void pst_process_folder (PstImporter *m, pst_item *item); ++static void pst_process_email (PstImporter *m, pst_item *item); ++static void pst_process_contact (PstImporter *m, pst_item *item); ++static void pst_process_appointment (PstImporter *m, pst_item *item); ++static void pst_process_task (PstImporter *m, pst_item *item); ++static void pst_process_journal (PstImporter *m, pst_item *item); ++ ++static void pst_import_file (PstImporter *m); ++gchar *foldername_to_utf8 (const gchar *pstname); ++gchar *string_to_utf8(const gchar *string); ++void contact_set_date (EContact *contact, EContactField id, FILETIME *date); ++struct icaltimetype get_ical_date (FILETIME *date, gboolean is_date); ++char *rfc2445_datetime_format (FILETIME *ft); ++ ++gboolean org_credativ_evolution_readpst_supported (EPlugin *epl, EImportTarget *target); ++GtkWidget *org_credativ_evolution_readpst_getwidget (EImport *ei, EImportTarget *target, EImportImporter *im); ++void org_credativ_evolution_readpst_import (EImport *ei, EImportTarget *target, EImportImporter *im); ++void org_credativ_evolution_readpst_cancel (EImport *ei, EImportTarget *target, EImportImporter *im); ++int e_plugin_lib_enable (EPluginLib *ep, int enable); ++ ++ ++/* em-folder-selection-button.h is private, even though other internal evo plugins use it! ++ so declare the functions here ++ TODO: sort out whether this should really be private ++*/ ++typedef struct _EMFolderSelectionButton EMFolderSelectionButton; ++GtkWidget *em_folder_selection_button_new (const char *title, const char *caption); ++void em_folder_selection_button_set_selection (EMFolderSelectionButton *button, const char *uri); ++const char *em_folder_selection_button_get_selection (EMFolderSelectionButton *button); ++ ++static unsigned char pst_signature [] = { '!', 'B', 'D', 'N' }; ++ ++struct _PstImporter { ++ MailMsg base; ++ ++ EImport *import; ++ EImportTarget *target; ++ ++ GMutex *status_lock; ++ char *status_what; ++ int status_pc; ++ int status_timeout_id; ++ CamelOperation *status; ++ CamelException ex; ++ ++ pst_file pst; ++ ++ CamelOperation *cancel; ++ CamelFolder *folder; ++ gchar *parent_uri; ++ gchar *folder_name; ++ gchar *folder_uri; ++ int folder_count; ++ int current_item; ++ ++ EBook *addressbook; ++ ECal *calendar; ++ ECal *tasks; ++ ECal *journal; ++}; ++ ++gboolean ++org_credativ_evolution_readpst_supported (EPlugin *epl, EImportTarget *target) ++{ ++ char signature[sizeof (pst_signature)]; ++ gboolean ret = FALSE; ++ int fd, n; ++ EImportTargetURI *s; ++ char *filename; ++ ++ if (target->type != E_IMPORT_TARGET_URI) { ++ return FALSE; ++ } ++ ++ s = (EImportTargetURI *)target; ++ ++ if (s->uri_src == NULL) { ++ return TRUE; ++ } ++ ++ if (strncmp (s->uri_src, "file:///", strlen ("file:///")) != 0) { ++ return FALSE; ++ } ++ ++ filename = g_filename_from_uri (s->uri_src, NULL, NULL); ++ fd = g_open (filename, O_RDONLY, 0); ++ g_free (filename); ++ ++ if (fd != -1) { ++ n = read (fd, signature, sizeof (pst_signature)); ++ ret = n == sizeof (pst_signature) && memcmp (signature, pst_signature, sizeof (pst_signature)) == 0; ++ close (fd); ++ } ++ ++ return ret; ++} ++ ++static void ++checkbox_mail_toggle_cb (GtkToggleButton *tb, EImportTarget *target) ++{ ++ g_datalist_set_data (&target->data, "pst-do-mail", GINT_TO_POINTER (gtk_toggle_button_get_active (tb))); ++} ++ ++static void ++checkbox_addr_toggle_cb (GtkToggleButton *tb, EImportTarget *target) ++{ ++ g_datalist_set_data (&target->data, "pst-do-addr", GINT_TO_POINTER (gtk_toggle_button_get_active (tb))); ++} ++ ++static void ++checkbox_appt_toggle_cb (GtkToggleButton *tb, EImportTarget *target) ++{ ++ g_datalist_set_data (&target->data, "pst-do-appt", GINT_TO_POINTER (gtk_toggle_button_get_active (tb))); ++} ++ ++static void ++checkbox_task_toggle_cb (GtkToggleButton *tb, EImportTarget *target) ++{ ++ g_datalist_set_data (&target->data, "pst-do-task", GINT_TO_POINTER (gtk_toggle_button_get_active (tb))); ++} ++ ++static void ++checkbox_journal_toggle_cb (GtkToggleButton *tb, EImportTarget *target) ++{ ++ g_datalist_set_data (&target->data, "pst-do-journal", GINT_TO_POINTER (gtk_toggle_button_get_active (tb))); ++} ++ ++static void ++folder_selected (EMFolderSelectionButton *button, EImportTargetURI *target) ++{ ++ g_free (target->uri_dest); ++ target->uri_dest = g_strdup (em_folder_selection_button_get_selection (button)); ++} ++ ++ ++/** ++ * Suggest a folder to import data into ++ * @param target ++ * @return ++ */ ++static gchar* ++get_suggested_foldername (EImportTargetURI *target) ++{ ++ const gchar *inbox; ++ gchar *delim, *filename; ++ gchar *rootname = NULL; ++ GString *foldername; ++ pst_file pst; ++ ++ /* Suggest a folder that is in the same mail storage as the users' inbox, ++ with a name derived from the .PST file */ ++ inbox = mail_component_get_folder_uri (NULL, MAIL_COMPONENT_FOLDER_INBOX); ++ g_message ("Inbox:%s", inbox); ++ ++ delim = g_strrstr (inbox, "#"); ++ if (delim != NULL) { ++ foldername = g_string_new_len (inbox, delim-inbox); ++ } else { ++ foldername = g_string_new (inbox); ++ } ++ ++ g_string_append_c (foldername, '#'); ++ ++ filename = g_filename_from_uri (target->uri_src, NULL, NULL); ++ ++ if (pst_init (&pst, filename) == 0) { ++ rootname = get_pst_rootname (&pst, filename); ++ } ++ ++ g_free (filename); ++ ++ if (rootname != NULL) { ++ gchar *utf8name; ++ utf8name = foldername_to_utf8 (rootname); ++ g_string_append (foldername, utf8name); ++ g_free (utf8name); ++ g_free (rootname); ++ } else { ++ g_string_append (foldername, "outlook_data"); ++ } ++ ++ if (mail_tool_uri_to_folder (foldername->str, 0, NULL) != NULL) { ++ /* Folder exists - add a number */ ++ int i, len; ++ len = foldername->len; ++ CamelFolder *folder; ++ ++ for (i=1; i<10000; i++) { ++ g_string_truncate (foldername, len); ++ g_string_append_printf (foldername, "_%d", i); ++ if ((folder=mail_tool_uri_to_folder (foldername->str, 0, NULL)) == NULL) { ++ /* Folder does not exist */ ++ break; ++ } ++ } ++ ++ if (folder != NULL) { ++ pst_error_msg ("Error searching for an unused folder name. uri=%s", foldername); ++ } ++ } ++ ++ return g_string_free (foldername, FALSE); ++ ++} ++ ++GtkWidget * ++org_credativ_evolution_readpst_getwidget (EImport *ei, EImportTarget *target, EImportImporter *im) ++{ ++ GtkWidget *hbox, *framebox, *w; ++ gchar *foldername; ++ ++ g_datalist_set_data (&target->data, "pst-do-mail", GINT_TO_POINTER (TRUE)); ++ g_datalist_set_data (&target->data, "pst-do-addr", GINT_TO_POINTER (TRUE)); ++ g_datalist_set_data (&target->data, "pst-do-appt", GINT_TO_POINTER (TRUE)); ++ g_datalist_set_data (&target->data, "pst-do-task", GINT_TO_POINTER (TRUE)); ++ g_datalist_set_data (&target->data, "pst-do-journal", GINT_TO_POINTER (TRUE)); ++ ++ framebox = gtk_vbox_new (FALSE, 2); ++ ++ /* Mail */ ++ hbox = gtk_hbox_new (FALSE, 0); ++ w = gtk_check_button_new_with_mnemonic (_("_Mail")); ++ gtk_toggle_button_set_active ((GtkToggleButton *) w, TRUE); ++ g_signal_connect (w, "toggled", G_CALLBACK (checkbox_mail_toggle_cb), target); ++ gtk_box_pack_start ((GtkBox *) hbox, w, FALSE, FALSE, 0); ++ ++ w = em_folder_selection_button_new (_("Select folder"), _("Select folder to import into")); ++ foldername = get_suggested_foldername ((EImportTargetURI *) target); ++ ((EImportTargetURI *) target)->uri_dest = g_strdup (foldername); ++ em_folder_selection_button_set_selection ((EMFolderSelectionButton *) w, foldername); ++ g_signal_connect (w, "selected", G_CALLBACK (folder_selected), target); ++ gtk_box_pack_end ((GtkBox *) hbox, w, FALSE, FALSE, 0); ++ ++ w = gtk_label_new (_("Destination folder:")); ++ gtk_box_pack_end ((GtkBox *) hbox, w, FALSE, TRUE, 6); ++ ++ gtk_box_pack_start ((GtkBox *) framebox, hbox, FALSE, FALSE, 0); ++ ++ /* Address book */ ++ w = gtk_check_button_new_with_mnemonic (_("_Address Book")); ++ gtk_toggle_button_set_active ((GtkToggleButton *) w, FALSE); ++ /*gtk_widget_set_sensitive ((GtkWidget *)w, FALSE);*/ /* Disable until implemented */ ++ g_signal_connect (w, "toggled", G_CALLBACK (checkbox_addr_toggle_cb), target); ++ gtk_box_pack_start ((GtkBox *) framebox, w, FALSE, FALSE, 0); ++ ++ /* Appointments */ ++ w = gtk_check_button_new_with_mnemonic (_("A_ppointments")); ++ gtk_toggle_button_set_active ((GtkToggleButton *) w, FALSE); ++ g_signal_connect (w, "toggled", G_CALLBACK (checkbox_appt_toggle_cb), target); ++ gtk_box_pack_start ((GtkBox *)framebox, w, FALSE, FALSE, 0); ++ ++ /* Tasks */ ++ w = gtk_check_button_new_with_mnemonic (_("_Tasks")); ++ gtk_toggle_button_set_active ((GtkToggleButton *)w, FALSE); ++ g_signal_connect (w, "toggled", G_CALLBACK (checkbox_task_toggle_cb), target); ++ gtk_box_pack_start ((GtkBox *)framebox, w, FALSE, FALSE, 0); ++ ++ /* Journal */ ++ w = gtk_check_button_new_with_mnemonic (_("_Journal entries")); ++ gtk_toggle_button_set_active ((GtkToggleButton *)w, FALSE); ++ g_signal_connect (w, "toggled", G_CALLBACK (checkbox_journal_toggle_cb), target); ++ gtk_box_pack_start ((GtkBox *)framebox, w, FALSE, FALSE, 0); ++ ++ gtk_widget_show_all (framebox); ++ ++ g_free (foldername); ++ ++ return framebox; ++} ++ ++static char * ++pst_import_describe (PstImporter *m, int complete) ++{ ++ return g_strdup (_("Importing Outlook data")); ++} ++ ++static ECal* ++open_ecal (ECalSourceType type, char *name) ++{ ++ /* Hack - grab the first calendar we can find ++ TODO - add a selection mechanism in get_widget */ ++ ESource *primary; ++ ESourceList *source_list; ++ ECal *cal; ++ ++ if ((e_cal_get_sources (&source_list, type, NULL)) == 0) { ++ g_warning ("Could not get any sources of type %s.", name); ++ return NULL; ++ } ++ ++ primary = e_source_list_peek_source_any (source_list); ++ ++ if ((cal = e_cal_new (primary, type)) == NULL) { ++ g_warning ("Could not create %s.", name); ++ g_object_unref (source_list); ++ return NULL; ++ } ++ ++ e_cal_open (cal, TRUE, NULL); ++ g_object_unref (primary); ++ g_object_unref (source_list); ++ ++ return cal; ++} ++ ++static void ++pst_import_import (PstImporter *m) ++{ ++ CamelOperation *oldcancel = NULL; ++ ++ oldcancel = camel_operation_register (m->status); ++ ++ if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-addr"))) { ++ /* Hack - grab the first address book we can find ++ TODO - add a selection mechanism in get_widget */ ++ ESource *primary; ++ ESourceList *source_list; ++ ++ if (e_book_get_addressbooks (&source_list, NULL)) { ++ primary = e_source_list_peek_source_any (source_list); ++ ++ if ((m->addressbook = e_book_new (primary,NULL))) { ++ e_book_open (m->addressbook, TRUE, NULL); ++ g_object_unref (primary); ++ g_object_unref (source_list); ++ } else { ++ g_warning ("Could not create EBook."); ++ } ++ } else { ++ g_warning ("Could not get address books."); ++ } ++ } ++ ++ if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-appt"))) { ++ m->calendar = open_ecal (E_CAL_SOURCE_TYPE_EVENT, "calendar"); ++ } ++ ++ if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-task"))) { ++ m->tasks = open_ecal (E_CAL_SOURCE_TYPE_TODO, "task list"); ++ } ++ ++ if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-journal"))) { ++ m->journal = open_ecal (E_CAL_SOURCE_TYPE_JOURNAL, "journal"); ++ } ++ ++ pst_import_file (m); ++ ++/* FIXME: Crashes often in here. ++ if (m->addressbook) { ++ g_object_unref (m->addressbook); ++ } ++ ++ if (m->calendar) { ++ g_object_unref (m->calendar); ++ } ++ ++ if (m->tasks) { ++ g_object_unref (m->tasks); ++ } ++ ++ if (m->journal) { ++ g_object_unref (m->journal); ++ } ++*/ ++ camel_operation_register (oldcancel); ++} ++ ++static void ++pst_import_file (PstImporter *m) ++{ ++ int ret; ++ gchar *filename; ++ pst_item *item = NULL; ++ pst_desc_ll *d_ptr; ++ ++ filename = g_filename_from_uri (((EImportTargetURI *)m->target)->uri_src, NULL, NULL); ++ m->parent_uri = g_strdup (((EImportTargetURI *)m->target)->uri_dest); /* Destination folder, was set in our widget */ ++ ++ camel_operation_start (NULL, _("Importing `%s'"), filename); ++ ++ if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-mail"))) { ++ mail_tool_uri_to_folder (m->parent_uri, CAMEL_STORE_FOLDER_CREATE, &m->base.ex); ++ } ++ ++ ret = pst_init (&m->pst, filename); ++ ++ if (ret < 0) { ++ g_free (filename); ++ camel_operation_end (NULL); ++ return; ++ } ++ ++ g_free (filename); ++ ++ camel_operation_progress_count (NULL, 1); ++ ++ if ((item = pst_parse_item (&m->pst, m->pst.d_head)) == NULL) { ++ pst_error_msg ("Could not get root record"); ++ return; ++ } ++ ++ camel_operation_progress_count (NULL, 2); ++ ++ if ((d_ptr = pst_getTopOfFolders (&m->pst, item)) == NULL) { ++ pst_error_msg ("Top of folders record not found. Cannot continue"); ++ return; ++ } ++ ++ camel_operation_progress_count (NULL, 3); ++ pst_import_folders (m, d_ptr); ++ ++ camel_operation_progress_count (NULL, 4); ++ ++ camel_operation_end (NULL); ++ ++ pst_freeItem (item); ++ ++} ++ ++static void ++pst_import_folders (PstImporter *m, pst_desc_ll *topitem) ++{ ++ pst_desc_ll *d_ptr; ++ gchar *seperator; ++ ++ d_ptr = topitem->child; ++ ++ /* Walk through folder tree */ ++ while (d_ptr != NULL && (camel_operation_cancel_check (NULL) == FALSE)) { ++ ++ pst_process_item (m, d_ptr); ++ ++ if (d_ptr->child != NULL) { ++ g_free (m->parent_uri); ++ m->parent_uri = g_strdup (m->folder_uri); ++ d_ptr = d_ptr->child; ++ } else if (d_ptr->next != NULL) { ++ d_ptr = d_ptr->next; ++ } else { ++ while (d_ptr != topitem && d_ptr->next == NULL) { ++ if(m->folder_uri) { ++ g_free(m->folder_uri); ++ } ++ ++ m->folder_uri = g_strdup (m->parent_uri); ++ seperator = g_strrstr (m->parent_uri, "/"); ++ ++ if (seperator != NULL) { ++ *seperator = '\0'; /* Truncate uri */ ++ } ++ ++ /*printf (" parent uri:%s\n", m->parent_uri);*/ ++ /*printf (" folder uri:%s\n", m->folder_uri);*/ ++ d_ptr = d_ptr->parent; ++ ++ } ++ if (d_ptr == topitem) { ++ return; ++ } ++ ++ d_ptr = d_ptr->next; ++ } ++ } ++} ++ ++static void ++pst_process_item (PstImporter *m, pst_desc_ll *d_ptr) ++{ ++ pst_item *item = NULL; ++ ++ if (d_ptr->desc == NULL) { ++ return; ++ } ++ ++ item = pst_parse_item (&m->pst, d_ptr); ++ ++ if (item == NULL) { ++ return; ++ } ++ ++ ++ if (item->message_store != NULL) { ++ pst_error_msg ("A second message_store has been found - ignored"); ++ pst_freeItem (item); ++ return; ++ } ++ ++ /*printf ("Item type: %i (%s)\n", item->type, (item->ascii_type ? item->ascii_type : "unknown"));*/ ++ ++ if (item->folder != NULL) { ++ pst_process_folder (m, item); ++ camel_operation_start (NULL, _("Importing `%s'"), item->file_as); ++ } else { ++ if (m->folder_count && (m->current_item < m->folder_count)) { ++ camel_operation_progress (NULL, (m->current_item * 100) / m->folder_count); ++ } else { ++ camel_operation_progress (NULL, 100); ++ } ++ ++ if (item->email != NULL && ++ (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) { ++ ++ if (GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-mail"))) ++ pst_process_email (m, item); ++ ++ } else if (item->contact && item->type == PST_TYPE_CONTACT) { ++ ++ if (m->addressbook && GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-addr"))) { ++ pst_process_contact (m, item); ++ } ++ ++ } else if (item->type == PST_TYPE_APPOINTMENT) { ++ ++ if (m->calendar && GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-appt"))) { ++ pst_process_appointment (m, item); ++ } ++ ++ } else if (item->type == PST_TYPE_TASK) { ++ ++ if (m->tasks && GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-task"))) { ++ pst_process_task (m, item); ++ } ++ ++ } else if (item->type == PST_TYPE_JOURNAL) { ++ ++ if (m->journal && GPOINTER_TO_INT (g_datalist_get_data (&m->target->data, "pst-do-journal"))) { ++ pst_process_journal (m, item); ++ } ++ ++ } ++ ++ m->current_item++; ++ } ++ ++ pst_freeItem (item); ++ ++ if (d_ptr->next == NULL) { ++ camel_operation_end (NULL); ++ } ++} ++ ++/** ++ * Convert string to utf8. Currently we just use the locale, but maybe there is encoding ++ * information hidden somewhere in the PST file? ++ * ++ * @param string String from PST file ++ * @return utf8 representation (caller should free), or NULL for error. ++ */ ++gchar * ++string_to_utf8(const gchar *string) ++{ ++ gchar *utf8; ++ ++ utf8 = g_locale_to_utf8 (string, -1, NULL, NULL, NULL); ++ ++ return utf8; ++} ++ ++/** ++ * Convert foldername to utf8 and escape characters if needed ++ * @param foldername from PST file ++ * @return converted folder name, or NULL for error. Caller should free ++ */ ++gchar * ++foldername_to_utf8 (const gchar *pstname) ++{ ++ gchar *utf8name, *folder_name; ++ ++ utf8name = string_to_utf8(pstname); ++ ++ if (utf8name == NULL) { ++ folder_name = camel_url_encode (pstname, NULL); ++ g_warning ("foldername_to_utf8: Cannot convert to utf8! foldername=%s", folder_name); ++ } else { ++ /* Encode using the current locale */ ++ folder_name = camel_url_encode (utf8name, NULL); ++ g_free (utf8name); ++ } ++ ++ g_strdelimit (folder_name, "/", '_'); ++ g_strescape (folder_name, NULL); ++ ++ return folder_name; ++} ++ ++static void ++pst_process_folder (PstImporter *m, pst_item *item) ++{ ++ gchar *uri; ++ g_free (m->folder_name); ++ g_free (m->folder_uri); ++ ++ if (item->file_as != NULL) { ++ m->folder_name = foldername_to_utf8 (item->file_as); ++ } else { ++ g_critical ("Folder: No name! item->file_as=%s", item->file_as); ++ m->folder_name = g_strdup ("unknown_name"); ++ } ++ ++ uri = g_strjoin ("/", m->parent_uri, m->folder_name, NULL); ++ m->folder_uri = uri; ++ ++ /*printf (" uri:%s\n", m->folder_uri);*/ ++ g_debug ("Folder name=%s email_count=%d unseen=%d assoc=%d", item->file_as, ++ item->folder->email_count, item->folder->unseen_email_count, item->folder->assoc_count); ++ ++ if (m->folder) { ++ camel_object_unref (m->folder); ++ m->folder = NULL; ++ } ++ ++ m->folder_count = item->folder->email_count; ++ m->current_item = 0; ++} ++ ++/** ++ * Create current folder in mail hierarchy. Parent folders will also be created. ++ * @param m PstImporter set to current folder ++ */ ++static void ++pst_create_folder (PstImporter *m) ++{ ++ const gchar *parent; ++ gchar *dest, *dest_end, *pos; ++ int dest_len; ++ ++ parent = ((EImportTargetURI *)m->target)->uri_dest; ++ g_debug("Create folder: %s", m->folder_uri); ++ dest = g_strdup (m->folder_uri); ++ ++ g_assert (g_str_has_prefix (dest, parent)); ++ ++ dest_len = strlen (dest); ++ dest_end = dest + dest_len; ++ ++ pos = dest + strlen(parent); ++ ++ while (pos != NULL && pos < dest_end) { ++ pos = g_strstr_len (pos+1, dest_end-pos, "/"); ++ if (pos != NULL) { ++ CamelFolder *folder; ++ ++ *pos = '\0'; ++ ++ g_debug ("Creating intermediate folder=%s", dest); ++ folder = mail_tool_uri_to_folder (dest, CAMEL_STORE_FOLDER_CREATE, &m->base.ex); ++ camel_object_unref(folder); ++ *pos = '/'; ++ } ++ } ++ ++ g_free (dest); ++ ++ if (m->folder) { ++ camel_object_unref (m->folder); ++ } ++ ++ m->folder = mail_tool_uri_to_folder (m->folder_uri, CAMEL_STORE_FOLDER_CREATE, &m->base.ex); ++ ++} ++ ++/** ++ * Create a camel mime part from given PST attachment ++ * @param attach attachment to convert ++ * @return CamelMimePart containing data and mime type ++ */ ++static CamelMimePart * ++attachment_to_part (PstImporter *m, pst_item_attach *attach) ++{ ++ CamelMimePart *part; ++ char *mimetype; ++ ++ part = camel_mime_part_new (); ++ ++ if (attach->filename2 || attach->filename1) { ++ camel_mime_part_set_filename (part, (attach->filename2 ? attach->filename2 : attach->filename1)); ++ camel_mime_part_set_disposition (part, "attachment"); ++ camel_mime_part_set_encoding (part, CAMEL_TRANSFER_ENCODING_BASE64); ++ } else { ++ camel_mime_part_set_disposition (part, "inline"); ++ } ++ ++ if (attach->mimetype != NULL) { ++ mimetype = attach->mimetype; ++ } else { ++ mimetype = "application/octet-stream"; ++ } ++ ++ if (attach->data != NULL) { ++ camel_mime_part_set_content (part, attach->data, strlen (attach->data), mimetype); ++ } else { ++ char *buf = NULL; ++ size_t size; ++ size = pst_attach_to_mem (&m->pst, attach, &buf); ++ ++ camel_mime_part_set_content (part, (char*) buf, size, mimetype); ++ free(buf); ++ } ++ ++ return part; ++} ++ ++static void ++pst_process_email (PstImporter *m, pst_item *item) ++{ ++ CamelMimeMessage *msg; ++ CamelInternetAddress *addr; ++ CamelMultipart *mp; ++ CamelMimePart *part; ++ CamelMessageInfo *info; ++ ++ if (m->folder == NULL) { ++ pst_create_folder (m); ++ } ++ ++ camel_folder_freeze (m->folder); ++ ++ msg = camel_mime_message_new (); ++ ++ if (item->email->subject != NULL) { ++ gchar *subj; ++ g_message ("Email subject=%s", item->email->subject->subj); ++ ++ subj = string_to_utf8 (item->email->subject->subj); ++ if (subj == NULL) { ++ g_warning ("Could not convert email subject to utf8: %s", item->email->subject->subj); ++ camel_mime_message_set_subject (msg, "(lost subject)"); ++ } else { ++ camel_mime_message_set_subject (msg, subj); ++ g_free(subj); ++ } ++ } ++ ++ addr = camel_internet_address_new (); ++ ++ if (item->email->outlook_sender_name != NULL && item->email->outlook_sender != NULL) { ++ camel_internet_address_add (addr, item->email->outlook_sender_name, item->email->outlook_sender); ++ } else if (item->email->outlook_sender_name != NULL) { ++ camel_address_decode (CAMEL_ADDRESS (addr), item->email->outlook_sender_name); ++ } else if (item->email->outlook_sender != NULL) { ++ camel_address_decode (CAMEL_ADDRESS (addr), item->email->outlook_sender); ++ } else { ++ /* Evo prints a warning if no from is set, so supply an empty address */ ++ camel_internet_address_add (addr, "", ""); ++ } ++ ++ camel_mime_message_set_from (msg, addr); ++ camel_object_unref (addr); ++ ++ if (item->email->sent_date != NULL) { ++ camel_mime_message_set_date (msg, fileTimeToUnixTime (item->email->sent_date, 0), 0); ++ } ++ ++ if (item->email->messageid != NULL) { ++ camel_mime_message_set_message_id (msg, item->email->messageid); ++ } ++ ++ if (item->email->header != NULL) { ++ /* Use mime parser to read headers */ ++ CamelStream *stream; ++ /*g_debug (" Email headers length=%zd", strlen (item->email->header));*/ ++ /*g_message (" Email headers... %s...", item->email->header);*/ ++ ++ stream = camel_stream_mem_new_with_buffer (item->email->header, strlen (item->email->header)); ++ if (camel_data_wrapper_construct_from_stream ((CamelDataWrapper *)msg, stream) == -1) ++ g_warning ("Error reading headers, skipped"); ++ ++ } else { ++ ++ if (item->email->sentto_address != NULL) { ++ addr = camel_internet_address_new (); ++ ++ g_print("\n\n The to header is:%s", item->email->sentto_address); ++ ++ if (camel_address_decode (CAMEL_ADDRESS (addr), item->email->sentto_address) > 0); ++ camel_mime_message_set_recipients (msg, "To", addr); ++ ++ camel_object_unref (addr); ++ } ++ ++ if (item->email->cc_address != NULL) { ++ addr = camel_internet_address_new (); ++ ++ if (camel_address_decode (CAMEL_ADDRESS (addr), item->email->cc_address) > 0); ++ camel_mime_message_set_recipients (msg, "CC", addr); ++ ++ camel_object_unref (addr); ++ } ++ } ++ ++ mp = camel_multipart_new (); ++ ++ if (item->attach != NULL) { ++ ++ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (mp), "multipart/mixed"); ++ ++ } else if (item->email->htmlbody && item->email->body) { ++ ++ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (mp), "multipart/alternate"); ++ ++ } else if (item->email->htmlbody) { ++ ++ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (mp), "text/html"); ++ ++ } ++ ++ camel_multipart_set_boundary (mp, NULL); ++ ++ if (item->email->body != NULL) { ++ /* Read internet headers */ ++ ++ /*g_debug (" Email body length=%zd", strlen (item->email->body)); ++ g_message (" Email body %100s...", item->email->body);*/ ++ ++ part = camel_mime_part_new (); ++ camel_mime_part_set_content (part, item->email->body, strlen (item->email->body), "text/plain"); ++ camel_multipart_add_part (mp, part); ++ camel_object_unref (part); ++ } ++ ++ if (item->email->htmlbody != NULL) { ++ /*g_debug (" HTML body length=%zd", strlen (item->email->htmlbody));*/ ++ part = camel_mime_part_new (); ++ camel_mime_part_set_content (part, item->email->htmlbody, strlen (item->email->htmlbody), "text/html"); ++ camel_multipart_add_part (mp, part); ++ camel_object_unref (part); ++ } ++ ++ item->current_attach = item->attach; ++ ++ while (item->current_attach != NULL) { ++ pst_item_attach *attach; ++ ++ attach = item->current_attach; ++ part = attachment_to_part(m, attach); ++ ++ camel_multipart_add_part (mp, part); ++ camel_object_unref (part); ++ ++ item->current_attach = item->current_attach->next; ++ } ++ ++ /*camel_mime_message_dump (msg, TRUE);*/ ++ ++ if (item->email->htmlbody || item->attach) { ++ camel_medium_set_content_object (CAMEL_MEDIUM (msg), CAMEL_DATA_WRAPPER (mp)); ++ } else if (item->email->body) { ++ camel_mime_part_set_content (CAMEL_MIME_PART (msg), item->email->body, strlen (item->email->body), "text/plain"); ++ } else { ++ g_warning ("Email without body. Subject:%s", ++ (item->email->subject->subj ? item->email->subject->subj : "(empty)")); ++ camel_mime_part_set_content (CAMEL_MIME_PART (msg), "\n", 1, "text/plain"); ++ } ++ ++ info = camel_message_info_new (NULL); ++ ++ /* Read message flags (see comments in libpst.c */ ++ if(item->email->flag && 0x01) ++ camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0); ++ ++ if(item->email->importance == 2) ++ camel_message_info_set_flags (info, CAMEL_MESSAGE_FLAGGED, ~0); ++ ++ if(item->email->flag && 0x08) ++ camel_message_info_set_flags (info, CAMEL_MESSAGE_DRAFT, ~0); ++ ++ camel_folder_append_message (m->folder, msg, info, NULL, &m->ex); ++ camel_message_info_free (info); ++ camel_object_unref (msg); ++ ++ camel_folder_sync (m->folder, FALSE, NULL); ++ camel_folder_thaw (m->folder); ++ ++ if (camel_exception_is_set (&m->ex)) { ++ g_critical ("Exception!"); ++ camel_exception_clear (&m->ex); ++ return; ++ } ++ ++} ++ ++static void ++contact_set_string (EContact *contact, EContactField id, char *string) ++{ ++ if (string != NULL) { ++ e_contact_set (contact, id, string); ++ } ++} ++ ++static void ++unknown_field (EContact *contact, GString *notes, char *name, char *string) ++{ ++ /* Field could not be mapped directly so add to notes field */ ++ if (string != NULL) { ++ g_string_append_printf (notes, "%s: %s\n", name, string); ++ } ++} ++ ++static void ++contact_set_address (EContact *contact, EContactField id, char *address, char *city, char *country, char *po_box, char *postal_code, char *state, char *street) ++{ ++ EContactAddress *eaddress; ++ ++ if (address || city || country || po_box || postal_code || state || street) { ++ eaddress = g_new0 (EContactAddress, 1); ++ if (po_box) { ++ eaddress->po = g_strdup (po_box); ++ } ++ //eaddress->ext = ++ ++ if (street) { ++ eaddress->street = g_strdup (street); ++ } ++ ++ if (city) { ++ eaddress->locality = g_strdup (city); ++ } ++ ++ if (state) { ++ eaddress->region = g_strdup (state); ++ } ++ ++ if (postal_code) { ++ eaddress->code = g_strdup (postal_code); ++ } ++ ++ if (country) { ++ eaddress->country = g_strdup (country); ++ } ++ ++ e_contact_set (contact, id, eaddress); ++ } ++} ++ ++void ++contact_set_date (EContact *contact, EContactField id, FILETIME *date) ++{ ++ if (date && (date->dwLowDateTime || date->dwHighDateTime) ) { ++ time_t t1; ++ struct tm tm; ++ EContactDate *bday; ++ bday = e_contact_date_new (); ++ ++ t1 = fileTimeToUnixTime (date, 0); ++ gmtime_r (&t1, &tm); ++ ++ bday->year = tm.tm_year + 1900; ++ bday->month = tm.tm_mon + 1; ++ bday->day = tm.tm_mday; ++ ++ e_contact_set (contact, id, bday); ++ } ++} ++ ++static void ++pst_process_contact (PstImporter *m, pst_item *item) ++{ ++ pst_item_contact *c; ++ EContact *ec; ++ c = item->contact; ++ GString *notes; ++ ++ notes = g_string_sized_new (2048); ++ g_message ("Contact name=%s", c->fullname); ++ ++ ec = e_contact_new (); ++ /* pst's fullname field only contains first, middle, surname */ ++ if (c->display_name_prefix || c->suffix) { ++ GString *name = g_string_sized_new (128); ++ ++ if (c->display_name_prefix) { ++ g_string_assign (name, c->display_name_prefix); ++ } ++ ++ if (c->first_name) { ++ g_string_append_printf (name, "%s%s", (name->len ? " " : ""), c->first_name); ++ } ++ ++ if (c->middle_name) { ++ g_string_append_printf (name, "%s%s", (name->len ? " " : ""), c->middle_name); ++ } ++ ++ if (c->surname) { ++ g_string_append_printf (name, "%s%s", (name->len ? " " : ""), c->surname); ++ } ++ ++ if (c->suffix) { ++ g_string_append_printf (name, "%s%s", (name->len ? " " : ""), c->suffix); ++ } ++ ++ contact_set_string (ec, E_CONTACT_FULL_NAME, name->str); ++ g_string_free (name, TRUE); ++ ++ } else { ++ contact_set_string (ec, E_CONTACT_FULL_NAME, c->fullname); ++ } ++ ++ /* unknown_field (ec, notes, "initials", c->initials); */ ++ ++ contact_set_string (ec, E_CONTACT_NICKNAME, c->nickname); ++ ++ contact_set_string (ec, E_CONTACT_ORG, c->company_name); ++ contact_set_string (ec, E_CONTACT_ORG_UNIT, c->department); ++ contact_set_string (ec, E_CONTACT_TITLE, c->job_title); ++ ++ contact_set_address (ec,E_CONTACT_ADDRESS_WORK, ++ c->business_address, c->business_city, c->business_country, ++ c->business_po_box, c->business_postal_code, c->business_state, c->business_street); ++ ++ contact_set_address (ec,E_CONTACT_ADDRESS_HOME, ++ c->home_address, c->home_city, c->home_country, ++ c->home_po_box, c->home_postal_code, c->home_state, c->home_street); ++ ++ contact_set_address (ec,E_CONTACT_ADDRESS_OTHER, ++ c->other_address, c->other_city, c->other_country, ++ c->other_po_box, c->other_postal_code, c->other_state, c->other_street); ++ ++ contact_set_string (ec, E_CONTACT_PHONE_ASSISTANT, c->assistant_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_BUSINESS_FAX, c->business_fax); ++ contact_set_string (ec, E_CONTACT_PHONE_BUSINESS, c->business_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_BUSINESS_2, c->business_phone2); ++ contact_set_string (ec, E_CONTACT_PHONE_CALLBACK, c->callback_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_CAR, c->car_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_COMPANY, c->company_main_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_HOME_FAX, c->home_fax); ++ contact_set_string (ec, E_CONTACT_PHONE_HOME, c->home_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_HOME_2, c->home_phone2); ++ contact_set_string (ec, E_CONTACT_PHONE_ISDN, c->isdn_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_MOBILE, c->mobile_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_OTHER_FAX, c->primary_fax); /* ? */ ++ contact_set_string (ec, E_CONTACT_PHONE_PAGER, c->pager_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_PRIMARY, c->primary_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_RADIO, c->radio_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_TTYTDD, c->ttytdd_phone); ++ contact_set_string (ec, E_CONTACT_PHONE_TELEX, c->telex); ++ unknown_field (ec, notes, "account_name", c->account_name); ++ contact_set_date (ec, E_CONTACT_ANNIVERSARY, c->wedding_anniversary); ++ contact_set_string (ec, E_CONTACT_ASSISTANT, c->assistant_name); ++ unknown_field (ec, notes, "billing_information", c->billing_information); ++ contact_set_date (ec, E_CONTACT_BIRTH_DATE, c->birthday); ++ /* contact_set_string (ec, E_CONTACT_CATEGORIES, c->??); */ ++ ++ contact_set_string (ec, E_CONTACT_EMAIL_1 , c->address1); ++ contact_set_string (ec, E_CONTACT_EMAIL_2 , c->address2); ++ contact_set_string (ec, E_CONTACT_EMAIL_3 , c->address3); ++ ++ /*unknown_field (ec, notes, "address1_desc" , c->address1_desc); ++ unknown_field (ec, notes, "address1_transport" , c->address1_transport); ++ unknown_field (ec, notes, "address2_desc" , c->address2_desc); ++ unknown_field (ec, notes, "address2_transport" , c->address2_transport); ++ unknown_field (ec, notes, "address3_desc" , c->address3_desc); ++ unknown_field (ec, notes, "address3_transport" , c->address3_transport);*/ ++ ++ /*unknown_field (ec, notes, "def_postal_address", c->def_postal_address);*/ ++ ++ /* unknown_field (ec, ??, c->gender); */ ++ unknown_field (ec, notes, "access_method", c->access_method); ++ unknown_field (ec, notes, "gov_id", c->gov_id); ++ unknown_field (ec, notes, "customer_id", c->customer_id); ++ unknown_field (ec, notes, "hobbies", c->hobbies); ++ unknown_field (ec, notes, "followup", c->followup); ++ ++ contact_set_string (ec, E_CONTACT_FREEBUSY_URL , c->free_busy_address); ++ ++ unknown_field (ec, notes, "keyword", c->keyword); ++ unknown_field (ec, notes, "language", c->language); ++ unknown_field (ec, notes, "location", c->location); ++ contact_set_string (ec, E_CONTACT_OFFICE, c->office_loc); ++ unknown_field (ec, notes, "computer_name", c->computer_name); ++ unknown_field (ec, notes, "ftp_site", c->ftp_site); ++ ++ contact_set_string (ec, E_CONTACT_MANAGER , c->manager_name); ++ unknown_field (ec, notes, "mileage", c->mileage); ++ unknown_field (ec, notes, "org_id", c->org_id); ++ contact_set_string (ec, E_CONTACT_ROLE, c->profession); ++ ++ contact_set_string (ec, E_CONTACT_SPOUSE , c->spouse_name); ++ ++ if (c->personal_homepage) { ++ contact_set_string (ec, E_CONTACT_HOMEPAGE_URL , c->personal_homepage); ++ if (c->business_homepage) { ++ unknown_field (ec, notes, "business_homepage", c->business_homepage); ++ } ++ } else if (c->business_homepage) { ++ contact_set_string (ec, E_CONTACT_HOMEPAGE_URL , c->business_homepage); ++ } ++ ++ if (item->comment) { ++ g_string_append_printf (notes, "%s\n", item->comment); ++ } ++ ++ if (item->email && item->email->body) { ++ g_string_append_printf (notes, "%s\n", item->email->body); ++ } ++ ++ contact_set_string (ec, E_CONTACT_NOTE, notes->str); ++ g_string_free (notes, TRUE); ++ ++ e_book_add_contact (m->addressbook, ec, NULL); ++ g_object_unref (ec); ++ ++} ++ ++/** ++ * Convert pst time to icaltimetype ++ * @param date time value from libpst ++ * @param is_date treat as date only (all day event)? ++ * @return converted date ++ */ ++struct icaltimetype ++get_ical_date (FILETIME *date, gboolean is_date) ++{ ++ if (date && (date->dwLowDateTime || date->dwHighDateTime) ) { ++ time_t t; ++ ++ t = fileTimeToUnixTime (date, 0); ++ return icaltime_from_timet_with_zone (t, is_date, NULL); ++ } else { ++ return icaltime_null_date (); ++ } ++} ++ ++char *rfc2445_datetime_format (FILETIME *ft) { ++ static char* buffer = NULL; ++ struct tm *stm = NULL; ++ ++ if (buffer == NULL) { ++ buffer = malloc (30); // should be enough ++ } ++ ++ stm = fileTimeToStructTM (ft); ++ strftime (buffer, 30, "%Y%m%dT%H%M%SZ", stm); ++ return buffer; ++} ++ ++static void ++set_cal_attachments (ECal *cal, ECalComponent *ec, PstImporter *m, pst_item_attach *attach) ++{ ++ GSList *list = NULL; ++ const char *uid; ++ char *store_dir; ++ ++ if (attach == NULL) { ++ return; ++ } ++ ++ e_cal_component_get_uid (ec, &uid); ++ store_dir = g_filename_from_uri (e_cal_get_local_attachment_store (cal), NULL, NULL); ++ ++ while (attach != NULL) { ++ const char* orig_filename; ++ char *filename, *tmp, *path, *dirname, *uri; ++ CamelMimePart *part; ++ CamelDataWrapper *content; ++ CamelStream *stream; ++ struct stat st; ++ ++ part = attachment_to_part(m, attach); ++ ++ orig_filename = camel_mime_part_get_filename(part); ++ ++ if (orig_filename == NULL) { ++ g_warning("Ignoring unnamed attachment"); ++ attach = attach->next; ++ continue; /* Ignore unnamed attachments */ ++ } ++ ++ tmp = camel_file_util_safe_filename (orig_filename); ++ filename = g_strdup_printf ("%s-%s", uid, tmp); ++ path = g_build_filename (store_dir, filename, NULL); ++ ++ g_free (tmp); ++ g_free (filename); ++ ++ dirname = g_path_get_dirname(path); ++ if (g_mkdir_with_parents(dirname, 0777) == -1) { ++ g_warning("Could not create directory %s: %s", dirname, g_strerror(errno)); ++ g_free(dirname); ++ attach = attach->next; ++ continue; ++ } ++ g_free(dirname); ++ ++ if (g_access(path, F_OK) == 0) { ++ if (g_access(path, W_OK) != 0) { ++ g_warning("Could not write file %s - file exists", path); ++ attach = attach->next; ++ continue; ++ } ++ } ++ ++ if (g_stat(path, &st) != -1 && !S_ISREG(st.st_mode)) { ++ g_warning("Could not write file %s - not a file", path); ++ attach = attach->next; ++ continue; ++ } ++ ++ if (!(stream = camel_stream_fs_new_with_name (path, O_WRONLY | O_CREAT | O_TRUNC, 0666))) { ++ g_warning ("Could not create stream for file %s - %s", path, g_strerror (errno)); ++ attach = attach->next; ++ continue; ++ } ++ ++ content = camel_medium_get_content_object (CAMEL_MEDIUM (part)); ++ ++ if (camel_data_wrapper_decode_to_stream (content, stream) == -1 ++ || camel_stream_flush (stream) == -1) ++ { ++ g_warning ("Could not write attachment to %s: %s", path, g_strerror (errno)); ++ camel_object_unref (stream); ++ attach = attach->next; ++ continue; ++ } ++ ++ camel_object_unref (stream); ++ ++ uri = g_filename_to_uri (path, NULL, NULL); ++ list = g_slist_append (list, g_strdup (uri)); ++ g_free (uri); ++ ++ camel_object_unref (part); ++ g_free (path); ++ ++ attach = attach->next; ++ ++ } ++ ++ g_free (store_dir); ++ ++ e_cal_component_set_attachment_list (ec, list); ++} ++ ++static void ++fill_calcomponent (PstImporter *m, pst_item *item, ECalComponent *ec, const char *type) ++{ ++ pst_item_appointment *a; ++ pst_item_email *e; ++ ++ a = item->appointment; ++ e = item->email; ++ ECalComponentText text; ++ struct icaltimetype tt_start, tt_end; ++ ECalComponentDateTime dt_start, dt_end; ++ ++ if (item->create_date) { ++ struct icaltimetype tt; ++ tt = get_ical_date (item->create_date, FALSE); ++ e_cal_component_set_created (ec, &tt); ++ } ++ if (item->modify_date) { ++ struct icaltimetype tt; ++ tt = get_ical_date (item->modify_date, FALSE); ++ e_cal_component_set_last_modified (ec, &tt); ++ } ++ ++ if (e) { ++ if (e->subject || e->proc_subject) { ++ if (e->subject) { ++ text.value = e->subject->subj; ++ } else if (e->proc_subject) { ++ text.value = e->proc_subject; ++ } ++ ++ text.altrep = NULL; /* email->proc_subject? */ ++ e_cal_component_set_summary (ec, &text); ++ g_message ("%s: %s", type, text.value); ++ } ++ if (e->body) { ++ GSList l; ++ text.value = e->body; ++ text.altrep = NULL; ++ l.data = &text; ++ l.next = NULL; ++ e_cal_component_set_description_list (ec, &l); ++ } ++ } else { ++ g_warning ("%s without subject / body!", type); ++ } ++ ++ if (a->location) { ++ e_cal_component_set_location (ec, a->location); ++ } ++ ++ if (a->start) { ++ tt_start = get_ical_date (a->start, a->all_day); ++ dt_start.value = &tt_start; ++ dt_start.tzid = NULL; ++ e_cal_component_set_dtstart (ec, &dt_start); ++ g_message ("start:%s", rfc2445_datetime_format (a->start)); ++ } ++ ++ if (a->end) { ++ tt_end = get_ical_date (a->end, a->all_day); ++ dt_end.value = &tt_end; ++ dt_end.tzid = NULL; ++ e_cal_component_set_dtend (ec, &dt_end); ++ g_message ("end:%s", rfc2445_datetime_format (a->end)); ++ } ++ ++ switch (a->showas) { ++ case PST_FREEBUSY_TENTATIVE: ++ e_cal_component_set_status (ec, ICAL_STATUS_TENTATIVE); ++ break; ++ case PST_FREEBUSY_FREE: ++ // mark as transparent and as confirmed ++ e_cal_component_set_transparency (ec, E_CAL_COMPONENT_TRANSP_TRANSPARENT); ++ case PST_FREEBUSY_BUSY: ++ case PST_FREEBUSY_OUT_OF_OFFICE: ++ e_cal_component_set_status (ec, ICAL_STATUS_CONFIRMED); ++ break; ++ } ++ switch (a->label) { ++ case PST_APP_LABEL_NONE: ++ break; ++ case PST_APP_LABEL_IMPORTANT: ++ e_cal_component_set_categories (ec, "Important"); break; ++ case PST_APP_LABEL_BUSINESS: ++ e_cal_component_set_categories (ec, "Business"); break; ++ case PST_APP_LABEL_PERSONAL: ++ e_cal_component_set_categories (ec, "Personal"); break; ++ case PST_APP_LABEL_VACATION: ++ e_cal_component_set_categories (ec, "Vacation"); break; ++ case PST_APP_LABEL_MUST_ATTEND: ++ e_cal_component_set_categories (ec, "Must-attend"); break; ++ case PST_APP_LABEL_TRAVEL_REQ: ++ e_cal_component_set_categories (ec, "Travel-required"); break; ++ case PST_APP_LABEL_NEEDS_PREP: ++ e_cal_component_set_categories (ec, "Needs-preparation"); break; ++ case PST_APP_LABEL_BIRTHDAY: ++ e_cal_component_set_categories (ec, "Birthday"); break; ++ case PST_APP_LABEL_ANNIVERSARY: ++ e_cal_component_set_categories (ec, "Anniversary"); break; ++ case PST_APP_LABEL_PHONE_CALL: ++ e_cal_component_set_categories (ec, "Phone-call"); break; ++ } ++ ++ if (a->alarm || a->alarm_minutes) { ++ ECalComponentAlarm *alarm; ++ ECalComponentAlarmTrigger trigger; ++ ++ alarm = e_cal_component_alarm_new (); ++ ++ if (a->alarm_minutes) { ++ trigger.type = E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START; ++ trigger.u.rel_duration = icaldurationtype_from_int (- (a->alarm_minutes)*60); ++ e_cal_component_alarm_set_trigger (alarm, trigger); ++ } ++ ++ if (a->alarm) { ++ if (a->alarm_filename) { ++ e_cal_component_alarm_set_action (alarm, E_CAL_COMPONENT_ALARM_AUDIO); ++ } else { ++ e_cal_component_alarm_set_action (alarm, E_CAL_COMPONENT_ALARM_DISPLAY); ++ } ++ } ++ ++ e_cal_component_add_alarm (ec, alarm); ++ e_cal_component_alarm_free(alarm); ++ ++ } ++ ++ if (a->recurrence != PST_APP_RECUR_NONE) { ++ struct icalrecurrencetype r; ++ GSList recur_list; ++ ++ icalrecurrencetype_clear (&r); ++ r.interval = 1; /* Interval not implemented in libpst */ ++ if (a->recurrence_end) { ++ r.until = get_ical_date (a->recurrence_end, FALSE); ++ } ++ ++ switch (a->recurrence_type) { ++ case PST_APP_RECUR_DAILY: ++ r.freq = ICAL_DAILY_RECURRENCE; break; ++ case PST_APP_RECUR_WEEKLY: ++ r.freq = ICAL_WEEKLY_RECURRENCE; break; ++ case PST_APP_RECUR_MONTHLY: ++ r.freq = ICAL_MONTHLY_RECURRENCE; break; ++ case PST_APP_RECUR_YEARLY: ++ r.freq = ICAL_YEARLY_RECURRENCE; break; ++ default: ++ r.freq = ICAL_NO_RECURRENCE; ++ } ++ ++ recur_list.data = &r; ++ recur_list.next = NULL; ++ e_cal_component_set_rrule_list (ec, &recur_list); ++ } ++ ++} ++ ++static void ++pst_process_appointment (PstImporter *m, pst_item *item) ++{ ++ ECalComponent *ec; ++ ++ ec = e_cal_component_new (); ++ e_cal_component_set_new_vtype (ec, E_CAL_COMPONENT_EVENT); ++ ++ fill_calcomponent (m, item, ec, "appointment"); ++ set_cal_attachments (m->calendar, ec, m, item->attach); ++ ++ if (!e_cal_create_object (m->calendar, e_cal_component_get_icalcomponent (ec), NULL, NULL)) { ++ g_warning("Creation of appointment failed"); ++ g_free(ec); ++ } ++ ++ g_object_unref (ec); ++ ++} ++ ++static void ++pst_process_task (PstImporter *m, pst_item *item) ++{ ++ ECalComponent *ec; ++ ++ ec = e_cal_component_new (); ++ e_cal_component_set_new_vtype (ec, E_CAL_COMPONENT_TODO); ++ ++ fill_calcomponent (m, item, ec, "task"); ++ set_cal_attachments (m->tasks, ec, m, item->attach); ++ ++ /* Note - libpst is missing many fields. E.g. task status, start/completion date, % complete */ ++ ++ if (!e_cal_create_object (m->tasks, e_cal_component_get_icalcomponent (ec), NULL, NULL)) { ++ g_warning("Creation of task failed"); ++ g_free(ec); ++ } ++ ++ g_object_unref (ec); ++ ++} ++ ++static void ++pst_process_journal (PstImporter *m, pst_item *item) ++{ ++ struct pst_item_journal *j; ++ ECalComponent *ec; ++ ++ j = item->journal; ++ ec = e_cal_component_new (); ++ e_cal_component_set_new_vtype (ec, E_CAL_COMPONENT_JOURNAL); ++ ++ fill_calcomponent (m, item, ec, "journal"); ++ set_cal_attachments (m->journal, ec, m, item->attach); ++ ++ /* Note - an Evo memo entry does not have date started/finished or type fields :( */ ++ /*if (j) { ++ ECalComponentText text; ++ struct icaltimetype tt_start, tt_end; ++ ECalComponentDateTime dt_start, dt_end; ++ ++ if (j->start) { ++ tt_start = get_ical_date (j->start, FALSE); ++ dt_start.value = &tt_start; ++ dt_start.tzid = NULL; ++ e_cal_component_set_dtstart (ec, &dt_start); ++ g_message ("journal start:%s", rfc2445_datetime_format (j->start)); ++ } ++ ++ if (j->end) { ++ tt_end = get_ical_date (j->end, FALSE); ++ dt_end.value = &tt_end; ++ dt_end.tzid = NULL; ++ e_cal_component_set_dtend (ec, &dt_end); ++ g_message ("end:%s", rfc2445_datetime_format (j->end)); ++ } ++ g_message ("type: %s", j->type); ++ }*/ ++ ++ if (!e_cal_create_object (m->journal, e_cal_component_get_icalcomponent (ec), NULL, NULL)) { ++ g_warning("Creation of journal entry failed"); ++ g_free(ec); ++ } ++ ++ g_object_unref (ec); ++ ++} ++ ++/* Print an error message - maybe later bring up an error dialog? */ ++static void ++pst_error_msg (const char *fmt, ...) ++{ ++ va_list ap; ++ ++ va_start (ap, fmt); ++ g_critical (fmt, ap); ++ va_end (ap); ++} ++ ++static void ++pst_import_imported (PstImporter *m) ++{ ++ e_import_complete (m->target->import, (EImportTarget *)m->target); ++} ++ ++static void ++pst_import_free (PstImporter *m) ++{ ++// pst_close (&m->pst); ++ camel_operation_unref (m->status); ++ ++ g_free (m->status_what); ++ g_mutex_free (m->status_lock); ++ ++ g_source_remove (m->status_timeout_id); ++ m->status_timeout_id = 0; ++ ++ g_free (m->folder_name); ++ g_free (m->folder_uri); ++ g_free (m->parent_uri); ++ ++ g_object_unref (m->import); ++} ++ ++static MailMsgInfo pst_import_info = { ++ sizeof (PstImporter), ++ (MailMsgDescFunc) pst_import_describe, ++ (MailMsgExecFunc) pst_import_import, ++ (MailMsgDoneFunc) pst_import_imported, ++ (MailMsgFreeFunc) pst_import_free, ++}; ++ ++static gboolean ++pst_status_timeout (void *data) ++{ ++ PstImporter *importer = data; ++ int pc; ++ char *what; ++ ++ if (importer->status_what) { ++ g_mutex_lock (importer->status_lock); ++ what = importer->status_what; ++ importer->status_what = NULL; ++ pc = importer->status_pc; ++ g_mutex_unlock (importer->status_lock); ++ ++ e_import_status (importer->target->import, (EImportTarget *)importer->target, what, pc); ++ } ++ ++ return TRUE; ++} ++ ++static void ++pst_status (CamelOperation *op, const char *what, int pc, void *data) ++{ ++ PstImporter *importer = data; ++ ++ if (pc == CAMEL_OPERATION_START) { ++ pc = 0; ++ } else if (pc == CAMEL_OPERATION_END) { ++ pc = 100; ++ } ++ ++ g_mutex_lock (importer->status_lock); ++ g_free (importer->status_what); ++ importer->status_what = g_strdup (what); ++ importer->status_pc = pc; ++ g_mutex_unlock (importer->status_lock); ++} ++ ++static int ++pst_import (EImport *ei, EImportTarget *target) ++{ ++ PstImporter *m; ++ int id; ++ ++ m = mail_msg_new (&pst_import_info); ++ g_datalist_set_data (&target->data, "pst-msg", m); ++ m->import = ei; ++ g_object_ref (m->import); ++ m->target = target; ++ g_message ("pst_import pstimporter=%p EImport=%p target=%p", m, ei, target); ++ ++ m->parent_uri = NULL; ++ m->folder_name = NULL; ++ m->folder_uri = NULL; ++ ++ m->addressbook = NULL; ++ m->calendar = NULL; ++ m->tasks = NULL; ++ m->journal = NULL; ++ ++ m->status_timeout_id = g_timeout_add (100, pst_status_timeout, m); ++ /*m->status_timeout_id = NULL;*/ ++ m->status_lock = g_mutex_new (); ++ m->status = camel_operation_new (pst_status, m); ++ ++ id = m->base.seq; ++ ++ mail_msg_unordered_push (m); ++ ++ return id; ++} ++ ++/* Start the main import operation */ ++void ++org_credativ_evolution_readpst_import (EImport *ei, EImportTarget *target, EImportImporter *im) ++{ ++ if (GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-mail")) ++ || GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-addr")) ++ || GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-appt")) ++ || GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-task")) ++ || GPOINTER_TO_INT (g_datalist_get_data (&target->data, "pst-do-journal"))) { ++ pst_import (ei, target); ++ } else { ++ e_import_complete (target->import, target); ++ } ++} ++ ++void ++org_credativ_evolution_readpst_cancel (EImport *ei, EImportTarget *target, EImportImporter *im) ++{ ++ PstImporter *m = g_datalist_get_data (&target->data, "pst-msg"); ++ ++ if (m) { ++ camel_operation_cancel (m->status); ++ } ++} ++ ++int ++e_plugin_lib_enable (EPluginLib *ep, int enable) ++{ ++ if (enable) { ++ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); ++ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); ++ g_message ("pst Plugin enabled"); ++ } else { ++ g_message ("pst Plugin disabled"); ++ } ++ ++ return 0; ++} ++ ++/** ++ * Open PST file and determine root folder name ++ * @param pst: pst_file structure to be used by libpst ++ * @param filename : path to file ++ * @return 0 for sucess, -1 for failure ++ */ ++int ++pst_init (pst_file *pst, gchar *filename) ++{ ++ ++#if 0 ++ char *d_log = "readpst.log"; ++ /* initialize log file */ ++ DEBUG_INIT (d_log); ++ DEBUG_REGISTER_CLOSE (); ++#endif ++ ++ DEBUG_ENT ("main"); ++ if (pst_open (pst, filename) < 0) { ++ pst_error_msg ("Error opening PST file %s", filename); ++ return -1; ++ } ++ ++// if (1) { ++ printf("\n\n %i is the pst index type\n\n", pst->ind_type); ++/* if (pst->ind_type != 14) { ++ printf("\nentered or not??\n not unknown index structure. Could this be a new Outlook 2003 PST file?\n"); ++ unicode_init(); ++ set_read64(); ++// DEBUG_RET(); ++// return -1; ++ } ++ else { ++ printf("\n\n check maadi\n\n"); ++// unicode_close(); ++ reset_read(); ++ } ++*/ ++ if (pst_load_index (pst) < 0) { ++ pst_error_msg ("Error loading indexes"); ++ return -1; ++ } ++ ++ if (pst_load_extended_attributes (pst) < 0) { ++ pst_error_msg ("Error loading file items"); ++ return -1; ++ } ++ ++// unicode_init(); ++ return 0; ++} ++ ++/** ++ * Open determine root folder name of PST file ++ * @param pst: pst_file structure to be used by libpst ++ * @param filename : if non NULL, fallback to this name if folder name is not available ++ * @return pointer to name of root folder (should be freed by caller), or NULL if error ++ */ ++gchar * ++get_pst_rootname (pst_file *pst, gchar *filename) ++{ ++ pst_item *item = NULL; ++ gchar *rootname = NULL; ++ ++ printf("\n reached here\n"); ++ if ((item = pst_parse_item (pst, pst->d_head)) == NULL) { ++ pst_error_msg ("Could not get root record"); ++ printf("\n crashed in if i guess\n"); ++ return NULL; ++ } ++ printf("\n crashed here i guess\n"); ++ if (item->message_store == NULL) { ++ pst_error_msg ("Could not get root message store"); ++ pst_freeItem (item); ++ return NULL; ++ } ++ ++ /* default the file_as to the same as the main filename if it doesn't exist */ ++ if (item->file_as == NULL) { ++ if (filename == NULL) { ++ pst_freeItem (item); ++ return NULL; ++ } ++ rootname = g_path_get_basename (filename); ++ } else { ++ rootname = g_strdup (item->file_as); ++ } ++ ++ g_message ("Root folder name: '%s'", rootname); ++ ++ pst_freeItem (item); ++ ++ return rootname; ++} +Index: plugins/pst-import/ChangeLog +=================================================================== +--- plugins/pst-import/ChangeLog (revision 0) ++++ plugins/pst-import/ChangeLog (revision 0) +@@ -0,0 +1,9 @@ ++2008-09-18 Bharath Acharya ++ ++ Basic functionality implemented by ++ Chris Halls ++ ++ ** Added PST-Import plugin ++ * Makefile.am: ++ * org-gnome-pst.eplug.xml: ++ * pst-importer.c: +Index: plugins/pst-import/org-gnome-pst.eplug.xml +=================================================================== +--- plugins/pst-import/org-gnome-pst.eplug.xml (revision 0) ++++ plugins/pst-import/org-gnome-pst.eplug.xml (revision 0) +@@ -0,0 +1,23 @@ ++ ++ ++ ++ <_description>Import Outlook messages from PST file ++ ++ ++ ++ ++ ++ ++ ++ ++ +Index: plugins/pst-import/Makefile.am +=================================================================== +--- plugins/pst-import/Makefile.am (revision 0) ++++ plugins/pst-import/Makefile.am (revision 0) +@@ -0,0 +1,24 @@ ++INCLUDES = \ ++ -I$(EVOLUTION_SOURCE) \ ++ -I$(top_srcdir) \ ++ -DGETTEXT_PACKAGE="\"$(GETTEXT_PACKAGE)\"" \ ++ -DLOCALEDIR="\"$(LOCALEDIR)\"" \ ++ $(EVOLUTION_CFLAGS) \ ++ $(EVOLUTION_MAIL_CFLAGS) ++ ++@EVO_PLUGIN_RULE@ ++ ++plugin_DATA = org-gnome-pst.eplug ++plugin_LTLIBRARIES = liborg-gnome-pst.la ++ ++liborg_gnome_pst_la_SOURCES = pst-importer.c ++liborg_gnome_pst_la_LDFLAGS = -module -avoid-version ++liborg_gnome_pst_la_LIBADD = \ ++ $(LIBPST_LIBS) ++ ++EXTRA_DIST = org-gnome-pst.eplug.xml ++ ++BUILT_SOURCES = org-gnome-pst.eplug ++ ++CLEANFILES = $(BUILT_SOURCES) ++ +Index: configure.in +=================================================================== +--- configure.in (revision 36340) ++++ configure.in (working copy) +@@ -1738,7 +1738,7 @@ + plugins_base="$plugins_base_always $SA_JUNK_PLUGIN $BF_JUNK_PLUGIN $EXCHANGE_PLUGIN $MONO_PLUGIN " + all_plugins_base="$plugins_base_always sa-junk-plugin bogo-junk-plugin exchange-operations mono" + +-plugins_standard_always="bbdb subject-thread save-calendar select-one-source copy-tool mail-to-task mark-calendar-offline audio-inline mailing-list-actions default-mailer import-ics-attachments prefer-plain mail-notification attachment-reminder face backup-restore email-custom-header templates" ++plugins_standard_always="bbdb subject-thread save-calendar select-one-source copy-tool mail-to-task mark-calendar-offline audio-inline mailing-list-actions default-mailer import-ics-attachments prefer-plain mail-notification attachment-reminder face backup-restore email-custom-header templates pst-import" + + plugins_standard="$plugins_standard_always" + all_plugins_standard="$plugins_standard" +@@ -1853,6 +1853,23 @@ + fi + fi + ++if echo ${plugins_enabled} | grep "pst-import" > /dev/null ++then ++ if ${PKG_CONFIG} --exists libpst ++ then ++ dnl ********************* ++ dnl libpst ++ dnl ********************* ++ PKG_CHECK_MODULES(LIBPST, libpst) ++ AC_SUBST(LIBPST_CFLAGS) ++ AC_SUBST(LIBPST_LIBS) ++ else ++ plugins_enabled=`echo $plugins_enabled | sed -e "s/pst-import//g"` ++ echo "warning: libpst was not found, pst-import plugin will not be built." ++ echo "you are probably missing libpst-devel package." ++ fi ++fi ++ + dnl *********** + dnl GConf stuff + dnl *********** +@@ -2049,6 +2066,7 @@ + plugins/imap-features/Makefile + plugins/tnef-attachments/Makefile + plugins/templates/Makefile ++plugins/pst-import/Makefile + plugins/face/Makefile + plugins/external-editor/Makefile + plugins/webdav-account-setup/Makefile