summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c2083
1 files changed, 2083 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..77d8192
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,2083 @@
1/*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2016 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 <gtk/gtkmain.h>
29#include <gtk/gtkrc.h>
30#include <gtk/gtkstock.h>
31#include <gtk/gtkaccelmap.h>
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <ctype.h>
37#include <unistd.h>
38#include <time.h>
39#include <sys/stat.h>
40#include <sys/types.h>
41#ifdef G_OS_UNIX
42# include <signal.h>
43#endif
44
45#if HAVE_LOCALE_H
46# include <locale.h>
47#endif
48
49#if USE_GPGME
50# include <gpgme.h>
51#endif
52
53#include "main.h"
54#include "mainwindow.h"
55#include "folderview.h"
56#include "summaryview.h"
57#include "prefs_common.h"
58#include "prefs_account.h"
59#include "prefs_actions.h"
60#include "prefs_display_header.h"
61#include "account.h"
62#include "account_dialog.h"
63#include "procmsg.h"
64#include "procheader.h"
65#include "filter.h"
66#include "send_message.h"
67#include "inc.h"
68#include "manage_window.h"
69#include "alertpanel.h"
70#include "inputdialog.h"
71#include "statusbar.h"
72#include "addressbook.h"
73#include "addrindex.h"
74#include "compose.h"
75#include "logwindow.h"
76#include "folder.h"
77#include "setup.h"
78#include "sylmain.h"
79#include "utils.h"
80#include "gtkutils.h"
81#include "socket.h"
82#include "stock_pixmap.h"
83#include "trayicon.h"
84#include "notificationwindow.h"
85#include "plugin.h"
86#include "plugin_manager.h"
87#include "foldersel.h"
88#include "update_check.h"
89#include "colorlabel.h"
90
91#if USE_GPGME
92# include "rfc2015.h"
93#endif
94#if USE_SSL
95# include "ssl.h"
96# include "sslmanager.h"
97#endif
98
99#ifdef G_OS_WIN32
100# include <windows.h>
101# include <pbt.h>
102# include <fcntl.h>
103# include <conio.h>
104#endif
105
106#include "version.h"
107
108gchar *prog_version;
109
110#ifdef G_OS_WIN32
111static gboolean init_console_done = FALSE;
112#endif
113
114static gint lock_socket = -1;
115static gint lock_socket_tag = 0;
116static GIOChannel *lock_ch = NULL;
117static gchar *instance_id = NULL;
118
119#if USE_THREADS
120static GThread *main_thread;
121#endif
122
123static struct RemoteCmd {
124 gboolean receive;
125 gboolean receive_all;
126 gboolean compose;
127 const gchar *compose_mailto;
128 GPtrArray *attach_files;
129 gboolean send;
130 gboolean status;
131 gboolean status_full;
132 GPtrArray *status_folders;
133 GPtrArray *status_full_folders;
134 gchar *open_msg;
135 gboolean configdir;
136 gboolean safe_mode;
137 gboolean exit;
138 gboolean restart;
139 gchar *argv0;
140#ifdef G_OS_WIN32
141 gushort ipcport;
142#endif
143} cmd;
144
145#define STATUSBAR_PUSH(mainwin, str) \
146{ \
147 gtk_statusbar_push(GTK_STATUSBAR(mainwin->statusbar), \
148 mainwin->mainwin_cid, str); \
149 gtkut_widget_draw_now(mainwin->statusbar); \
150}
151
152#define STATUSBAR_POP(mainwin) \
153{ \
154 gtk_statusbar_pop(GTK_STATUSBAR(mainwin->statusbar), \
155 mainwin->mainwin_cid); \
156}
157
158#if defined(G_OS_WIN32) || defined(__APPLE__)
159static void fix_font_setting (void);
160#endif
161
162static void parse_cmd_opt (int argc,
163 char *argv[]);
164
165static void app_init (void);
166static void parse_gtkrc_files (void);
167static void setup_rc_dir (void);
168static void check_gpg (void);
169static void set_log_handlers (gboolean enable);
170static void register_system_events (void);
171static void plugin_init (void);
172
173static gchar *get_socket_name (void);
174static gint prohibit_duplicate_launch (void);
175static gint lock_socket_remove (void);
176static gboolean lock_socket_input_cb (GIOChannel *source,
177 GIOCondition condition,
178 gpointer data);
179
180static void remote_command_exec (void);
181
182#if !defined(G_OS_WIN32) && !defined(__APPLE__)
183static void migrate_old_config (void);
184#endif
185
186static void open_compose_new (const gchar *address,
187 GPtrArray *attach_files);
188static void open_message (const gchar *path);
189
190static void send_queue (void);
191
192#define MAKE_DIR_IF_NOT_EXIST(dir) \
193{ \
194 if (!is_dir_exist(dir)) { \
195 if (is_file_exist(dir)) { \
196 alertpanel_warning \
197 (_("File `%s' already exists.\n" \
198 "Can't create folder."), \
199 dir); \
200 exit(1); \
201 } \
202 if (make_dir(dir) < 0) \
203 exit(1); \
204 } \
205}
206
207#define CHDIR_EXIT_IF_FAIL(dir, val) \
208{ \
209 if (change_dir(dir) < 0) \
210 exit(val); \
211}
212
213static void load_cb(GObject *obj, GModule *module, gpointer data)
214{
215 debug_print("load_cb: %p (%s), %p\n", module, module ? g_module_name(module) : "(null)", data);
216}
217
218int main(int argc, char *argv[])
219{
220 MainWindow *mainwin;
221 FolderView *folderview;
222 GdkPixbuf *icon;
223#ifdef G_OS_WIN32
224 GList *iconlist = NULL;
225#endif
226 GObject *syl_app;
227 PrefsAccount *new_account = NULL;
228 gboolean first_run = FALSE;
229 gchar *path;
230
231 app_init();
232 parse_cmd_opt(argc, argv);
233
234 /* check and create (unix domain) socket for remote operation */
235 lock_socket = prohibit_duplicate_launch();
236 if (lock_socket < 0) return 0;
237
238 if (cmd.status || cmd.status_full) {
239 puts("0 Sylpheed not running.");
240 lock_socket_remove();
241 return 0;
242 }
243
244#if USE_THREADS
245 gdk_threads_enter();
246#endif
247 gtk_set_locale();
248 gtk_init(&argc, &argv);
249
250 syl_app = syl_app_create();
251
252 gdk_rgb_init();
253 gtk_widget_set_default_colormap(gdk_rgb_get_cmap());
254 gtk_widget_set_default_visual(gdk_rgb_get_visual());
255
256 parse_gtkrc_files();
257 setup_rc_dir();
258
259 if (is_file_exist("sylpheed.log")) {
260 if (rename_force("sylpheed.log", "sylpheed.log.bak") < 0)
261 FILE_OP_ERROR("sylpheed.log", "rename");
262 }
263 set_log_file("sylpheed.log");
264
265 set_ui_update_func(gtkut_events_flush);
266 set_progress_func(main_window_progress_show);
267 set_input_query_password_func(input_dialog_query_password);
268#if USE_SSL
269 ssl_init();
270 ssl_set_verify_func(ssl_manager_verify_cert);
271#endif
272
273 CHDIR_EXIT_IF_FAIL(get_home_dir(), 1);
274
275 prefs_common_read_config();
276 filter_set_addressbook_func(addressbook_has_address);
277 filter_read_config();
278 prefs_actions_read_config();
279 prefs_display_header_read_config();
280 colorlabel_read_config();
281
282 prefs_common.user_agent_str = g_strdup_printf
283 ("%s (GTK+ %d.%d.%d; %s)",
284 prog_version,
285 gtk_major_version, gtk_minor_version, gtk_micro_version,
286 TARGET_ALIAS);
287
288#if defined(G_OS_WIN32) || defined(__APPLE__)
289 fix_font_setting();
290#endif
291
292 gtkut_stock_button_set_set_reverse(!prefs_common.comply_gnome_hig);
293
294 check_gpg();
295
296 sock_set_io_timeout(prefs_common.io_timeout_secs);
297
298 gtkut_widget_init();
299
300 gtkut_get_dpi();
301
302 path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, "icons", NULL);
303 if (is_dir_exist(path)) {
304 debug_print("icon theme dir: %s\n", path);
305 stock_pixbuf_set_theme_dir(path);
306 } else {
307 g_free(path);
308 if (g_path_is_absolute(THEMEDIR))
309 path = g_strconcat(THEMEDIR, NULL);
310 else
311 path = g_strconcat(get_startup_dir(), G_DIR_SEPARATOR_S, THEMEDIR, NULL);
312 if (is_dir_exist(path)) {
313 debug_print("icon theme dir: %s\n", path);
314 stock_pixbuf_set_theme_dir(path);
315 }
316 }
317 g_free(path);
318
319#ifdef G_OS_WIN32
320 stock_pixbuf_gdk(NULL, STOCK_PIXMAP_SYLPHEED_32, &icon);
321 iconlist = g_list_append(iconlist, icon);
322 stock_pixbuf_gdk(NULL, STOCK_PIXMAP_SYLPHEED_SMALL, &icon);
323 iconlist = g_list_append(iconlist, icon);
324 gtk_window_set_default_icon_list(iconlist);
325 g_list_free(iconlist);
326#else
327 stock_pixbuf_gdk(NULL, STOCK_PIXMAP_SYLPHEED, &icon);
328 gtk_window_set_default_icon(icon);
329#endif
330
331 mainwin = main_window_create
332 (prefs_common.sep_folder | prefs_common.sep_msg << 1);
333 folderview = mainwin->folderview;
334
335 /* register the callback of socket input */
336 if (lock_socket > 0) {
337 lock_ch = g_io_channel_unix_new(lock_socket);
338 lock_socket_tag = g_io_add_watch(lock_ch,
339 G_IO_IN|G_IO_PRI|G_IO_ERR,
340 lock_socket_input_cb, mainwin);
341 }
342
343 set_log_handlers(TRUE);
344
345 account_read_config_all();
346 account_set_menu();
347 main_window_reflect_prefs_all();
348
349 if (folder_read_list() < 0) {
350 first_run = TRUE;
351 setup_mailbox();
352 folder_write_list();
353 }
354 if (!account_get_list()) {
355 new_account = setup_account();
356 }
357
358 account_set_menu();
359 main_window_reflect_prefs_all();
360
361 account_set_missing_folder();
362 folder_set_missing_folders();
363 folderview_set(folderview);
364 if (new_account && new_account->folder)
365 folder_write_list();
366
367 addressbook_read_file();
368
369 register_system_events();
370
371 inc_autocheck_timer_init(mainwin);
372
373 plugin_init();
374
375 g_signal_emit_by_name(syl_app, "init-done");
376
377 if (first_run) {
378 setup_import_data();
379 setup_import_addressbook();
380 }
381
382 remote_command_exec();
383
384#if USE_UPDATE_CHECK
385 if (prefs_common.auto_update_check)
386 update_check(FALSE);
387#endif
388
389 gtk_main();
390#if USE_THREADS
391 gdk_threads_leave();
392#endif
393
394 return 0;
395}
396
397static void init_console(void)
398{
399#ifdef G_OS_WIN32
400 gint fd;
401 FILE *fp;
402
403 if (init_console_done)
404 return;
405
406 if (!AllocConsole()) {
407 g_warning("AllocConsole() failed\n");
408 return;
409 }
410
411 fd = _open_osfhandle((glong)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
412 _dup2(fd, 1);
413 fp = _fdopen(fd, "w");
414 *stdout = *fp;
415 setvbuf(stdout, NULL, _IONBF, 0);
416 fd = _open_osfhandle((glong)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT);
417 _dup2(fd, 2);
418 fp = _fdopen(fd, "w");
419 *stderr = *fp;
420 setvbuf(stderr, NULL, _IONBF, 0);
421
422 init_console_done = TRUE;
423#endif
424}
425
426static void cleanup_console(void)
427{
428#ifdef G_OS_WIN32
429 FreeConsole();
430#endif
431}
432
433#ifdef G_OS_WIN32
434static void read_ini_file(void)
435{
436 static gushort ipcport = REMOTE_CMD_PORT;
437 static gchar *confdir = NULL;
438
439 static PrefParam param[] = {
440 {"ipcport", "50215", &ipcport, P_USHORT},
441 {"configdir", NULL, &confdir, P_STRING},
442
443 {NULL, NULL, NULL, P_OTHER}
444 };
445
446 gchar *file;
447
448 file = g_strconcat(get_startup_dir(), G_DIR_SEPARATOR_S, "sylpheed.ini",
449 NULL);
450 if (!is_file_exist(file)) {
451 g_free(file);
452 return;
453 }
454
455 prefs_read_config(param, "Sylpheed", file,
456 conv_get_locale_charset_str());
457 g_free(file);
458
459 cmd.ipcport = ipcport;
460 if (confdir) {
461 set_rc_dir(confdir);
462 g_free(confdir);
463 confdir = NULL;
464 cmd.configdir = TRUE;
465 }
466}
467#endif /* G_OS_WIN32 */
468
469#if defined(G_OS_WIN32) || defined(__APPLE__)
470static void fix_font_setting(void)
471{
472 gchar *str = NULL;
473 gchar **strv = NULL;
474 gchar *style = NULL;
475 gchar *size = NULL;
476 gchar *suffix = NULL;
477
478 if (!conv_is_ja_locale())
479 return;
480
481 if (prefs_common.textfont &&
482 strcmp(prefs_common.textfont, DEFAULT_MESSAGE_FONT) != 0) {
483 guint len;
484
485 if (gtkut_font_can_load(prefs_common.textfont)) {
486 debug_print("font '%s' load ok\n", prefs_common.textfont);
487 return;
488 }
489 debug_print("font '%s' load failed\n", prefs_common.textfont);
490 debug_print("fixing prefs_common.textfont setting\n");
491
492 strv = g_strsplit(prefs_common.textfont, " ", -1);
493 len = g_strv_length(strv);
494 if (len > 0) {
495 if (g_ascii_isdigit(strv[len - 1][0]))
496 size = g_strdup(strv[len - 1]);
497 if (len > 2) {
498 if (g_ascii_strcasecmp(strv[len - 2], "Bold") == 0)
499 style = g_strdup(strv[len - 2]);
500 }
501 }
502 g_strfreev(strv);
503 }
504
505 if (style && size)
506 suffix = g_strconcat(style, " ", size, NULL);
507 else if (size)
508 suffix = g_strdup(size);
509 else
510 suffix = g_strdup("12");
511 g_free(style);
512 g_free(size);
513#ifdef G_OS_WIN32
514 str = g_strconcat("MS Gothic ", suffix, NULL);
515#else /* __APPLE__ */
516 str = g_strconcat("Hiragino Kaku Gothic Pro ", suffix, NULL);
517#endif
518
519 if (!gtkut_font_can_load(str)) {
520#ifdef G_OS_WIN32
521 debug_print("font '%s' load failed\n", str);
522 g_free(str);
523 str = g_strconcat("\xef\xbc\xad\xef\xbc\xb3 \xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf ", suffix, NULL);
524 if (!gtkut_font_can_load(str)) {
525 debug_print("font '%s' load failed\n", str);
526 g_free(str);
527 str = NULL;
528 }
529#else /* __APPLE__ */
530 debug_print("font '%s' load failed\n", str);
531 g_free(str);
532 str = NULL;
533#endif
534 }
535
536 if (str) {
537 debug_print("font '%s' load ok\n", str);
538 g_free(prefs_common.textfont);
539 prefs_common.textfont = g_strdup(str);
540 g_free(str);
541 } else
542 g_warning("failed to load text font!");
543
544 g_free(suffix);
545}
546#endif
547
548static void parse_cmd_opt(int argc, char *argv[])
549{
550 gint i;
551
552 for (i = 1; i < argc; i++) {
553 if (!strncmp(argv[i], "--debug", 7)) {
554 init_console();
555 set_debug_mode(TRUE);
556 } else if (!strncmp(argv[i], "--receive-all", 13))
557 cmd.receive_all = TRUE;
558 else if (!strncmp(argv[i], "--receive", 9))
559 cmd.receive = TRUE;
560 else if (!strncmp(argv[i], "--compose", 9)) {
561 const gchar *p = argv[i + 1];
562
563 cmd.compose = TRUE;
564 cmd.compose_mailto = NULL;
565 if (p && *p != '\0' && *p != '-') {
566 if (!strncmp(p, "mailto:", 7))
567 cmd.compose_mailto = p + 7;
568 else
569 cmd.compose_mailto = p;
570 i++;
571 }
572 } else if (!strncmp(argv[i], "--attach", 8)) {
573 const gchar *p = argv[i + 1];
574 gchar *file;
575
576 while (p && *p != '\0' && *p != '-') {
577 if (!cmd.attach_files)
578 cmd.attach_files = g_ptr_array_new();
579 if (!g_path_is_absolute(p))
580 file = g_strconcat(get_startup_dir(),
581 G_DIR_SEPARATOR_S,
582 p, NULL);
583 else
584 file = g_strdup(p);
585 g_ptr_array_add(cmd.attach_files, file);
586 i++;
587 p = argv[i + 1];
588 }
589 } else if (!strncmp(argv[i], "--send", 6)) {
590 cmd.send = TRUE;
591 } else if (!strncmp(argv[i], "--version", 9)) {
592 puts("Sylpheed version " VERSION);
593 exit(0);
594 } else if (!strncmp(argv[i], "--status-full", 13)) {
595 const gchar *p = argv[i + 1];
596
597 cmd.status_full = TRUE;
598 while (p && *p != '\0' && *p != '-') {
599 if (!cmd.status_full_folders)
600 cmd.status_full_folders =
601 g_ptr_array_new();
602 g_ptr_array_add(cmd.status_full_folders,
603 g_strdup(p));
604 i++;
605 p = argv[i + 1];
606 }
607 } else if (!strncmp(argv[i], "--status", 8)) {
608 const gchar *p = argv[i + 1];
609
610 cmd.status = TRUE;
611 while (p && *p != '\0' && *p != '-') {
612 if (!cmd.status_folders)
613 cmd.status_folders = g_ptr_array_new();
614 g_ptr_array_add(cmd.status_folders,
615 g_strdup(p));
616 i++;
617 p = argv[i + 1];
618 }
619 } else if (!strncmp(argv[i], "--open", 6)) {
620 const gchar *p = argv[i + 1];
621
622 if (p && *p != '\0' && *p != '-') {
623 if (cmd.open_msg)
624 g_free(cmd.open_msg);
625 cmd.open_msg = g_locale_to_utf8
626 (p, -1, NULL, NULL, NULL);
627 i++;
628 }
629 } else if (!strncmp(argv[i], "--configdir", 11)) {
630 const gchar *p = argv[i + 1];
631
632 if (p && *p != '\0' && *p != '-') {
633 /* this must only be done at startup */
634#ifdef G_OS_WIN32
635 gchar *utf8dir;
636
637 utf8dir = g_locale_to_utf8
638 (p, -1, NULL, NULL, NULL);
639 if (utf8dir) {
640 set_rc_dir(utf8dir);
641 g_free(utf8dir);
642 } else
643 set_rc_dir(p);
644#else
645 set_rc_dir(p);
646#endif
647 cmd.configdir = TRUE;
648 i++;
649 }
650#ifdef G_OS_WIN32
651 } else if (!strncmp(argv[i], "--ipcport", 9)) {
652 if (argv[i + 1]) {
653 cmd.ipcport = atoi(argv[i + 1]);
654 i++;
655 }
656#endif
657 } else if (!strncmp(argv[i], "--instance-id", 13)) {
658 if (argv[i + 1]) {
659 instance_id = g_locale_to_utf8
660 (argv[i + 1], -1, NULL, NULL, NULL);
661 i++;
662 }
663 } else if (!strncmp(argv[i], "--safe-mode", 11)) {
664 cmd.safe_mode = TRUE;
665 } else if (!strncmp(argv[i], "--dpi", 5)) {
666 if (argv[i + 1]) {
667 gdouble dpi;
668
669 dpi = strtod(argv[i + 1], NULL);
670 if (dpi > 0.0)
671 gtkut_set_dpi(dpi);
672 i++;
673 }
674 } else if (!strncmp(argv[i], "--exit", 6)) {
675 cmd.exit = TRUE;
676 } else if (!strncmp(argv[i], "--help", 6)) {
677 init_console();
678
679 g_print(_("Usage: %s [OPTIONS ...] [URL]\n"),
680 g_basename(argv[0]));
681
682 g_print("%s\n", _(" --compose [mailto URL] open composition window"));
683 g_print("%s\n", _(" --attach file1 [file2]...\n"
684 " open composition window with specified files\n"
685 " attached"));
686 g_print("%s\n", _(" --receive receive new messages"));
687 g_print("%s\n", _(" --receive-all receive new messages of all accounts"));
688 g_print("%s\n", _(" --send send all queued messages"));
689 g_print("%s\n", _(" --status [folder]... show the total number of messages"));
690 g_print("%s\n", _(" --status-full [folder]...\n"
691 " show the status of each folder"));
692 g_print("%s\n", _(" --open folderid/msgnum open existing message in a new window"));
693 g_print("%s\n", _(" --open <file URL> open an rfc822 message file in a new window"));
694 g_print("%s\n", _(" --configdir dirname specify directory which stores configuration files"));
695#ifdef G_OS_WIN32
696 g_print("%s\n", _(" --ipcport portnum specify port for IPC remote commands"));
697#endif
698 g_print("%s\n", _(" --dpi dpinum force DPI"));
699 g_print("%s\n", _(" --exit exit Sylpheed"));
700 g_print("%s\n", _(" --debug debug mode"));
701 g_print("%s\n", _(" --safe-mode safe mode"));
702 g_print("%s\n", _(" --help display this help and exit"));
703 g_print("%s\n", _(" --version output version information and exit"));
704
705#ifdef G_OS_WIN32
706 g_print("\n");
707 g_print(_("Press any key..."));
708 _getch();
709#endif
710
711 cleanup_console();
712 exit(1);
713 } else {
714 /* file or URL */
715 const gchar *p = argv[i];
716
717 if (p && *p != '\0') {
718 if (!strncmp(p, "mailto:", 7)) {
719 cmd.compose = TRUE;
720 cmd.compose_mailto = p + 7;
721 } else {
722 if (cmd.open_msg)
723 g_free(cmd.open_msg);
724 cmd.open_msg = g_locale_to_utf8
725 (p, -1, NULL, NULL, NULL);
726 }
727 }
728 }
729 }
730
731 if (cmd.attach_files && cmd.compose == FALSE) {
732 cmd.compose = TRUE;
733 cmd.compose_mailto = NULL;
734 }
735
736 cmd.argv0 = g_locale_to_utf8(argv[0], -1, NULL, NULL, NULL);
737 if (!cmd.argv0)
738 cmd.argv0 = g_strdup(argv[0]);
739}
740
741static gint get_queued_message_num(void)
742{
743 FolderItem *queue;
744
745 queue = folder_get_default_queue();
746 if (!queue) return -1;
747
748 folder_item_scan(queue);
749 return queue->total;
750}
751
752#if USE_THREADS
753/* enables recursive locking with gdk_thread_enter / gdk_threads_leave */
754static GStaticRecMutex syl_mutex = G_STATIC_REC_MUTEX_INIT;
755
756static void thread_enter_func(void)
757{
758 g_static_rec_mutex_lock(&syl_mutex);
759#if 0
760 syl_mutex_lock_count++;
761 if (syl_mutex_lock_count > 1)
762 g_print("enter: syl_mutex_lock_count: %d\n", syl_mutex_lock_count);
763#endif
764}
765
766static void thread_leave_func(void)
767{
768#if 0
769 syl_mutex_lock_count--;
770 if (syl_mutex_lock_count > 0)
771 g_print("leave: syl_mutex_lock_count: %d\n", syl_mutex_lock_count);
772#endif
773 g_static_rec_mutex_unlock(&syl_mutex);
774}
775
776static void event_loop_iteration_func(void)
777{
778 if (g_thread_self() != main_thread) {
779 g_fprintf(stderr, "event_loop_iteration_func called from non-main thread (%p)\n", g_thread_self());
780 g_usleep(10000);
781 return;
782 }
783 gtk_main_iteration();
784}
785#endif
786
787static void app_init(void)
788{
789#if USE_THREADS
790 if (!g_thread_supported())
791 g_thread_init(NULL);
792 if (!g_thread_supported())
793 g_error("g_thread is not supported by glib.");
794 else {
795 gdk_threads_set_lock_functions(thread_enter_func,
796 thread_leave_func);
797 gdk_threads_init();
798 main_thread = g_thread_self();
799 }
800#endif
801 syl_init();
802
803#if USE_THREADS
804 set_event_loop_func(event_loop_iteration_func);
805#endif
806 prog_version = PROG_VERSION;
807
808#ifdef G_OS_WIN32
809 read_ini_file();
810#endif
811}
812
813static void parse_gtkrc_files(void)
814{
815 gchar *userrc;
816
817 /* parse gtkrc files */
818 userrc = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S, ".gtkrc-2.0",
819 NULL);
820 gtk_rc_parse(userrc);
821 g_free(userrc);
822 userrc = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S, ".gtk",
823 G_DIR_SEPARATOR_S, "gtkrc-2.0", NULL);
824 gtk_rc_parse(userrc);
825 g_free(userrc);
826 userrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, "gtkrc", NULL);
827 gtk_rc_parse(userrc);
828 g_free(userrc);
829
830 userrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MENU_RC, NULL);
831 gtk_accel_map_load(userrc);
832 g_free(userrc);
833}
834
835static void setup_rc_dir(void)
836{
837#if !defined(G_OS_WIN32) && !defined(__APPLE__)
838 CHDIR_EXIT_IF_FAIL(get_home_dir(), 1);
839
840 /* backup if old rc file exists */
841 if (!cmd.configdir && is_file_exist(RC_DIR)) {
842 if (rename_force(RC_DIR, RC_DIR ".bak") < 0)
843 FILE_OP_ERROR(RC_DIR, "rename");
844 }
845
846 /* migration from ~/.sylpheed to ~/.sylpheed-2.0 */
847 if (!cmd.configdir && !is_dir_exist(RC_DIR)) {
848 const gchar *envstr;
849 AlertValue val;
850
851 /* check for filename encoding */
852 if (conv_get_locale_charset() != C_UTF_8) {
853 envstr = g_getenv("G_FILENAME_ENCODING");
854 if (!envstr)
855 envstr = g_getenv("G_BROKEN_FILENAMES");
856 if (!envstr) {
857 val = alertpanel(_("Filename encoding"),
858 _("The locale encoding is not UTF-8, but the environmental variable G_FILENAME_ENCODING is not set.\n"
859 "If the locale encoding is used for file name or directory name, it will not work correctly.\n"
860 "In that case, you must set the following environmental variable (see README for detail):\n"
861 "\n"
862 "\tG_FILENAME_ENCODING=@locale\n"
863 "\n"
864 "Continue?"),
865 GTK_STOCK_OK, GTK_STOCK_QUIT,
866 NULL);
867 if (G_ALERTDEFAULT != val)
868 exit(1);
869 }
870 }
871
872 if (make_dir(RC_DIR) < 0)
873 exit(1);
874 if (is_dir_exist(OLD_RC_DIR))
875 migrate_old_config();
876 }
877#endif /* !G_OS_WIN32 && !__APPLE__ */
878
879 syl_setup_rc_dir();
880}
881
882static void app_restart(void)
883{
884 gchar *cmdline;
885 GError *error = NULL;
886#ifdef G_OS_WIN32
887 if (cmd.configdir) {
888 cmdline = g_strdup_printf("\"%s\"%s --configdir \"%s\" --ipcport %d",
889 cmd.argv0,
890 get_debug_mode() ? " --debug" : "",
891 get_rc_dir(),
892 cmd.ipcport);
893 } else {
894 cmdline = g_strdup_printf("\"%s\"%s --ipcport %d",
895 cmd.argv0,
896 get_debug_mode() ? " --debug" : "",
897 cmd.ipcport);
898 }
899#else
900 if (cmd.configdir) {
901 cmdline = g_strdup_printf("\"%s\"%s --configdir \"%s\"",
902 cmd.argv0,
903 get_debug_mode() ? " --debug" : "",
904 get_rc_dir());
905 } else {
906 cmdline = g_strdup_printf("\"%s\"%s",
907 cmd.argv0,
908 get_debug_mode() ? " --debug" : "");
909 }
910#endif
911 if (!g_spawn_command_line_async(cmdline, &error)) {
912 alertpanel_error("restart failed\n'%s'\n%s", cmdline, error->message);
913 g_error_free(error);
914 }
915 g_free(cmdline);
916}
917
918void app_will_restart(gboolean force)
919{
920 cmd.restart = TRUE;
921 app_will_exit(force);
922 /* canceled */
923 cmd.restart = FALSE;
924}
925
926void app_will_exit(gboolean force)
927{
928 MainWindow *mainwin;
929 gchar *filename;
930 static gboolean on_exit = FALSE;
931 GList *cur;
932
933 if (on_exit)
934 return;
935 on_exit = TRUE;
936
937 mainwin = main_window_get();
938
939 if (!force && compose_get_compose_list()) {
940 if (alertpanel(_("Notice"),
941 _("Composing message exists. Really quit?"),
942 GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL)
943 != G_ALERTDEFAULT) {
944 on_exit = FALSE;
945 return;
946 }
947 manage_window_focus_in(mainwin->window, NULL, NULL);
948 }
949
950 if (!force &&
951 prefs_common.warn_queued_on_exit && get_queued_message_num() > 0) {
952 if (alertpanel(_("Queued messages"),
953 _("Some unsent messages are queued. Exit now?"),
954 GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL)
955 != G_ALERTDEFAULT) {
956 on_exit = FALSE;
957 return;
958 }
959 manage_window_focus_in(mainwin->window, NULL, NULL);
960 }
961
962 if (force)
963 g_signal_emit_by_name(syl_app_get(), "app-force-exit");
964 g_signal_emit_by_name(syl_app_get(), "app-exit");
965
966 inc_autocheck_timer_remove();
967
968 if (prefs_common.clean_on_exit)
969 main_window_empty_trash(mainwin,
970 !force && prefs_common.ask_on_clean);
971
972 for (cur = account_get_list(); cur != NULL; cur = cur->next) {
973 PrefsAccount *ac = (PrefsAccount *)cur->data;
974 if (ac->protocol == A_IMAP4 && ac->imap_clear_cache_on_exit &&
975 ac->folder)
976 procmsg_remove_all_cached_messages(FOLDER(ac->folder));
977 }
978
979 syl_plugin_unload_all();
980
981 trayicon_destroy(mainwin->tray_icon);
982
983 /* save all state before exiting */
984 summary_write_cache(mainwin->summaryview);
985 main_window_get_size(mainwin);
986 main_window_get_position(mainwin);
987 syl_save_all_state();
988 addressbook_export_to_file();
989
990 filename = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MENU_RC, NULL);
991 gtk_accel_map_save(filename);
992 g_free(filename);
993
994 /* remove temporary files, close log file, socket cleanup */
995#if USE_SSL
996 ssl_done();
997#endif
998 syl_cleanup();
999 lock_socket_remove();
1000
1001#ifdef USE_UPDATE_CHECK_PLUGIN
1002#ifdef G_OS_WIN32
1003 cur = gtk_window_list_toplevels();
1004 g_list_foreach(cur, (GFunc)gtk_widget_hide, NULL);
1005 g_list_free(cur);
1006 update_check_spawn_plugin_updater();
1007#endif
1008#endif
1009
1010 cleanup_console();
1011
1012 if (gtk_main_level() > 0)
1013 gtk_main_quit();
1014
1015 if (cmd.restart)
1016 app_restart();
1017
1018 exit(0);
1019}
1020
1021#if 0
1022#if USE_GPGME
1023static void idle_function_for_gpgme(void)
1024{
1025 while (gtk_events_pending())
1026 gtk_main_iteration();
1027}
1028#endif /* USE_GPGME */
1029#endif /* 0 */
1030
1031static void check_gpg(void)
1032{
1033#if USE_GPGME
1034 const gchar *version;
1035 gpgme_error_t err = 0;
1036
1037 version = gpgme_check_version("1.0.0");
1038 if (version) {
1039 debug_print("GPGME Version: %s\n", version);
1040 err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
1041 if (err)
1042 debug_print("gpgme_engine_check_version: %s\n",
1043 gpgme_strerror(err));
1044 }
1045
1046 if (version && !err) {
1047 /* Also does some gpgme init */
1048 gpgme_engine_info_t engineInfo;
1049
1050#if HAVE_LOCALE_H
1051 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
1052 gpgme_set_locale(NULL, LC_MESSAGES,
1053 setlocale(LC_MESSAGES, NULL));
1054#endif
1055
1056 if (!gpgme_get_engine_info(&engineInfo)) {
1057 while (engineInfo) {
1058 debug_print("GPGME Protocol: %s\n Version: %s\n",
1059 gpgme_get_protocol_name
1060 (engineInfo->protocol),
1061 engineInfo->version ?
1062 engineInfo->version : "(unknown)");
1063 engineInfo = engineInfo->next;
1064 }
1065 }
1066
1067 procmsg_set_decrypt_message_func
1068 (rfc2015_open_message_decrypted);
1069 procmsg_set_auto_decrypt_message(TRUE);
1070 } else {
1071 rfc2015_disable_all();
1072
1073 if (prefs_common.gpg_warning) {
1074 AlertValue val;
1075
1076 val = alertpanel_message_with_disable
1077 (_("Warning"),
1078 _("GnuPG is not installed properly, or its version is too old.\n"
1079 "OpenPGP support disabled."),
1080 ALERT_WARNING);
1081 if (val & G_ALERTDISABLE)
1082 prefs_common.gpg_warning = FALSE;
1083 }
1084 }
1085 /* FIXME: This function went away. We can either block until gpgme
1086 * operations finish (currently implemented) or register callbacks
1087 * with the gtk main loop via the gpgme io callback interface instead.
1088 *
1089 * gpgme_register_idle(idle_function_for_gpgme);
1090 */
1091#endif
1092}
1093
1094static void default_log_func(const gchar *log_domain, GLogLevelFlags log_level,
1095 const gchar *message, gpointer user_data)
1096{
1097 gchar *prefix = "";
1098 gchar *file_prefix = "";
1099 LogType level = LOG_NORMAL;
1100 gchar *str;
1101 const gchar *message_;
1102
1103 switch (log_level) {
1104 case G_LOG_LEVEL_ERROR:
1105 prefix = "ERROR";
1106 file_prefix = "*** ";
1107 level = LOG_ERROR;
1108 break;
1109 case G_LOG_LEVEL_CRITICAL:
1110 prefix = "CRITICAL";
1111 file_prefix = "** ";
1112 level = LOG_WARN;
1113 break;
1114 case G_LOG_LEVEL_WARNING:
1115 prefix = "WARNING";
1116 file_prefix = "** ";
1117 level = LOG_WARN;
1118 break;
1119 case G_LOG_LEVEL_MESSAGE:
1120 prefix = "Message";
1121 file_prefix = "* ";
1122 level = LOG_MSG;
1123 break;
1124 case G_LOG_LEVEL_INFO:
1125 prefix = "INFO";
1126 file_prefix = "* ";
1127 level = LOG_MSG;
1128 break;
1129 case G_LOG_LEVEL_DEBUG:
1130 prefix = "DEBUG";
1131 break;
1132 default:
1133 prefix = "LOG";
1134 break;
1135 }
1136
1137 if (!message)
1138 message_ = "(NULL) message";
1139 else
1140 message_ = message;
1141 if (log_domain)
1142 str = g_strconcat(log_domain, "-", prefix, ": ", message_, "\n",
1143 NULL);
1144 else
1145 str = g_strconcat(prefix, ": ", message_, "\n", NULL);
1146 log_window_append(str, level);
1147 log_write(str, file_prefix);
1148 g_free(str);
1149
1150 g_log_default_handler(log_domain, log_level, message, user_data);
1151}
1152
1153static void set_log_handlers(gboolean enable)
1154{
1155#if GLIB_CHECK_VERSION(2, 6, 0)
1156 if (enable)
1157 g_log_set_default_handler(default_log_func, NULL);
1158 else
1159 g_log_set_default_handler(g_log_default_handler, NULL);
1160#else
1161 static guint handler_id[4] = {0, 0, 0, 0};
1162
1163 if (enable) {
1164 handler_id[0] = g_log_set_handler
1165 ("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
1166 | G_LOG_FLAG_RECURSION, default_log_func, NULL);
1167 handler_id[1] = g_log_set_handler
1168 ("Gtk", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
1169 | G_LOG_FLAG_RECURSION, default_log_func, NULL);
1170 handler_id[2] = g_log_set_handler
1171 ("LibSylph", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
1172 | G_LOG_FLAG_RECURSION, default_log_func, NULL);
1173 handler_id[3] = g_log_set_handler
1174 ("Sylpheed", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
1175 | G_LOG_FLAG_RECURSION, default_log_func, NULL);
1176 } else {
1177 g_log_remove_handler("GLib", handler_id[0]);
1178 g_log_remove_handler("Gtk", handler_id[1]);
1179 g_log_remove_handler("LibSylph", handler_id[2]);
1180 g_log_remove_handler("Sylpheed", handler_id[3]);
1181 handler_id[0] = 0;
1182 handler_id[1] = 0;
1183 handler_id[2] = 0;
1184 handler_id[3] = 0;
1185 }
1186#endif
1187}
1188
1189#ifdef G_OS_WIN32
1190
1191#if !GTK_CHECK_VERSION(2, 14, 0)
1192static UINT taskbar_created_msg;
1193#endif
1194
1195static BOOL WINAPI
1196ctrl_handler(DWORD dwctrltype)
1197{
1198 log_print("ctrl_handler: received %d\n", dwctrltype);
1199 app_will_exit(TRUE);
1200
1201 return TRUE;
1202}
1203
1204static LRESULT CALLBACK
1205wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1206{
1207 switch (message) {
1208 case WM_POWERBROADCAST:
1209 debug_print("WM_POWERBROADCAST received: wparam = %d\n",
1210 wparam);
1211 if (wparam == PBT_APMSUSPEND || wparam == PBT_APMSTANDBY) {
1212 debug_print("suspend now\n");
1213 inc_autocheck_timer_remove();
1214 } else if (wparam == PBT_APMRESUMESUSPEND ||
1215 wparam == PBT_APMRESUMESTANDBY) {
1216 debug_print("resume now\n");
1217 inc_autocheck_timer_set();
1218 }
1219 break;
1220 case WM_ENDSESSION:
1221 if (wparam == 1) {
1222 log_print("WM_ENDSESSION received: system is quitting\n");
1223 app_will_exit(TRUE);
1224 }
1225 break;
1226 default:
1227#if !GTK_CHECK_VERSION(2, 14, 0)
1228 if (message == taskbar_created_msg) {
1229 debug_print("TaskbarCreated received\n");
1230
1231 /* recreate tray icon */
1232 {
1233 MainWindow *mainwin = main_window_get();
1234 if (mainwin && mainwin->tray_icon &&
1235 gtk_status_icon_get_visible(mainwin->tray_icon->status_icon)) {
1236 trayicon_hide(mainwin->tray_icon);
1237 trayicon_show(mainwin->tray_icon);
1238 }
1239 }
1240 }
1241#endif
1242 break;
1243 }
1244
1245 return DefWindowProc(hwnd, message, wparam, lparam);
1246}
1247
1248static void register_system_events(void)
1249{
1250 WNDCLASS wclass;
1251 static HWND hwnd = NULL;
1252 static BOOL ctrl_handler_set = FALSE;
1253 ATOM klass;
1254 HINSTANCE hmodule = GetModuleHandle(NULL);
1255
1256 if (init_console_done && !ctrl_handler_set) {
1257 debug_print("register_system_events(): SetConsoleCtrlHandler\n");
1258 ctrl_handler_set = SetConsoleCtrlHandler(ctrl_handler, TRUE);
1259 if (!ctrl_handler_set)
1260 g_warning("SetConsoleCtrlHandler() failed\n");
1261 }
1262
1263 if (hwnd)
1264 return;
1265
1266#if !GTK_CHECK_VERSION(2, 14, 0)
1267 taskbar_created_msg = RegisterWindowMessage("TaskbarCreated");
1268#endif
1269
1270 debug_print("register_system_events(): RegisterClass\n");
1271
1272 memset(&wclass, 0, sizeof(WNDCLASS));
1273 wclass.lpszClassName = "sylpheed-observer";
1274 wclass.lpfnWndProc = wndproc;
1275 wclass.hInstance = hmodule;
1276
1277 klass = RegisterClass(&wclass);
1278 if (!klass)
1279 return;
1280
1281 hwnd = CreateWindow(MAKEINTRESOURCE(klass), NULL, WS_POPUP,
1282 0, 0, 1, 1, NULL, NULL, hmodule, NULL);
1283 if (!hwnd)
1284 UnregisterClass(MAKEINTRESOURCE(klass), hmodule);
1285}
1286#else /* G_OS_WIN32 */
1287static void sig_handler(gint signum)
1288{
1289 debug_print("signal %d received\n", signum);
1290
1291 switch (signum) {
1292 case SIGHUP:
1293 case SIGINT:
1294 case SIGTERM:
1295 case SIGQUIT:
1296 app_will_exit(TRUE);
1297 break;
1298 default:
1299 break;
1300 }
1301}
1302
1303static void register_system_events(void)
1304{
1305 struct sigaction sa;
1306
1307 memset(&sa, 0, sizeof(sa));
1308 sa.sa_handler = sig_handler;
1309 sa.sa_flags = SA_RESTART;
1310
1311 sigemptyset(&sa.sa_mask);
1312 sigaddset(&sa.sa_mask, SIGHUP);
1313 sigaddset(&sa.sa_mask, SIGINT);
1314 sigaddset(&sa.sa_mask, SIGTERM);
1315 sigaddset(&sa.sa_mask, SIGQUIT);
1316 sigaddset(&sa.sa_mask, SIGPIPE);
1317
1318 sigaction(SIGHUP, &sa, NULL);
1319 sigaction(SIGINT, &sa, NULL);
1320 sigaction(SIGTERM, &sa, NULL);
1321 sigaction(SIGQUIT, &sa, NULL);
1322 sigaction(SIGPIPE, &sa, NULL);
1323}
1324#endif
1325
1326#define ADD_SYM(sym) syl_plugin_add_symbol(#sym, sym)
1327
1328static void plugin_init(void)
1329{
1330 MainWindow *mainwin;
1331 gchar *path;
1332
1333 mainwin = main_window_get();
1334
1335 STATUSBAR_PUSH(mainwin, _("Loading plug-ins..."));
1336
1337 if (syl_plugin_init_lib() != 0) {
1338 STATUSBAR_POP(mainwin);
1339 return;
1340 }
1341
1342 if (cmd.safe_mode) {
1343 debug_print("plugin_init: safe mode enabled, skipping plug-in loading.\n");
1344 STATUSBAR_POP(mainwin);
1345 return;
1346 }
1347
1348 ADD_SYM(prog_version);
1349 ADD_SYM(app_will_exit);
1350
1351 ADD_SYM(main_window_lock);
1352 ADD_SYM(main_window_unlock);
1353 ADD_SYM(main_window_get);
1354 ADD_SYM(main_window_popup);
1355
1356 syl_plugin_add_symbol("main_window_menu_factory",
1357 mainwin->menu_factory);
1358 syl_plugin_add_symbol("main_window_toolbar", mainwin->toolbar);
1359 syl_plugin_add_symbol("main_window_statusbar", mainwin->statusbar);
1360
1361 ADD_SYM(folderview_get);
1362 ADD_SYM(folderview_add_sub_widget);
1363 ADD_SYM(folderview_select);
1364 ADD_SYM(folderview_unselect);
1365 ADD_SYM(folderview_select_next_unread);
1366 ADD_SYM(folderview_get_selected_item);
1367 ADD_SYM(folderview_check_new);
1368 ADD_SYM(folderview_check_new_item);
1369 ADD_SYM(folderview_check_new_all);
1370 ADD_SYM(folderview_update_item);
1371 ADD_SYM(folderview_update_item_foreach);
1372 ADD_SYM(folderview_update_all_updated);
1373 ADD_SYM(folderview_check_new_selected);
1374
1375 syl_plugin_add_symbol("folderview_mail_popup_factory",
1376 mainwin->folderview->mail_factory);
1377 syl_plugin_add_symbol("folderview_imap_popup_factory",
1378 mainwin->folderview->imap_factory);
1379 syl_plugin_add_symbol("folderview_news_popup_factory",
1380 mainwin->folderview->news_factory);
1381
1382 syl_plugin_add_symbol("summaryview", mainwin->summaryview);
1383 syl_plugin_add_symbol("summaryview_popup_factory",
1384 mainwin->summaryview->popupfactory);
1385
1386 ADD_SYM(summary_select_by_msgnum);
1387 ADD_SYM(summary_select_by_msginfo);
1388 ADD_SYM(summary_lock);
1389 ADD_SYM(summary_unlock);
1390 ADD_SYM(summary_is_locked);
1391 ADD_SYM(summary_is_read_locked);
1392 ADD_SYM(summary_write_lock);
1393 ADD_SYM(summary_write_unlock);
1394 ADD_SYM(summary_is_write_locked);
1395 ADD_SYM(summary_get_current_folder);
1396 ADD_SYM(summary_get_selection_type);
1397 ADD_SYM(summary_get_selected_msg_list);
1398 ADD_SYM(summary_get_msg_list);
1399 ADD_SYM(summary_show_queued_msgs);
1400 ADD_SYM(summary_redisplay_msg);
1401 ADD_SYM(summary_open_msg);
1402 ADD_SYM(summary_view_source);
1403 ADD_SYM(summary_reedit);
1404 ADD_SYM(summary_update_selected_rows);
1405 ADD_SYM(summary_update_by_msgnum);
1406
1407 ADD_SYM(messageview_create_with_new_window);
1408 ADD_SYM(messageview_show);
1409
1410 ADD_SYM(compose_new);
1411 ADD_SYM(compose_reply);
1412 ADD_SYM(compose_forward);
1413 ADD_SYM(compose_redirect);
1414 ADD_SYM(compose_reedit);
1415 ADD_SYM(compose_entry_set);
1416 ADD_SYM(compose_entry_append);
1417 ADD_SYM(compose_entry_get_text);
1418 ADD_SYM(compose_lock);
1419 ADD_SYM(compose_unlock);
1420 ADD_SYM(compose_get_toolbar);
1421 ADD_SYM(compose_get_misc_hbox);
1422 ADD_SYM(compose_get_textview);
1423 ADD_SYM(compose_attach_append);
1424 ADD_SYM(compose_attach_remove_all);
1425 ADD_SYM(compose_get_attach_list);
1426 ADD_SYM(compose_send);
1427
1428 ADD_SYM(foldersel_folder_sel);
1429 ADD_SYM(foldersel_folder_sel_full);
1430
1431 ADD_SYM(input_dialog);
1432 ADD_SYM(input_dialog_with_invisible);
1433
1434 ADD_SYM(manage_window_set_transient);
1435 ADD_SYM(manage_window_signals_connect);
1436 ADD_SYM(manage_window_get_focus_window);
1437
1438 ADD_SYM(inc_mail);
1439 ADD_SYM(inc_is_active);
1440 ADD_SYM(inc_lock);
1441 ADD_SYM(inc_unlock);
1442
1443#if USE_UPDATE_CHECK
1444 ADD_SYM(update_check);
1445 ADD_SYM(update_check_set_check_url);
1446 ADD_SYM(update_check_get_check_url);
1447 ADD_SYM(update_check_set_download_url);
1448 ADD_SYM(update_check_get_download_url);
1449 ADD_SYM(update_check_set_jump_url);
1450 ADD_SYM(update_check_get_jump_url);
1451#ifdef USE_UPDATE_CHECK_PLUGIN
1452 ADD_SYM(update_check_set_check_plugin_url);
1453 ADD_SYM(update_check_get_check_plugin_url);
1454 ADD_SYM(update_check_set_jump_plugin_url);
1455 ADD_SYM(update_check_get_jump_plugin_url);
1456#endif /* USE_UPDATE_CHECK_PLUGIN */
1457#endif
1458
1459 ADD_SYM(alertpanel_full);
1460 ADD_SYM(alertpanel);
1461 ADD_SYM(alertpanel_message);
1462 ADD_SYM(alertpanel_message_with_disable);
1463
1464 ADD_SYM(send_message);
1465 ADD_SYM(send_message_queue_all);
1466 ADD_SYM(send_message_set_reply_flag);
1467 ADD_SYM(send_message_set_forward_flags);
1468
1469 ADD_SYM(notification_window_open);
1470 ADD_SYM(notification_window_set_message);
1471 ADD_SYM(notification_window_close);
1472
1473 syl_plugin_signal_connect("plugin-load", G_CALLBACK(load_cb), NULL);
1474
1475 /* loading plug-ins from user plug-in directory */
1476 path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, PLUGIN_DIR, NULL);
1477 syl_plugin_load_all(path);
1478 g_free(path);
1479
1480 /* loading plug-ins from system plug-in directory */
1481#ifdef G_OS_WIN32
1482 path = g_strconcat(get_startup_dir(), G_DIR_SEPARATOR_S, PLUGIN_DIR,
1483 NULL);
1484 syl_plugin_load_all(path);
1485 g_free(path);
1486#elif defined(__APPLE__)
1487 path = g_strconcat(get_startup_dir(), G_DIR_SEPARATOR_S,
1488 "Contents" G_DIR_SEPARATOR_S
1489 "Resources" G_DIR_SEPARATOR_S
1490 "lib" G_DIR_SEPARATOR_S
1491 "sylpheed" G_DIR_SEPARATOR_S
1492 PLUGIN_DIR,
1493 NULL);
1494 syl_plugin_load_all(path);
1495 g_free(path);
1496#else
1497 syl_plugin_load_all(PLUGINDIR);
1498#endif
1499
1500 STATUSBAR_POP(mainwin);
1501}
1502
1503static gchar *get_socket_name(void)
1504{
1505 static gchar *filename = NULL;
1506
1507 if (filename == NULL) {
1508 filename = g_strdup_printf("%s%c%s-%d",
1509 g_get_tmp_dir(), G_DIR_SEPARATOR,
1510 instance_id ? instance_id : "sylpheed",
1511#if HAVE_GETUID
1512 getuid());
1513#else
1514 0);
1515#endif
1516 }
1517
1518 return filename;
1519}
1520
1521static gint prohibit_duplicate_launch(void)
1522{
1523 gint sock;
1524
1525#ifdef G_OS_WIN32
1526 HANDLE hmutex;
1527 const gchar *ins_id = instance_id ? instance_id : "Sylpheed";
1528 gushort port = cmd.ipcport ? cmd.ipcport : REMOTE_CMD_PORT;
1529
1530 debug_print("prohibit_duplicate_launch: checking mutex: %s\n", ins_id);
1531 hmutex = CreateMutexA(NULL, FALSE, ins_id);
1532 if (!hmutex) {
1533 g_warning("cannot create Mutex: %s\n", ins_id);
1534 return -1;
1535 }
1536 if (GetLastError() != ERROR_ALREADY_EXISTS) {
1537 debug_print("prohibit_duplicate_launch: creating socket: port %d\n", port);
1538 sock = fd_open_inet(port);
1539 if (sock < 0)
1540 return 0;
1541 return sock;
1542 }
1543
1544 debug_print("prohibit_duplicate_launch: connecting to socket: port %d\n", port);
1545 sock = fd_connect_inet(port);
1546 if (sock < 0)
1547 return -1;
1548#else
1549 gchar *path;
1550
1551 path = get_socket_name();
1552 debug_print("prohibit_duplicate_launch: checking socket: %s\n", path);
1553 sock = fd_connect_unix(path);
1554 if (sock < 0) {
1555 debug_print("prohibit_duplicate_launch: creating socket: %s\n", path);
1556 g_unlink(path);
1557 return fd_open_unix(path);
1558 }
1559#endif
1560
1561 /* remote command mode */
1562
1563 debug_print(_("another Sylpheed is already running.\n"));
1564
1565 if (cmd.receive_all)
1566 fd_write_all(sock, "receive_all\n", 12);
1567 else if (cmd.receive)
1568 fd_write_all(sock, "receive\n", 8);
1569 else if (cmd.compose && cmd.attach_files) {
1570 gchar *str, *compose_str;
1571 gint i;
1572
1573 if (cmd.compose_mailto)
1574 compose_str = g_strdup_printf("compose_attach %s\n",
1575 cmd.compose_mailto);
1576 else
1577 compose_str = g_strdup("compose_attach\n");
1578
1579 fd_write_all(sock, compose_str, strlen(compose_str));
1580 g_free(compose_str);
1581
1582 for (i = 0; i < cmd.attach_files->len; i++) {
1583 str = g_ptr_array_index(cmd.attach_files, i);
1584 fd_write_all(sock, str, strlen(str));
1585 fd_write_all(sock, "\n", 1);
1586 }
1587
1588 fd_write_all(sock, ".\n", 2);
1589 } else if (cmd.compose) {
1590 gchar *compose_str;
1591
1592 if (cmd.compose_mailto)
1593 compose_str = g_strdup_printf
1594 ("compose %s\n", cmd.compose_mailto);
1595 else
1596 compose_str = g_strdup("compose\n");
1597
1598 fd_write_all(sock, compose_str, strlen(compose_str));
1599 g_free(compose_str);
1600 } else if (cmd.send) {
1601 fd_write_all(sock, "send\n", 5);
1602 } else if (cmd.status || cmd.status_full) {
1603 gchar buf[BUFFSIZE];
1604 gint i;
1605 const gchar *command;
1606 GPtrArray *folders;
1607 gchar *folder;
1608
1609 command = cmd.status_full ? "status-full\n" : "status\n";
1610 folders = cmd.status_full ? cmd.status_full_folders :
1611 cmd.status_folders;
1612
1613 fd_write_all(sock, command, strlen(command));
1614 for (i = 0; folders && i < folders->len; ++i) {
1615 folder = g_ptr_array_index(folders, i);
1616 fd_write_all(sock, folder, strlen(folder));
1617 fd_write_all(sock, "\n", 1);
1618 }
1619 fd_write_all(sock, ".\n", 2);
1620 for (;;) {
1621 if (fd_gets(sock, buf, sizeof(buf)) <= 0) break;
1622 if (!strncmp(buf, ".\n", 2)) break;
1623 fputs(buf, stdout);
1624 }
1625 } else if (cmd.open_msg) {
1626 gchar *str;
1627
1628 str = g_strdup_printf("open %s\n", cmd.open_msg);
1629 fd_write_all(sock, str, strlen(str));
1630 g_free(str);
1631 } else if (cmd.exit) {
1632 fd_write_all(sock, "exit\n", 5);
1633 } else {
1634#ifdef G_OS_WIN32
1635 HWND hwnd;
1636
1637 fd_write_all(sock, "popup\n", 6);
1638 if (fd_read(sock, (gchar *)&hwnd, sizeof(hwnd)) == sizeof(hwnd))
1639 SetForegroundWindow(hwnd);
1640#else
1641 fd_write_all(sock, "popup\n", 6);
1642#endif
1643 }
1644
1645 fd_close(sock);
1646 return -1;
1647}
1648
1649static gint lock_socket_remove(void)
1650{
1651#ifndef G_OS_WIN32
1652 gchar *filename;
1653#endif
1654
1655 if (lock_socket < 0) return -1;
1656
1657 if (lock_socket_tag > 0)
1658 g_source_remove(lock_socket_tag);
1659 if (lock_ch) {
1660 g_io_channel_shutdown(lock_ch, FALSE, NULL);
1661 g_io_channel_unref(lock_ch);
1662 lock_ch = NULL;
1663 }
1664
1665#ifndef G_OS_WIN32
1666 filename = get_socket_name();
1667 debug_print("lock_socket_remove: removing socket: %s\n", filename);
1668 g_unlink(filename);
1669#endif
1670
1671 return 0;
1672}
1673
1674static GPtrArray *get_folder_item_list(gint sock)
1675{
1676 gchar buf[BUFFSIZE];
1677 FolderItem *item;
1678 GPtrArray *folders = NULL;
1679
1680 for (;;) {
1681 if (fd_gets(sock, buf, sizeof(buf)) <= 0) break;
1682 if (!strncmp(buf, ".\n", 2)) break;
1683 strretchomp(buf);
1684 if (!folders) folders = g_ptr_array_new();
1685 item = folder_find_item_from_identifier(buf);
1686 if (item)
1687 g_ptr_array_add(folders, item);
1688 else
1689 g_warning("no such folder: %s\n", buf);
1690 }
1691
1692 return folders;
1693}
1694
1695static gboolean lock_socket_input_cb(GIOChannel *source, GIOCondition condition,
1696 gpointer data)
1697{
1698 MainWindow *mainwin = (MainWindow *)data;
1699 gint fd, sock;
1700 gchar buf[BUFFSIZE];
1701
1702#if USE_THREADS
1703 gdk_threads_enter();
1704#endif
1705
1706 fd = g_io_channel_unix_get_fd(source);
1707 sock = fd_accept(fd);
1708 if (fd_gets(sock, buf, sizeof(buf)) <= 0) {
1709 fd_close(sock);
1710#if USE_THREADS
1711 gdk_threads_leave();
1712#endif
1713 return TRUE;
1714 }
1715
1716 if (!strncmp(buf, "popup", 5)) {
1717#ifdef G_OS_WIN32
1718 HWND hwnd;
1719
1720 hwnd = (HWND)gdk_win32_drawable_get_handle
1721 (GDK_DRAWABLE(mainwin->window->window));
1722 fd_write(sock, (gchar *)&hwnd, sizeof(hwnd));
1723 if (mainwin->window_hidden)
1724 main_window_popup(mainwin);
1725#else
1726 main_window_popup(mainwin);
1727#endif
1728 } else if (!strncmp(buf, "receive_all", 11)) {
1729 main_window_popup(mainwin);
1730 if (!gtkut_window_modal_exist())
1731 inc_all_account_mail(mainwin, FALSE);
1732 } else if (!strncmp(buf, "receive", 7)) {
1733 main_window_popup(mainwin);
1734 if (!gtkut_window_modal_exist())
1735 inc_mail(mainwin);
1736 } else if (!strncmp(buf, "compose_attach", 14)) {
1737 GPtrArray *files;
1738 gchar *mailto;
1739
1740 mailto = g_strdup(buf + strlen("compose_attach") + 1);
1741 files = g_ptr_array_new();
1742 while (fd_gets(sock, buf, sizeof(buf)) > 0) {
1743 if (buf[0] == '.' && buf[1] == '\n') break;
1744 strretchomp(buf);
1745 g_ptr_array_add(files, g_strdup(buf));
1746 }
1747 open_compose_new(mailto, files);
1748 ptr_array_free_strings(files);
1749 g_ptr_array_free(files, TRUE);
1750 g_free(mailto);
1751 } else if (!strncmp(buf, "compose", 7)) {
1752 open_compose_new(buf + strlen("compose") + 1, NULL);
1753 } else if (!strncmp(buf, "send", 4)) {
1754 send_queue();
1755 } else if (!strncmp(buf, "status-full", 11) ||
1756 !strncmp(buf, "status", 6)) {
1757 gchar *status;
1758 GPtrArray *folders;
1759
1760 folders = get_folder_item_list(sock);
1761 status = folder_get_status
1762 (folders, !strncmp(buf, "status-full", 11));
1763 fd_write_all(sock, status, strlen(status));
1764 fd_write_all(sock, ".\n", 2);
1765 g_free(status);
1766 if (folders) g_ptr_array_free(folders, TRUE);
1767 } else if (!strncmp(buf, "open", 4)) {
1768 strretchomp(buf);
1769 if (strlen(buf) < 6 || buf[4] != ' ') {
1770 fd_close(sock);
1771#if USE_THREADS
1772 gdk_threads_leave();
1773#endif
1774 return TRUE;
1775 }
1776 open_message(buf + 5);
1777 } else if (!strncmp(buf, "exit", 4)) {
1778 fd_close(sock);
1779 app_will_exit(TRUE);
1780 }
1781
1782 fd_close(sock);
1783
1784#if USE_THREADS
1785 gdk_threads_leave();
1786#endif
1787
1788 return TRUE;
1789}
1790
1791static void remote_command_exec(void)
1792{
1793 MainWindow *mainwin;
1794
1795 mainwin = main_window_get();
1796
1797 if (prefs_common.open_inbox_on_startup) {
1798 FolderItem *item;
1799 PrefsAccount *ac;
1800
1801 ac = account_get_default();
1802 if (!ac)
1803 ac = cur_account;
1804 item = ac && ac->inbox
1805 ? folder_find_item_from_identifier(ac->inbox)
1806 : folder_get_default_inbox();
1807 folderview_select(mainwin->folderview, item);
1808 }
1809
1810 if (!gtkut_window_modal_exist()) {
1811 if (cmd.compose)
1812 open_compose_new(cmd.compose_mailto, cmd.attach_files);
1813
1814 if (cmd.open_msg)
1815 open_message(cmd.open_msg);
1816
1817 if (cmd.receive_all)
1818 inc_all_account_mail(mainwin, FALSE);
1819 else if (prefs_common.chk_on_startup)
1820 inc_all_account_mail(mainwin, TRUE);
1821 else if (cmd.receive)
1822 inc_mail(mainwin);
1823
1824 if (cmd.send)
1825 send_queue();
1826 }
1827
1828 if (cmd.attach_files) {
1829 ptr_array_free_strings(cmd.attach_files);
1830 g_ptr_array_free(cmd.attach_files, TRUE);
1831 cmd.attach_files = NULL;
1832 }
1833 if (cmd.status_folders) {
1834 g_ptr_array_free(cmd.status_folders, TRUE);
1835 cmd.status_folders = NULL;
1836 }
1837 if (cmd.status_full_folders) {
1838 g_ptr_array_free(cmd.status_full_folders, TRUE);
1839 cmd.status_full_folders = NULL;
1840 }
1841 if (cmd.open_msg) {
1842 g_free(cmd.open_msg);
1843 cmd.open_msg = NULL;
1844 }
1845 if (cmd.exit) {
1846 app_will_exit(TRUE);
1847 }
1848}
1849
1850#if !defined(G_OS_WIN32) && !defined(__APPLE__)
1851static void migrate_old_config(void)
1852{
1853 GDir *dir;
1854 const gchar *dir_name;
1855 GPatternSpec *pspec;
1856
1857 if (alertpanel(_("Migration of configuration"),
1858 _("The previous version of configuration found.\n"
1859 "Do you want to migrate it?"),
1860 GTK_STOCK_YES, GTK_STOCK_NO, NULL) != G_ALERTDEFAULT)
1861 return;
1862
1863 debug_print("Migrating old configuration...\n");
1864
1865#define COPY_FILE(rcfile) \
1866 if (is_file_exist(OLD_RC_DIR G_DIR_SEPARATOR_S rcfile)) { \
1867 conv_copy_file(OLD_RC_DIR G_DIR_SEPARATOR_S rcfile, \
1868 RC_DIR G_DIR_SEPARATOR_S rcfile, \
1869 conv_get_locale_charset_str()); \
1870 }
1871
1872 COPY_FILE(ACCOUNT_RC);
1873 COPY_FILE(ACTIONS_RC);
1874 COPY_FILE(COMMON_RC);
1875 COPY_FILE(CUSTOM_HEADER_RC);
1876 COPY_FILE(DISPLAY_HEADER_RC);
1877 COPY_FILE(FILTER_HEADER_RC);
1878 COPY_FILE(COMMAND_HISTORY);
1879
1880#undef COPY_FILE
1881
1882 if (is_file_exist(OLD_RC_DIR G_DIR_SEPARATOR_S FILTER_LIST))
1883 copy_file(OLD_RC_DIR G_DIR_SEPARATOR_S FILTER_LIST,
1884 RC_DIR G_DIR_SEPARATOR_S FILTER_LIST, FALSE);
1885 if (is_file_exist(OLD_RC_DIR G_DIR_SEPARATOR_S FOLDER_LIST))
1886 copy_file(OLD_RC_DIR G_DIR_SEPARATOR_S FOLDER_LIST,
1887 RC_DIR G_DIR_SEPARATOR_S FOLDER_LIST, FALSE);
1888 if (is_file_exist(OLD_RC_DIR G_DIR_SEPARATOR_S "mime.types"))
1889 copy_file(OLD_RC_DIR G_DIR_SEPARATOR_S "mime.types",
1890 RC_DIR G_DIR_SEPARATOR_S "mime.types", FALSE);
1891
1892 if (is_dir_exist(OLD_RC_DIR G_DIR_SEPARATOR_S TEMPLATE_DIR))
1893 conv_copy_dir(OLD_RC_DIR G_DIR_SEPARATOR_S TEMPLATE_DIR,
1894 RC_DIR G_DIR_SEPARATOR_S TEMPLATE_DIR,
1895 conv_get_locale_charset_str());
1896 if (is_dir_exist(OLD_RC_DIR G_DIR_SEPARATOR_S UIDL_DIR))
1897 copy_dir(OLD_RC_DIR G_DIR_SEPARATOR_S UIDL_DIR,
1898 RC_DIR G_DIR_SEPARATOR_S UIDL_DIR);
1899
1900 if (!is_file_exist(OLD_RC_DIR G_DIR_SEPARATOR_S ADDRESSBOOK_INDEX_FILE))
1901 return;
1902
1903 if ((dir = g_dir_open(OLD_RC_DIR, 0, NULL)) == NULL) {
1904 g_warning("failed to open directory: %s\n", OLD_RC_DIR);
1905 return;
1906 }
1907
1908 pspec = g_pattern_spec_new("addrbook-*.xml");
1909
1910 while ((dir_name = g_dir_read_name(dir)) != NULL) {
1911 if (g_pattern_match_string(pspec, dir_name)) {
1912 gchar *old_file;
1913 gchar *new_file;
1914
1915 old_file = g_strconcat(OLD_RC_DIR G_DIR_SEPARATOR_S,
1916 dir_name, NULL);
1917 new_file = g_strconcat(RC_DIR G_DIR_SEPARATOR_S,
1918 dir_name, NULL);
1919 copy_file(old_file, new_file, FALSE);
1920 g_free(new_file);
1921 g_free(old_file);
1922 }
1923 }
1924
1925 g_pattern_spec_free(pspec);
1926 g_dir_close(dir);
1927}
1928#endif /* !G_OS_WIN32 && !__APPLE__ */
1929
1930static void open_compose_new(const gchar *address, GPtrArray *attach_files)
1931{
1932 gchar *utf8addr = NULL;
1933#ifdef G_OS_WIN32
1934 GPtrArray *utf8files = NULL;
1935#endif
1936
1937 if (gtkut_window_modal_exist())
1938 return;
1939
1940 if (address) {
1941 utf8addr = g_locale_to_utf8(address, -1, NULL, NULL, NULL);
1942 if (utf8addr)
1943 g_strstrip(utf8addr);
1944 debug_print("open compose: %s\n", utf8addr ? utf8addr : "");
1945 }
1946
1947#ifdef G_OS_WIN32
1948 if (attach_files) {
1949 gint i;
1950 gchar *file, *utf8file;
1951
1952 utf8files = g_ptr_array_new();
1953 for (i = 0; i < attach_files->len; i++) {
1954 file = g_ptr_array_index(attach_files, i);
1955 utf8file = g_locale_to_utf8(file, -1, NULL, NULL, NULL);
1956 if (utf8file)
1957 g_ptr_array_add(utf8files, utf8file);
1958 }
1959 }
1960
1961 compose_new(NULL, NULL, utf8addr, utf8files);
1962 if (utf8files) {
1963 ptr_array_free_strings(utf8files);
1964 g_ptr_array_free(utf8files, TRUE);
1965 }
1966#else
1967 compose_new(NULL, NULL, utf8addr, attach_files);
1968#endif
1969
1970 g_free(utf8addr);
1971}
1972
1973static void open_message_file(const gchar *file)
1974{
1975 MsgInfo *msginfo;
1976 MsgFlags flags = {0};
1977 MessageView *msgview;
1978
1979 g_return_if_fail(file != NULL);
1980
1981 debug_print("open message file: %s\n", file);
1982
1983 if (!is_file_exist(file) || get_file_size(file) <= 0) {
1984 debug_print("file not found: %s\n", file);
1985 return;
1986 }
1987
1988 msginfo = procheader_parse_file(file, flags, FALSE);
1989 if (msginfo) {
1990 msginfo->file_path = g_strdup(file);
1991 msgview = messageview_create_with_new_window();
1992 messageview_show(msgview, msginfo, FALSE);
1993 procmsg_msginfo_free(msginfo);
1994 } else
1995 debug_print("cannot open message: %s\n", file);
1996}
1997
1998static void open_message(const gchar *path)
1999{
2000 gchar *fid;
2001 gchar *msg;
2002 gint num;
2003 FolderItem *item;
2004 MsgInfo *msginfo;
2005 MessageView *msgview;
2006 gchar *file;
2007
2008 g_return_if_fail(path != NULL);
2009
2010 if (gtkut_window_modal_exist())
2011 return;
2012
2013 debug_print("open message: %s\n", path);
2014
2015 if (!strncmp(path, "file:", 5)) {
2016 file = g_filename_from_uri(path, NULL, NULL);
2017 open_message_file(file);
2018 g_free(file);
2019 return;
2020 } else if (g_path_is_absolute(path)) {
2021 open_message_file(path);
2022 return;
2023 }
2024
2025 /* relative path, or folder identifier */
2026
2027 fid = g_path_get_dirname(path);
2028 msg = g_path_get_basename(path);
2029 num = to_number(msg);
2030 item = folder_find_item_from_identifier(fid);
2031
2032 if (num > 0 && item) {
2033 debug_print("open folder id: %s (msg %d)\n", fid, num);
2034 msginfo = folder_item_get_msginfo(item, num);
2035 if (msginfo) {
2036 msgview = messageview_create_with_new_window();
2037 messageview_show(msgview, msginfo, FALSE);
2038 procmsg_msginfo_free(msginfo);
2039 g_free(msg);
2040 g_free(fid);
2041 return;
2042 } else
2043 debug_print("message %d not found\n", num);
2044 }
2045
2046 g_free(msg);
2047 g_free(fid);
2048
2049 /* relative path */
2050
2051 file = g_strconcat(get_startup_dir(), G_DIR_SEPARATOR_S, path, NULL);
2052 open_message_file(file);
2053 g_free(file);
2054}
2055
2056static void send_queue(void)
2057{
2058 GList *list;
2059
2060 if (gtkut_window_modal_exist())
2061 return;
2062 if (!main_window_toggle_online_if_offline(main_window_get()))
2063 return;
2064
2065 for (list = folder_get_list(); list != NULL; list = list->next) {
2066 Folder *folder = list->data;
2067
2068 if (folder->queue) {
2069 gint ret;
2070
2071 ret = send_message_queue_all(folder->queue,
2072 prefs_common.savemsg,
2073 prefs_common.filter_sent);
2074 statusbar_pop_all();
2075 if (ret > 0)
2076 folder_item_scan(folder->queue);
2077 }
2078 }
2079
2080 folderview_update_all_updated(TRUE);
2081 main_window_set_menu_sensitive(main_window_get());
2082 main_window_set_toolbar_sensitive(main_window_get());
2083}