summaryrefslogtreecommitdiff
path: root/src/export.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/export.c')
-rw-r--r--src/export.c551
1 files changed, 551 insertions, 0 deletions
diff --git a/src/export.c b/src/export.c
new file mode 100644
index 0000000..85a27e9
--- /dev/null
+++ b/src/export.c
@@ -0,0 +1,551 @@
1/*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2014 Hiroyuki Yamamoto
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21# include "config.h"
22#endif
23
24#include "defs.h"
25
26#include <glib.h>
27#include <glib/gi18n.h>
28#include <gdk/gdkkeysyms.h>
29#include <gtk/gtkmain.h>
30#include <gtk/gtkwidget.h>
31#include <gtk/gtkwindow.h>
32#include <gtk/gtkvbox.h>
33#include <gtk/gtktable.h>
34#include <gtk/gtkmenu.h>
35#include <gtk/gtkmenuitem.h>
36#include <gtk/gtkoptionmenu.h>
37#include <gtk/gtklabel.h>
38#include <gtk/gtkentry.h>
39#include <gtk/gtkhbbox.h>
40#include <gtk/gtkbutton.h>
41#include <gtk/gtkcheckbutton.h>
42#include <gtk/gtkprogressbar.h>
43
44#include "main.h"
45#include "inc.h"
46#include "mbox.h"
47#include "folder.h"
48#include "procmsg.h"
49#include "menu.h"
50#include "filesel.h"
51#include "foldersel.h"
52#include "gtkutils.h"
53#include "manage_window.h"
54#include "folder.h"
55#include "utils.h"
56#include "progressdialog.h"
57#include "alertpanel.h"
58#include "mainwindow.h"
59#include "summaryview.h"
60#include "prefs_ui.h"
61
62enum
63{
64 EXPORT_MBOX,
65 EXPORT_EML,
66 EXPORT_MH
67};
68
69static GtkWidget *window;
70static GtkWidget *format_optmenu;
71static GtkWidget *desc_label;
72static GtkWidget *file_label;
73static GtkWidget *src_entry;
74static GtkWidget *file_entry;
75static GtkWidget *src_button;
76static GtkWidget *file_button;
77static GtkWidget *selected_only_chkbtn;
78static GtkWidget *ok_button;
79static GtkWidget *cancel_button;
80static gboolean export_finished;
81static gboolean export_ack;
82static ProgressDialog *progress;
83
84static gboolean progress_cancel = FALSE;
85
86static void export_create (void);
87static gint export_do (void);
88static gint export_eml (FolderItem *src,
89 GSList *sel_mlist,
90 const gchar *path,
91 gint type);
92
93static void export_format_menu_cb (GtkWidget *widget,
94 gpointer data);
95
96static void export_ok_cb (GtkWidget *widget,
97 gpointer data);
98static void export_cancel_cb (GtkWidget *widget,
99 gpointer data);
100static void export_srcsel_cb (GtkWidget *widget,
101 gpointer data);
102static void export_filesel_cb (GtkWidget *widget,
103 gpointer data);
104static gint delete_event (GtkWidget *widget,
105 GdkEventAny *event,
106 gpointer data);
107static gboolean key_pressed (GtkWidget *widget,
108 GdkEventKey *event,
109 gpointer data);
110
111static void export_progress_cancel_cb (GtkWidget *widget,
112 gpointer data);
113
114
115static gboolean export_mbox_func(Folder *folder, FolderItem *item, guint count, guint total, gpointer data)
116{
117 gchar str[64];
118 static GTimeVal tv_prev = {0, 0};
119 GTimeVal tv_cur;
120
121 g_get_current_time(&tv_cur);
122 g_snprintf(str, sizeof(str), "%u / %d", count, total);
123 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress->progressbar), str);
124
125 if (tv_prev.tv_sec == 0 ||
126 (tv_cur.tv_sec - tv_prev.tv_sec) * G_USEC_PER_SEC +
127 tv_cur.tv_usec - tv_prev.tv_usec > 100 * 1000) {
128 if (item->total > 0)
129 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress->progressbar), (gdouble)count / item->total);
130 else
131 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(progress->progressbar));
132 ui_update();
133 tv_prev = tv_cur;
134 }
135
136 if (progress_cancel)
137 return FALSE;
138 else
139 return TRUE;
140}
141
142gint export_mail(FolderItem *default_src)
143{
144 gint ok = 0;
145 gchar *src_id = NULL;
146
147 export_create();
148
149 change_dir(get_startup_dir());
150
151 if (default_src && default_src->path)
152 src_id = folder_item_get_identifier(default_src);
153
154 if (src_id) {
155 gtk_entry_set_text(GTK_ENTRY(src_entry), src_id);
156 g_free(src_id);
157 }
158 gtk_widget_grab_focus(file_entry);
159
160 manage_window_set_transient(GTK_WINDOW(window));
161
162 export_finished = FALSE;
163 export_ack = FALSE;
164
165 inc_lock();
166
167 while (!export_finished)
168 gtk_main_iteration();
169
170 if (export_ack)
171 ok = export_do();
172
173 gtk_widget_destroy(window);
174 window = NULL;
175 src_entry = file_entry = NULL;
176 src_button = file_button = ok_button = cancel_button = NULL;
177
178 inc_unlock();
179
180 return ok;
181}
182
183static gint export_do(void)
184{
185 gint ok = 0;
186 const gchar *srcdir, *utf8mbox;
187 FolderItem *src;
188 gchar *mbox;
189 gchar *msg;
190 gint type;
191 gboolean selected_only;
192 MainWindow *mainwin;
193 GSList *mlist = NULL;
194
195 type = menu_get_option_menu_active_index
196 (GTK_OPTION_MENU(format_optmenu));
197
198 srcdir = gtk_entry_get_text(GTK_ENTRY(src_entry));
199 utf8mbox = gtk_entry_get_text(GTK_ENTRY(file_entry));
200
201 if (!utf8mbox || !*utf8mbox)
202 return -1;
203
204 mbox = g_filename_from_utf8(utf8mbox, -1, NULL, NULL, NULL);
205 if (!mbox) {
206 g_warning("failed to convert character set.");
207 mbox = g_strdup(utf8mbox);
208 }
209
210 selected_only = gtk_toggle_button_get_active
211 (GTK_TOGGLE_BUTTON(selected_only_chkbtn));
212
213 if (selected_only) {
214 mainwin = main_window_get();
215 src = mainwin->summaryview->folder_item;
216 mlist = summary_get_selected_msg_list(mainwin->summaryview);
217 } else
218 src = folder_find_item_from_identifier(srcdir);
219
220 if (!src) {
221 g_warning("Can't find the folder.");
222 g_free(mbox);
223 return -1;
224 }
225
226 msg = g_strdup_printf(_("Exporting %s ..."), src->name);
227 progress = progress_dialog_simple_create();
228 gtk_window_set_title(GTK_WINDOW(progress->window), _("Exporting"));
229 progress_dialog_set_label(progress, msg);
230 g_free(msg);
231 gtk_window_set_modal(GTK_WINDOW(progress->window), TRUE);
232 manage_window_set_transient(GTK_WINDOW(progress->window));
233 g_signal_connect(G_OBJECT(progress->cancel_btn), "clicked",
234 G_CALLBACK(export_progress_cancel_cb), NULL);
235 g_signal_connect(G_OBJECT(progress->window), "delete_event",
236 G_CALLBACK(gtk_true), NULL);
237 gtk_widget_show(progress->window);
238 ui_update();
239
240 progress_cancel = FALSE;
241
242 if (type == EXPORT_MBOX) {
243 folder_set_ui_func2(src->folder, export_mbox_func, NULL);
244 if (mlist)
245 ok = export_msgs_to_mbox(src, mlist, mbox);
246 else
247 ok = export_to_mbox(src, mbox);
248 folder_set_ui_func2(src->folder, NULL, NULL);
249 } else if (type == EXPORT_EML || type == EXPORT_MH) {
250 ok = export_eml(src, mlist, mbox, type);
251 }
252
253 progress_dialog_destroy(progress);
254 progress = NULL;
255
256 if (mlist)
257 g_slist_free(mlist);
258 g_free(mbox);
259
260 if (ok == -1)
261 alertpanel_error(_("Error occurred on export."));
262
263 return ok;
264}
265
266static gint export_eml(FolderItem *src, GSList *sel_mlist, const gchar *path,
267 gint type)
268{
269 const gchar *ext = "";
270 GSList *mlist, *cur;
271 MsgInfo *msginfo;
272 gchar *file, *dest;
273 guint count = 0;
274 guint total;
275 gint ok = 0;
276
277 g_return_val_if_fail(src != NULL, -1);
278 g_return_val_if_fail(path != NULL, -1);
279
280 if (type == EXPORT_EML)
281 ext = ".eml";
282
283 if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
284 if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
285 make_dir_hier(path);
286 if (!g_file_test(path, G_FILE_TEST_IS_DIR))
287 return -1;
288 } else {
289 g_warning("export_eml(): directory %s already exists.",
290 path);
291 return -1;
292 }
293 }
294
295 if (sel_mlist)
296 mlist = sel_mlist;
297 else {
298 mlist = folder_item_get_msg_list(src, TRUE);
299 if (!mlist)
300 return 0;
301 }
302 total = g_slist_length(mlist);
303
304 for (cur = mlist; cur != NULL; cur = cur->next) {
305 msginfo = (MsgInfo *)cur->data;
306
307 count++;
308 if (export_mbox_func(src->folder, src, count, total, NULL) == FALSE) {
309 ok = -2;
310 break;
311 }
312
313 file = folder_item_fetch_msg(src, msginfo->msgnum);
314 if (!file) {
315 ok = -1;
316 break;
317 }
318 dest = g_strdup_printf("%s%c%u%s", path, G_DIR_SEPARATOR,
319 count, ext);
320 if (g_file_test(dest, G_FILE_TEST_EXISTS)) {
321 g_warning("export_eml(): %s already exists.", dest);
322 g_free(dest);
323 g_free(file);
324 ok = -1;
325 break;
326 }
327 if (copy_file(file, dest, FALSE) < 0) {
328 g_free(dest);
329 g_free(file);
330 ok = -1;
331 break;
332 }
333 g_free(dest);
334 g_free(file);
335 }
336
337 if (!sel_mlist)
338 procmsg_msg_list_free(mlist);
339
340 return ok;
341}
342
343static void export_create(void)
344{
345 GtkWidget *vbox;
346 GtkWidget *hbox;
347 GtkWidget *table;
348 GtkWidget *menu;
349 GtkWidget *menuitem;
350 GtkWidget *format_label;
351 GtkWidget *src_label;
352 GtkWidget *confirm_area;
353
354 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
355 gtk_window_set_title(GTK_WINDOW(window), _("Export"));
356 gtk_container_set_border_width(GTK_CONTAINER(window), 5);
357 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
358 gtk_window_set_modal(GTK_WINDOW(window), TRUE);
359 gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, FALSE);
360 g_signal_connect(G_OBJECT(window), "delete_event",
361 G_CALLBACK(delete_event), NULL);
362 g_signal_connect(G_OBJECT(window), "key_press_event",
363 G_CALLBACK(key_pressed), NULL);
364 MANAGE_WINDOW_SIGNALS_CONNECT(window);
365
366 vbox = gtk_vbox_new(FALSE, 4);
367 gtk_container_add(GTK_CONTAINER(window), vbox);
368
369 hbox = gtk_hbox_new(FALSE, 0);
370 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
371 gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
372
373 desc_label = gtk_label_new
374 (_("Specify source folder and destination file."));
375 gtk_box_pack_start(GTK_BOX(hbox), desc_label, FALSE, FALSE, 0);
376
377 table = gtk_table_new(2, 3, FALSE);
378 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
379 gtk_container_set_border_width(GTK_CONTAINER(table), 8);
380 gtk_table_set_row_spacings(GTK_TABLE(table), 8);
381 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
382 gtk_widget_set_size_request(table, 420 * gtkut_get_dpi_multiplier(), -1);
383
384 format_label = gtk_label_new(_("File format:"));
385 gtk_table_attach(GTK_TABLE(table), format_label, 0, 1, 0, 1,
386 GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
387 gtk_misc_set_alignment(GTK_MISC(format_label), 1, 0.5);
388
389 src_label = gtk_label_new(_("Source folder:"));
390 gtk_table_attach(GTK_TABLE(table), src_label, 0, 1, 1, 2,
391 GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
392 gtk_misc_set_alignment(GTK_MISC(src_label), 1, 0.5);
393
394 file_label = gtk_label_new(_("Destination:"));
395 gtk_table_attach(GTK_TABLE(table), file_label, 0, 1, 2, 3,
396 GTK_FILL, GTK_EXPAND|GTK_FILL, 0, 0);
397 gtk_misc_set_alignment(GTK_MISC(file_label), 1, 0.5);
398
399 format_optmenu = gtk_option_menu_new();
400 gtk_table_attach(GTK_TABLE(table), format_optmenu, 1, 2, 0, 1,
401 GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
402
403 menu = gtk_menu_new();
404 MENUITEM_ADD(menu, menuitem, _("UNIX mbox"), EXPORT_MBOX);
405 g_signal_connect(G_OBJECT(menuitem), "activate",
406 G_CALLBACK(export_format_menu_cb), NULL);
407 MENUITEM_ADD(menu, menuitem, _("eml (number + .eml)"), EXPORT_EML);
408 g_signal_connect(G_OBJECT(menuitem), "activate",
409 G_CALLBACK(export_format_menu_cb), NULL);
410 MENUITEM_ADD(menu, menuitem, _("MH (number only)"), EXPORT_MH);
411 g_signal_connect(G_OBJECT(menuitem), "activate",
412 G_CALLBACK(export_format_menu_cb), NULL);
413
414 gtk_option_menu_set_menu(GTK_OPTION_MENU(format_optmenu), menu);
415
416 src_entry = gtk_entry_new();
417 gtk_table_attach(GTK_TABLE(table), src_entry, 1, 2, 1, 2,
418 GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
419
420 file_entry = gtk_entry_new();
421 gtk_table_attach(GTK_TABLE(table), file_entry, 1, 2, 2, 3,
422 GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0, 0);
423
424 src_button = gtk_button_new_with_label(_(" Select... "));
425 gtk_table_attach(GTK_TABLE(table), src_button, 2, 3, 1, 2,
426 0, 0, 0, 0);
427 g_signal_connect(G_OBJECT(src_button), "clicked",
428 G_CALLBACK(export_srcsel_cb), NULL);
429
430 file_button = gtk_button_new_with_label(_(" Select... "));
431 gtk_table_attach(GTK_TABLE(table), file_button, 2, 3, 2, 3,
432 0, 0, 0, 0);
433 g_signal_connect(G_OBJECT(file_button), "clicked",
434 G_CALLBACK(export_filesel_cb), NULL);
435
436 hbox = gtk_hbox_new(FALSE, 0);
437 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
438 gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);
439
440 selected_only_chkbtn = gtk_check_button_new_with_label
441 (_("Export only selected messages"));
442 gtk_box_pack_start(GTK_BOX(hbox), selected_only_chkbtn,
443 FALSE, FALSE, 0);
444
445 SET_TOGGLE_SENSITIVITY_REV(selected_only_chkbtn, src_entry);
446 SET_TOGGLE_SENSITIVITY_REV(selected_only_chkbtn, src_button);
447
448 gtkut_stock_button_set_create(&confirm_area,
449 &ok_button, GTK_STOCK_OK,
450 &cancel_button, GTK_STOCK_CANCEL,
451 NULL, NULL);
452 gtk_box_pack_end(GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
453 gtk_widget_grab_default(ok_button);
454
455 g_signal_connect(G_OBJECT(ok_button), "clicked",
456 G_CALLBACK(export_ok_cb), NULL);
457 g_signal_connect(G_OBJECT(cancel_button), "clicked",
458 G_CALLBACK(export_cancel_cb), NULL);
459
460 gtk_widget_show_all(window);
461}
462
463static void export_format_menu_cb(GtkWidget *widget, gpointer data)
464{
465 gint type;
466
467 type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget),
468 MENU_VAL_ID));
469 if (type == EXPORT_MBOX) {
470 gtk_label_set_text(GTK_LABEL(desc_label),
471 _("Specify source folder and destination file."));
472 } else {
473 gtk_label_set_text(GTK_LABEL(desc_label),
474 _("Specify source folder and destination folder."));
475 }
476}
477
478static void export_ok_cb(GtkWidget *widget, gpointer data)
479{
480 export_finished = TRUE;
481 export_ack = TRUE;
482}
483
484static void export_cancel_cb(GtkWidget *widget, gpointer data)
485{
486 export_finished = TRUE;
487 export_ack = FALSE;
488}
489
490static void export_filesel_cb(GtkWidget *widget, gpointer data)
491{
492 gchar *filename;
493 gchar *utf8_filename;
494 gint type;
495
496 type = menu_get_option_menu_active_index
497 (GTK_OPTION_MENU(format_optmenu));
498
499 if (type == EXPORT_MBOX)
500 filename = filesel_select_file(_("Select destination file"),
501 NULL,
502 GTK_FILE_CHOOSER_ACTION_SAVE);
503 else
504 filename = filesel_select_file(_("Select destination folder"),
505 NULL,
506 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
507 if (!filename) return;
508
509 utf8_filename = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
510 if (!utf8_filename) {
511 g_warning("export_filesel_cb(): failed to convert character set.");
512 utf8_filename = g_strdup(filename);
513 }
514 gtk_entry_set_text(GTK_ENTRY(file_entry), utf8_filename);
515 g_free(utf8_filename);
516
517 g_free(filename);
518}
519
520static void export_srcsel_cb(GtkWidget *widget, gpointer data)
521{
522 FolderItem *src;
523 gchar *src_id;
524
525 src = foldersel_folder_sel(NULL, FOLDER_SEL_ALL, NULL);
526 if (src && src->path) {
527 src_id = folder_item_get_identifier(src);
528 if (src_id) {
529 gtk_entry_set_text(GTK_ENTRY(src_entry), src_id);
530 g_free(src_id);
531 }
532 }
533}
534
535static gint delete_event(GtkWidget *widget, GdkEventAny *event, gpointer data)
536{
537 export_cancel_cb(NULL, NULL);
538 return TRUE;
539}
540
541static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
542{
543 if (event && event->keyval == GDK_Escape)
544 export_cancel_cb(NULL, NULL);
545 return FALSE;
546}
547
548static void export_progress_cancel_cb(GtkWidget *widget, gpointer data)
549{
550 progress_cancel = TRUE;
551}