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 <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 
31 #include <glib.h>
32 #include <glib/gi18n-lib.h>
33 #include <glib/gstdio.h>
34 #include <gio/gio.h>
35 
36 #include <libebook/libebook.h>
37 
38 #include "shell/e-shell.h"
39 #include "mail/e-mail-backend.h"
40 
41 #include "kmail-libs.h"
42 
43 static GSList  *kmail_read_folder (const gchar *path, GSList *list);
44 
45 const CamelStore *
evolution_get_local_store(void)46 evolution_get_local_store (void)
47 {
48 	EShell *shell;
49 	EShellBackend *shell_backend;
50 	EMailBackend *backend;
51 	EMailSession *session;
52 	static CamelStore *local_store = NULL;
53 
54 	if (local_store)
55 		return local_store;
56 	/* XXX Dig up the mail backend from the default EShell.
57 	 *     Since the EImport framework doesn't allow for user
58 	 *     data, I don't see how else to get to it. */
59 	shell = e_shell_get_default ();
60 	shell_backend = e_shell_get_backend_by_name (shell, "mail");
61 
62 	backend = E_MAIL_BACKEND (shell_backend);
63 	session = e_mail_backend_get_session (backend);
64 
65 	local_store = e_mail_session_get_local_store (session);
66 
67 	return local_store;
68 }
69 
70 static gboolean
is_kmail_box(const gchar * k_folder)71 is_kmail_box (const gchar *k_folder)
72 {
73 	const gchar *special_folders []= {"cur", "tmp", "new", NULL};
74 	gchar *source_dir;
75 	GDir *dir;
76 	gint i;
77 
78 	for (i = 0; special_folders[i]; i++) {
79 		source_dir = g_build_filename (k_folder, special_folders[i], NULL);
80 		dir = g_dir_open (source_dir, 0, NULL);
81 		if (!dir) {
82 			/* If we did not find the subdir with 'cur' 'tmp' and 'new',
83 			   we don't take it as the kmail box. */
84 			g_free (source_dir);
85 			return FALSE;
86 		}
87 		g_dir_close (dir);
88 		g_free (source_dir);
89 	}
90 
91 	/* No matter whether the folder was empty, we return it to the importer */
92 	return TRUE;
93 }
94 
95 static gboolean
is_kmail_directory(const gchar * folder)96 is_kmail_directory (const gchar *folder)
97 {
98 	if (g_str_has_prefix (folder, ".") && g_str_has_suffix (folder, ".directory"))
99 		return TRUE;
100 	else
101 		return FALSE;
102 }
103 
104 gchar *
kmail_get_base_dir(void)105 kmail_get_base_dir (void)
106 {
107 	gchar *base_dir;
108 
109 	base_dir = g_build_filename (g_get_home_dir (), KMAIL_4_3_DIR, NULL);
110 
111 	return base_dir;
112 }
113 
114 gchar *
kuri_to_euri(const gchar * k_uri)115 kuri_to_euri (const gchar *k_uri)
116 {
117 	gchar *base_dir;
118 	gchar *p;
119 	gchar **folders;
120 	GString *e_folder = NULL;
121 	gint i;
122 	gboolean dropped = FALSE;
123 
124 	e_folder = g_string_new (EVOLUTION_LOCAL_BASE);
125 	base_dir = g_build_filename (g_get_home_dir (), KMAIL_4_3_DIR, NULL);
126 	p = (gchar *) k_uri + strlen (base_dir) + 1;
127 	folders = g_strsplit (p, "/", -1);
128 
129 	for (i = 0; folders[i]; i++) {
130 		gchar *folder = folders[i];
131 		if (g_str_has_prefix (folder, ".") && g_str_has_suffix (folder, ".directory")) {
132 			folder ++;
133 			p = g_strrstr (folder, ".directory");
134 			*p = '\0';
135 		}
136 		if (i == 0) {
137 			/* Some local folders */
138 			if ((strcasecmp (folder, "Inbox") == 0) || (strcmp (folder, _("Inbox")) == 0)) {
139 				folder = (gchar *)"Inbox";
140 			} else if ((strcasecmp (folder, "Outbox") == 0) || (strcmp (folder, _("Outbox")) == 0)) {
141 				folder = (gchar *)"Outbox";
142 			} else if ((strcasecmp (folder, "sent-mail") == 0) || (strcmp (folder, _("Sent")) == 0)) {
143 				folder = (gchar *)"Sent";
144 			} else if ((strcasecmp (folder, "drafts") == 0) || (strcmp (folder, _("Drafts")) == 0)) {
145 				folder = (gchar *)"Drafts";
146 			} else if ((strcasecmp (folder, "templates") == 0) || (strcmp (folder, _("Templates")) == 0)) {
147 				folder = (gchar *)"Templates";
148 				break;
149 			} else if ((strcasecmp (folder, "trash") == 0) || (strcmp (folder, _("Trash")) == 0)) {
150 				dropped = TRUE;
151 				break;
152 			}
153 		}
154 		g_string_append_printf (e_folder, "/%s", folder);
155 	}
156 
157 	g_strfreev (folders);
158 	return g_string_free (e_folder, dropped);
159 }
160 
161 static GSList *
kmail_read_folder(const gchar * path,GSList * kmail_list)162 kmail_read_folder (const gchar *path, GSList *kmail_list)
163 {
164 	GDir *dir;
165 	gchar *filename;
166 	const gchar *d;
167 	struct stat st;
168 
169 	dir = g_dir_open (path, 0, NULL);
170 
171 	while ((d = g_dir_read_name (dir))) {
172 		if ((strcmp (d, ".") == 0) || (strcmp (d, "..") == 0)) {
173 			continue;
174 		}
175 
176 		filename = g_build_filename (path, d, NULL);
177 		/* skip non files and directories, and skip directories in mozilla mode */
178 		if (g_stat (filename, &st) == -1) {
179 			g_free (filename);
180 			continue;
181 		}
182 		if (S_ISDIR (st.st_mode)) {
183 			if (is_kmail_directory (d)) {
184 				kmail_list = kmail_read_folder (filename, kmail_list);
185 			} else if (is_kmail_box (filename)) {
186 				kmail_list = g_slist_prepend (kmail_list, g_strdup (filename));
187 			}
188 		}
189 		g_free (filename);
190 	}
191 	g_dir_close (dir);
192 
193 	return kmail_list;
194 }
195 
196 GSList *
kmail_get_folders(gchar * path)197 kmail_get_folders (gchar *path)
198 {
199 	GSList *list = NULL;
200 
201 	list = kmail_read_folder (path, list);
202 
203 	return list;
204 }
205 
206 /* Copied from addressbook/util/eab-book-util.c:eab_contact_list_from_string */
207 static GSList *
get_contact_list_from_string(const gchar * str)208 get_contact_list_from_string (const gchar *str)
209 {
210 	GSList *contacts = NULL;
211 	GString *gstr = g_string_new (NULL);
212 	gchar *str_stripped;
213 	gchar *p = (gchar *) str;
214 	gchar *q;
215 	if (!p)
216 		return NULL;
217 
218 	if (!strncmp (p, "Book: ", 6)) {
219 		p = strchr (p, '\n');
220 		if (!p) {
221 			g_warning (G_STRLOC ": Got book but no newline!");
222 			return NULL;
223 		}
224 		p++;
225 	}
226 
227 	while (*p) {
228 		if (*p != '\r') g_string_append_c (gstr, *p);
229 
230 		p++;
231 	}
232 
233 	p = str_stripped = g_string_free (gstr, FALSE);
234 
235 	for (p = camel_strstrcase (p, "BEGIN:VCARD"); p; p = camel_strstrcase (q, "\nBEGIN:VCARD")) {
236 		gchar *card_str;
237 
238 		if (*p == '\n')
239 			p++;
240 
241 		for (q = camel_strstrcase (p, "END:VCARD"); q; q = camel_strstrcase (q, "END:VCARD")) {
242 			gchar *temp;
243 
244 			q += 9;
245 			temp = q;
246 			if (*temp)
247 				temp += strspn (temp, "\r\n\t ");
248 
249 			if (*temp == '\0' || !g_ascii_strncasecmp (temp, "BEGIN:VCARD", 11))
250 				break;  /* Found the outer END:VCARD */
251 		}
252 
253 		if (!q)
254 			break;
255 		card_str = g_strndup (p, q - p);
256 		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard (card_str));
257 		g_free (card_str);
258 	}
259 
260 	g_free (str_stripped);
261 
262 	return g_slist_reverse (contacts);
263 }
264 
265 static gchar *
get_kcontact_folder(void)266 get_kcontact_folder (void)
267 {
268 	gchar *folder;
269 
270 	folder = g_build_filename (g_get_home_dir (), KCONTACT_4_3_DIR, NULL);
271 
272 	return folder;
273 }
274 
275 GSList *
kcontact_get_list(void)276 kcontact_get_list (void)
277 {
278 	GSList *list = NULL;
279 	gchar *foldername = NULL;
280 	gchar *filename;
281 	const gchar *d;
282 	GDir *dir;
283 	struct stat st;
284 
285 	foldername = get_kcontact_folder ();
286 	if (!foldername)
287 		return NULL;
288 	dir = g_dir_open (foldername, 0, NULL);
289 
290 	while ((d = g_dir_read_name (dir))) {
291 		if ((strcmp (d, ".") == 0) || (strcmp (d, "..") == 0)) {
292 			continue;
293 		}
294 		if (!g_str_has_suffix (d, ".vcf")) {
295 			continue;
296 		}
297 		filename = g_build_filename (foldername, d, NULL);
298 		if (g_stat (filename, &st) == -1) {
299 			g_free (filename);
300 			continue;
301 		}
302 		if (S_ISREG (st.st_mode)) {
303 			list = g_slist_prepend (list, filename);
304 		}
305 	}
306 
307 	g_free (foldername);
308 	g_dir_close (dir);
309 
310 	return list;
311 }
312 
313 void
kcontact_load(GSList * files)314 kcontact_load (GSList *files)
315 {
316 	GSList *contactlist = NULL;
317 	GSList *l;
318 
319 	GError *error = NULL;
320 	GString *vcards = NULL;
321 	EBookClient *book_client;
322 	EClient *client;
323 	EShell *shell;
324 	ESourceRegistry *registry;
325 	EClientCache *client_cache;
326 	ESource *primary;
327 
328 	if (!files)
329 		return;
330 
331 	shell = e_shell_get_default ();
332 	registry = e_shell_get_registry (shell);
333 
334 	primary = e_source_registry_ref_default_address_book (registry);
335 	if (!primary) {
336 		printf ("%s: No default address book found\n", G_STRFUNC);
337 		return;
338 	}
339 
340 	client_cache = e_shell_get_client_cache (shell);
341 	client = e_client_cache_get_client_sync (client_cache, primary, E_SOURCE_EXTENSION_ADDRESS_BOOK, 15, NULL, &error);
342 
343 	if (!client) {
344 		printf ("%s: Failed to open address book '%s': %s\n", G_STRFUNC, e_source_get_display_name (primary), error ? error->message : "Unknown error");
345 		g_clear_object (&primary);
346 		g_clear_error (&error);
347 		return;
348 	}
349 	g_clear_object (&primary);
350 
351 	book_client = E_BOOK_CLIENT (client);
352 
353 	for (l = files; l; l = l->next) {
354 		const gchar *filename;
355 		gchar *contents = NULL;
356 
357 		filename = (gchar *) l->data;
358 		if (g_file_get_contents (filename, &contents, NULL, NULL)) {
359 			if (vcards == NULL) {
360 				vcards = g_string_new (contents);
361 			} else {
362 				g_string_append_c (vcards, '\n');
363 				g_string_append (vcards, contents);
364 			}
365 			g_free (contents);
366 		}
367 	}
368 
369 	if (vcards) {
370 		contactlist = get_contact_list_from_string (vcards->str);
371 	}
372 
373 	if (contactlist) {
374 		e_book_client_add_contacts_sync (book_client, contactlist, E_BOOK_OPERATION_FLAG_NONE, NULL, NULL, &error);
375 
376 		if (error) {
377 			printf ("%s: Failed to add contacts: %s\n", G_STRFUNC, error->message);
378 			g_error_free (error);
379 		}
380 	}
381 
382 	if (vcards)
383 		g_string_free (vcards, TRUE);
384 	if (contactlist)
385 		g_slist_free_full (contactlist, g_object_unref);
386 	g_object_unref (book_client);
387 }
388 
389 gboolean
kmail_is_supported(void)390 kmail_is_supported (void)
391 {
392 	gchar *kmaildir;
393 	gboolean exists;
394 
395 	kmaildir = g_build_filename (g_get_home_dir (), KMAIL_4_3_DIR, NULL);
396 	exists = g_file_test (kmaildir, G_FILE_TEST_IS_DIR);
397 	g_free (kmaildir);
398 
399 	if (!exists)
400 		return FALSE;
401 
402 	return TRUE;
403 }
404