1 /*
2  * Copyright (C) 2015 SUSE (www.suse.com)
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
16  *
17  * Authors:
18  *           David Liang <dliang@suse.com>
19  *
20  */
21 
22 #include "evolution-config.h"
23 
24 #include <stdio.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <dirent.h>
30 #include <string.h>
31 
32 #include <gtk/gtk.h>
33 #include <glib/gi18n-lib.h>
34 
35 #include "kmail-libs.h"
36 #include "mail-importer.h"
37 
38 #include "libemail-engine/libemail-engine.h"
39 #include "e-util/e-util.h"
40 #include "shell/e-shell.h"
41 #include "shell/e-shell-window.h"
42 #include "shell/e-shell-view.h"
43 #include "shell/e-shell-sidebar.h"
44 
45 #include "mail/e-mail-backend.h"
46 #include "mail/em-folder-selection-button.h"
47 #include "mail/em-folder-tree-model.h"
48 #include "mail/em-folder-tree.h"
49 
50 #define ENABLE_SELECT 0
51 #define d(x)
52 
53 typedef struct {
54 	EImport *import;
55 	EImportTarget *target;
56 
57 	GMutex status_lock;
58 	gchar *status_what;
59 	gint status_pc;
60 	gint status_timeout_id;
61 	GCancellable *cancellable;      /* cancel/status port */
62 
63 	gchar *uri;
64 } KMailImporter;
65 
66 static gboolean
kmail_supported(EImport * ei,EImportTarget * target,EImportImporter * im)67 kmail_supported (EImport *ei,
68                  EImportTarget *target,
69                  EImportImporter *im)
70 {
71 	return kmail_is_supported ();
72 }
73 
74 static void
kmail_import_done(gpointer data,GError ** error)75 kmail_import_done (gpointer data,
76                    GError **error)
77 {
78 	KMailImporter *importer = data;
79 
80 	g_source_remove (importer->status_timeout_id);
81 	g_free (importer->status_what);
82 
83 	g_mutex_clear (&importer->status_lock);
84 	g_object_unref (importer->cancellable);
85 
86 	e_import_complete (importer->import, importer->target, error ? *error : NULL);
87 	g_free (importer);
88 }
89 
90 static void
kmail_status(CamelOperation * op,const gchar * what,gint pc,gpointer data)91 kmail_status (CamelOperation *op,
92               const gchar *what,
93               gint pc,
94               gpointer data)
95 {
96 	KMailImporter *importer = data;
97 	g_mutex_lock (&importer->status_lock);
98 	g_free (importer->status_what);
99 	importer->status_what = g_strdup (what);
100 	importer->status_pc = pc;
101 	g_mutex_unlock (&importer->status_lock);
102 }
103 
104 static gboolean
kmail_status_timeout(gpointer data)105 kmail_status_timeout (gpointer data)
106 {
107 	KMailImporter *importer = data;
108 	gint pc;
109 	gchar *what;
110 	if (importer->status_what) {
111 		g_mutex_lock (&importer->status_lock);
112 		what = importer->status_what;
113 		importer->status_what = NULL;
114 		pc = importer->status_pc;
115 		g_mutex_unlock (&importer->status_lock);
116 
117 		e_import_status (
118 			importer->import, (EImportTarget *)
119 			importer->target, what, pc);
120 	}
121 
122 	return TRUE;
123 }
124 
125 static void
checkbox_toggle_cb(GtkToggleButton * tb,EImportTarget * target)126 checkbox_toggle_cb (GtkToggleButton *tb,
127                     EImportTarget *target)
128 {
129 	g_datalist_set_data (
130 		&target->data, "kmail-do-mail",
131 		GINT_TO_POINTER (gtk_toggle_button_get_active (tb)));
132 }
133 
134 #if ENABLE_SELECT
135 static void
folder_selected(EMFolderSelectionButton * button,EImportTargetURI * target)136 folder_selected (EMFolderSelectionButton *button,
137                  EImportTargetURI *target)
138 {
139 	g_free (target->uri_dest);
140 	target->uri_dest = g_strdup (em_folder_selection_button_get_folder_uri (button));
141 }
142 
143 static GtkWidget *
import_folder_getwidget(EImport * ei,EImportTarget * target,EImportImporter * im)144 import_folder_getwidget (EImport *ei,
145                          EImportTarget *target,
146                          EImportImporter *im)
147 {
148 	EShell *shell;
149 	EShellBackend *shell_backend;
150 	EMailBackend *backend;
151 	EMailSession *session;
152 	GtkWindow *window;
153 	GtkWidget *hbox, *w;
154 	GtkLabel *label;
155 	gchar *select_uri = NULL;
156 
157 	/* XXX Dig up the mail backend from the default EShell.
158 	 *     Since the EImport framework doesn't allow for user
159 	 *     data, I don't see how else to get to it. */
160 	shell = e_shell_get_default ();
161 	shell_backend = e_shell_get_backend_by_name (shell, "mail");
162 
163 	backend = E_MAIL_BACKEND (shell_backend);
164 	session = e_mail_backend_get_session (backend);
165 
166 	/* preselect the folder selected in a mail view */
167 	window = e_shell_get_active_window (shell);
168 	if (E_IS_SHELL_WINDOW (window)) {
169 		EShellWindow *shell_window;
170 		const gchar *view;
171 
172 		shell_window = E_SHELL_WINDOW (window);
173 		view = e_shell_window_get_active_view (shell_window);
174 
175 		if (view && g_str_equal (view, "mail")) {
176 			EShellView *shell_view;
177 			EShellSidebar *shell_sidebar;
178 			EMFolderTree *folder_tree = NULL;
179 
180 			shell_view = e_shell_window_get_shell_view (
181 				shell_window, view);
182 
183 			shell_sidebar =
184 				e_shell_view_get_shell_sidebar (shell_view);
185 
186 			g_object_get (
187 				shell_sidebar, "folder-tree",
188 				&folder_tree, NULL);
189 
190 			select_uri =
191 				em_folder_tree_get_selected_uri (folder_tree);
192 
193 			g_object_unref (folder_tree);
194 		}
195 	}
196 
197 	if (!select_uri) {
198 		const gchar *uri;
199 		uri = e_mail_session_get_local_folder_uri (
200 			session, E_MAIL_LOCAL_FOLDER_INBOX);
201 		select_uri = g_strdup (uri);
202 	}
203 
204 	hbox = gtk_hbox_new (FALSE, 0);
205 
206 	w = gtk_label_new_with_mnemonic (_("_Destination folder:"));
207 	gtk_box_pack_start ((GtkBox *) hbox, w, FALSE, TRUE, 6);
208 
209 	label = GTK_LABEL (w);
210 
211 	w = em_folder_selection_button_new (
212 		session, _("Select folder"),
213 		_("Select folder to import into"));
214 	gtk_label_set_mnemonic_widget (label, w);
215 	em_folder_selection_button_set_folder_uri (
216 		EM_FOLDER_SELECTION_BUTTON (w), select_uri);
217 	folder_selected (
218 		EM_FOLDER_SELECTION_BUTTON (w), (EImportTargetURI *) target);
219 	g_signal_connect (
220 		w, "selected",
221 		G_CALLBACK (folder_selected), target);
222 	gtk_box_pack_start ((GtkBox *) hbox, w, FALSE, TRUE, 6);
223 
224 	w = gtk_vbox_new (FALSE, 0);
225 	gtk_box_pack_start ((GtkBox *) w, hbox, FALSE, FALSE, 0);
226 	gtk_widget_show_all (w);
227 
228 	g_free (select_uri);
229 
230 	return w;
231 }
232 #endif
233 
234 static GtkWidget *
kmail_getwidget(EImport * ei,EImportTarget * target,EImportImporter * im)235 kmail_getwidget (EImport *ei,
236                  EImportTarget *target,
237                  EImportImporter *im)
238 {
239 	GtkWidget *box, *w;
240 	GSList *contact_list;
241 	gint count;
242 	gchar *contact_str;
243 
244 
245 	g_datalist_set_data (
246 		&target->data, "kmail-do-mail", GINT_TO_POINTER (TRUE));
247 
248 	box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
249 	w = gtk_check_button_new_with_label (_("Mail"));
250 	gtk_toggle_button_set_active ((GtkToggleButton *) w, TRUE);
251 	g_signal_connect (
252 		w, "toggled",
253 		G_CALLBACK (checkbox_toggle_cb), target);
254 
255 	gtk_box_pack_start ((GtkBox *) box, w, FALSE, FALSE, 0);
256 
257 	contact_list = kcontact_get_list ();
258 	count = g_slist_length (contact_list);
259 	contact_str = g_strdup_printf (ngettext ("%d Address", "%d Addresses", count), count);
260 	w = gtk_check_button_new_with_label (contact_str);
261 	gtk_toggle_button_set_active ((GtkToggleButton *) w, TRUE);
262 	g_signal_connect (
263 		w, "toggled",
264 		G_CALLBACK (checkbox_toggle_cb), target);
265 
266 	gtk_box_pack_start ((GtkBox *) box, w, FALSE, FALSE, 0);
267 
268 	/* for now, we don't allow to select a folder */
269 	#if ENABLE_SELECT
270 	w = import_folder_getwidget (ei, target, im);
271 	gtk_box_pack_start ((GtkBox *) box, w, FALSE, FALSE, 0);
272 	#endif
273 
274 	gtk_widget_show_all (box);
275 	g_slist_free_full (contact_list, g_free);
276 	g_free (contact_str);
277 
278 	return box;
279 }
280 
281 static void
kmail_import(EImport * ei,EImportTarget * target,EImportImporter * im)282 kmail_import (EImport *ei,
283               EImportTarget *target,
284               EImportImporter *im)
285 {
286 	EShell *shell;
287 	EShellBackend *shell_backend;
288 	EMailSession *session;
289 	KMailImporter *importer;
290 	gchar *path;
291 	GSList *contact_list;
292 
293 	/* XXX Dig up the EMailSession from the default EShell.
294 	 *     Since the EImport framework doesn't allow for user
295 	 *     data, I don't see how else to get to it. */
296 	shell = e_shell_get_default ();
297 	shell_backend = e_shell_get_backend_by_name (shell, "mail");
298 	session = e_mail_backend_get_session (E_MAIL_BACKEND (shell_backend));
299 
300 	importer = g_malloc0 (sizeof (*importer));
301 	g_datalist_set_data (&target->data, "kmail-data", importer);
302 	importer->status_what = NULL;
303 	importer->import = ei;
304 	importer->target = target;
305 	importer->cancellable = camel_operation_new ();
306 	g_mutex_init (&importer->status_lock);
307 	importer->status_timeout_id = g_timeout_add (100, kmail_status_timeout, importer);
308 
309 	g_signal_connect (
310 		importer->cancellable, "status",
311 		G_CALLBACK (kmail_status), importer);
312 
313 	/* import emails */
314 	path = kmail_get_base_dir ();
315 	mail_importer_import_kmail (
316 		session, path, NULL,
317 		importer->cancellable, kmail_import_done, importer);
318 	g_free (path);
319 
320 	/* import contacts */
321 	contact_list = kcontact_get_list ();
322 	kcontact_load (contact_list);
323 	g_slist_free_full (contact_list, g_free);
324 }
325 
326 static void
kmail_cancel(EImport * ei,EImportTarget * target,EImportImporter * im)327 kmail_cancel (EImport *ei,
328               EImportTarget *target,
329               EImportImporter *im)
330 {
331 	KMailImporter *m = g_datalist_get_data (&target->data, "kmail-data");
332 
333 	if (m)
334 		g_cancellable_cancel (m->cancellable);
335 }
336 
337 static EImportImporter kmail_importer = {
338 	E_IMPORT_TARGET_HOME,
339 	0,
340 	kmail_supported,
341 	kmail_getwidget,
342 	kmail_import,
343 	kmail_cancel,
344 	NULL, /* get_preview */
345 };
346 
347 EImportImporter *
kmail_importer_peek(void)348 kmail_importer_peek (void)
349 {
350 	kmail_importer.name = _("Evolution KMail importer");
351 	kmail_importer.description = _("Import mail and contacts from KMail.");
352 
353 	return &kmail_importer;
354 }
355