Statistics
| Revision:

root / src / main.c @ 2712

History | View | Annotate | Download (44.2 kB)

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