Statistics
| Revision:

root / src / main.c @ 1016

History | View | Annotate | Download (29.8 kB)

1
/*
2
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3
 * Copyright (C) 1999-2006 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 "import.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 "utils.h"
79
#include "gtkutils.h"
80
#include "socket.h"
81
#include "stock_pixmap.h"
82
83
#if USE_GPGME
84
#  include "rfc2015.h"
85
#endif
86
#if USE_SSL
87
#  include "ssl.h"
88
#endif
89
90
#ifdef G_OS_WIN32
91
#  include <windows.h>
92
#  include <fcntl.h>
93
#endif
94
95
#include "version.h"
96
97
gchar *prog_version;
98
99
static gint lock_socket = -1;
100
static gint lock_socket_tag = 0;
101
static GIOChannel *lock_ch = NULL;
102
103
static struct RemoteCmd {
104
        gboolean receive;
105
        gboolean receive_all;
106
        gboolean compose;
107
        const gchar *compose_mailto;
108
        GPtrArray *attach_files;
109
        gboolean send;
110
        gboolean status;
111
        gboolean status_full;
112
        GPtrArray *status_folders;
113
        GPtrArray *status_full_folders;
114
        gboolean configdir;
115
        gboolean exit;
116
} cmd;
117
118
static void parse_cmd_opt                (int                 argc,
119
                                         char                *argv[]);
120
121
static void app_init                        (void);
122
static void parse_gtkrc_files                (void);
123
static void setup_rc_dir                (void);
124
static void check_gpg                        (void);
125
static void set_log_handlers                (gboolean         enable);
126
127
static gchar *get_socket_name                (void);
128
static gint prohibit_duplicate_launch        (void);
129
static gint lock_socket_remove                (void);
130
static gboolean lock_socket_input_cb        (GIOChannel        *source,
131
                                         GIOCondition         condition,
132
                                         gpointer         data);
133
134
static void remote_command_exec                (void);
135
static void migrate_old_config                (void);
136
137
static void open_compose_new                (const gchar        *address,
138
                                         GPtrArray        *attach_files);
139
140
static void send_queue                        (void);
141
142
#define MAKE_DIR_IF_NOT_EXIST(dir)                                        \
143
{                                                                        \
144
        if (!is_dir_exist(dir)) {                                        \
145
                if (is_file_exist(dir)) {                                \
146
                        alertpanel_warning                                \
147
                                (_("File `%s' already exists.\n"        \
148
                                   "Can't create folder."),                \
149
                                 dir);                                        \
150
                        exit(1);                                        \
151
                }                                                        \
152
                if (make_dir(dir) < 0)                                        \
153
                        exit(1);                                        \
154
        }                                                                \
155
}
156
157
#define CHDIR_EXIT_IF_FAIL(dir, val)        \
158
{                                        \
159
        if (change_dir(dir) < 0)        \
160
                exit(val);                \
161
}
162
163
164
int main(int argc, char *argv[])
165
{
166
        MainWindow *mainwin;
167
        FolderView *folderview;
168
        GdkPixbuf *icon;
169
170
        app_init();
171
        parse_cmd_opt(argc, argv);
172
173
        /* check and create (unix domain) socket for remote operation */
174
        lock_socket = prohibit_duplicate_launch();
175
        if (lock_socket < 0) return 0;
176
177
        if (cmd.status || cmd.status_full) {
178
                puts("0 Sylpheed not running.");
179
                lock_socket_remove();
180
                return 0;
181
        }
182
183
        gtk_set_locale();
184
        gtk_init(&argc, &argv);
185
186
        gdk_rgb_init();
187
        gtk_widget_set_default_colormap(gdk_rgb_get_cmap());
188
        gtk_widget_set_default_visual(gdk_rgb_get_visual());
189
190
#if USE_THREADS || USE_LDAP
191
        g_thread_init(NULL);
192
        if (!g_thread_supported())
193
                g_error(_("g_thread is not supported by glib.\n"));
194
#endif
195
196
        parse_gtkrc_files();
197
        setup_rc_dir();
198
199
        if (is_file_exist("sylpheed.log")) {
200
                if (rename_force("sylpheed.log", "sylpheed.log.bak") < 0)
201
                        FILE_OP_ERROR("sylpheed.log", "rename");
202
        }
203
        set_log_file("sylpheed.log");
204
205
        set_ui_update_func(gtkut_events_flush);
206
        set_progress_func(main_window_progress_show);
207
        set_input_query_password_func(input_dialog_query_password);
208
209
        CHDIR_EXIT_IF_FAIL(get_home_dir(), 1);
210
211
        prefs_common_read_config();
212
        filter_read_config();
213
        prefs_actions_read_config();
214
        prefs_display_header_read_config();
215
216
        gtkut_stock_button_set_set_reverse(!prefs_common.comply_gnome_hig);
217
218
        check_gpg();
219
220
        sock_set_io_timeout(prefs_common.io_timeout_secs);
221
222
        gtkut_widget_init();
223
        stock_pixbuf_gdk(NULL, STOCK_PIXMAP_SYLPHEED, &icon);
224
        gtk_window_set_default_icon(icon);
225
226
        mainwin = main_window_create
227
                (prefs_common.sep_folder | prefs_common.sep_msg << 1);
228
        folderview = mainwin->folderview;
229
230
        /* register the callback of socket input */
231
        if (lock_socket > 0) {
232
                lock_ch = g_io_channel_unix_new(lock_socket);
233
                lock_socket_tag = g_io_add_watch(lock_ch,
234
                                                 G_IO_IN|G_IO_PRI|G_IO_ERR,
235
                                                 lock_socket_input_cb, mainwin);
236
        }
237
238
        set_log_handlers(TRUE);
239
240
        account_read_config_all();
241
        account_set_menu();
242
        main_window_reflect_prefs_all();
243
244
        if (folder_read_list() < 0) {
245
                setup(mainwin);
246
                folder_write_list();
247
        }
248
        if (!account_get_list()) {
249
                account_edit_open();
250
                account_add();
251
        }
252
253
        account_set_missing_folder();
254
        folder_set_missing_folders();
255
        folderview_set(folderview);
256
257
        addressbook_read_file();
258
259
        inc_autocheck_timer_init(mainwin);
260
261
        remote_command_exec();
262
263
        gtk_main();
264
265
        return 0;
266
}
267
268
static void init_console(void)
269
{
270
#ifdef G_OS_WIN32
271
        gint fd;
272
        FILE *fp;
273
274
        if (!AllocConsole()) {
275
                g_warning("AllocConsole() failed\n");
276
                return;
277
        }
278
279
        fd = _open_osfhandle((glong)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
280
        _dup2(fd, 1);
281
        fp = _fdopen(fd, "w");
282
        *stdout = *fp;
283
        setvbuf(stdout, NULL, _IONBF, 0);
284
        fd = _open_osfhandle((glong)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT);
285
        _dup2(fd, 2);
286
        fp = _fdopen(fd, "w");
287
        *stderr = *fp;
288
        setvbuf(stderr, NULL, _IONBF, 0);
289
#endif
290
}
291
292
static void cleanup_console(void)
293
{
294
#ifdef G_OS_WIN32
295
        FreeConsole();
296
#endif
297
}
298
299
static void parse_cmd_opt(int argc, char *argv[])
300
{
301
        gint i;
302
303
        for (i = 1; i < argc; i++) {
304
                if (!strncmp(argv[i], "--debug", 7)) {
305
                        init_console();
306
                        set_debug_mode(TRUE);
307
                } else if (!strncmp(argv[i], "--receive-all", 13))
308
                        cmd.receive_all = TRUE;
309
                else if (!strncmp(argv[i], "--receive", 9))
310
                        cmd.receive = TRUE;
311
                else if (!strncmp(argv[i], "--compose", 9)) {
312
                        const gchar *p = argv[i + 1];
313
314
                        cmd.compose = TRUE;
315
                        cmd.compose_mailto = NULL;
316
                        if (p && *p != '\0' && *p != '-') {
317
                                if (!strncmp(p, "mailto:", 7))
318
                                        cmd.compose_mailto = p + 7;
319
                                else
320
                                        cmd.compose_mailto = p;
321
                                i++;
322
                        }
323
                } else if (!strncmp(argv[i], "--attach", 8)) {
324
                        const gchar *p = argv[i + 1];
325
                        gchar *file;
326
327
                        while (p && *p != '\0' && *p != '-') {
328
                                if (!cmd.attach_files)
329
                                        cmd.attach_files = g_ptr_array_new();
330
                                if (*p != G_DIR_SEPARATOR)
331
                                        file = g_strconcat(get_startup_dir(),
332
                                                           G_DIR_SEPARATOR_S,
333
                                                           p, NULL);
334
                                else
335
                                        file = g_strdup(p);
336
                                g_ptr_array_add(cmd.attach_files, file);
337
                                i++;
338
                                p = argv[i + 1];
339
                        }
340
                } else if (!strncmp(argv[i], "--send", 6)) {
341
                        cmd.send = TRUE;
342
                } else if (!strncmp(argv[i], "--version", 9)) {
343
                        puts("Sylpheed version " VERSION);
344
                        exit(0);
345
                } else if (!strncmp(argv[i], "--status-full", 13)) {
346
                        const gchar *p = argv[i + 1];
347
348
                        cmd.status_full = TRUE;
349
                        while (p && *p != '\0' && *p != '-') {
350
                                if (!cmd.status_full_folders)
351
                                        cmd.status_full_folders =
352
                                                g_ptr_array_new();
353
                                g_ptr_array_add(cmd.status_full_folders,
354
                                                g_strdup(p));
355
                                i++;
356
                                p = argv[i + 1];
357
                        }
358
                } else if (!strncmp(argv[i], "--status", 8)) {
359
                        const gchar *p = argv[i + 1];
360
361
                        cmd.status = TRUE;
362
                        while (p && *p != '\0' && *p != '-') {
363
                                if (!cmd.status_folders)
364
                                        cmd.status_folders = g_ptr_array_new();
365
                                g_ptr_array_add(cmd.status_folders,
366
                                                g_strdup(p));
367
                                i++;
368
                                p = argv[i + 1];
369
                        }
370
                } else if (!strncmp(argv[i], "--configdir", 11)) {
371
                        const gchar *p = argv[i + 1];
372
373
                        if (p && *p != '\0' && *p != '-') {
374
                                /* this must only be done at startup */
375
#ifdef G_OS_WIN32
376
                                gchar *utf8dir;
377
378
                                utf8dir = g_locale_to_utf8
379
                                        (p, -1, NULL, NULL, NULL);
380
                                if (utf8dir) {
381
                                        set_rc_dir(utf8dir);
382
                                        g_free(utf8dir);
383
                                } else
384
                                        set_rc_dir(p);
385
#else
386
                                set_rc_dir(p);
387
#endif
388
                                cmd.configdir = TRUE;
389
                                i++;
390
                        }
391
                } else if (!strncmp(argv[i], "--exit", 6)) {
392
                        cmd.exit = TRUE;
393
                } else if (!strncmp(argv[i], "--help", 6)) {
394
                        init_console();
395
396
                        g_print(_("Usage: %s [OPTION]...\n"),
397
                                g_basename(argv[0]));
398
399
                        g_print("%s\n", _("  --compose [address]    open composition window"));
400
                        g_print("%s\n", _("  --attach file1 [file2]...\n"
401
                                "                         open composition window with specified files\n"
402
                                "                         attached"));
403
                        g_print("%s\n", _("  --receive              receive new messages"));
404
                        g_print("%s\n", _("  --receive-all          receive new messages of all accounts"));
405
                        g_print("%s\n", _("  --send                 send all queued messages"));
406
                        g_print("%s\n", _("  --status [folder]...   show the total number of messages"));
407
                        g_print("%s\n", _("  --status-full [folder]...\n"
408
                                "                         show the status of each folder"));
409
                        g_print("%s\n", _("  --configdir dirname    specify directory which stores configuration files"));
410
                        g_print("%s\n", _("  --exit                 exit Sylpheed"));
411
                        g_print("%s\n", _("  --debug                debug mode"));
412
                        g_print("%s\n", _("  --help                 display this help and exit"));
413
                        g_print("%s\n", _("  --version              output version information and exit"));
414
415
#ifdef G_OS_WIN32
416
                        g_print("\n");
417
                        g_print(_("Press any key..."));
418
                        _getch();
419
#endif
420
421
                        cleanup_console();
422
                        exit(1);
423
                }
424
        }
425
426
        if (cmd.attach_files && cmd.compose == FALSE) {
427
                cmd.compose = TRUE;
428
                cmd.compose_mailto = NULL;
429
        }
430
}
431
432
static gint get_queued_message_num(void)
433
{
434
        FolderItem *queue;
435
436
        queue = folder_get_default_queue();
437
        if (!queue) return -1;
438
439
        folder_item_scan(queue);
440
        return queue->total;
441
}
442
443
static void app_init(void)
444
{
445
#ifdef G_OS_WIN32
446
        gchar *newpath;
447
        const gchar *lang_env;
448
449
        /* disable locale variable such as "LANG=1041" */
450
451
#define DISABLE_DIGIT_LOCALE(envstr)                        \
452
{                                                        \
453
        lang_env = g_getenv(envstr);                        \
454
        if (lang_env && g_ascii_isdigit(lang_env[0]))        \
455
                g_unsetenv(envstr);                        \
456
}
457
458
        DISABLE_DIGIT_LOCALE("LC_ALL");
459
        DISABLE_DIGIT_LOCALE("LANG");
460
        DISABLE_DIGIT_LOCALE("LC_CTYPE");
461
        DISABLE_DIGIT_LOCALE("LC_MESSAGES");
462
463
#undef DISABLE_DIGIT_LOCALE
464
#endif
465
466
        setlocale(LC_ALL, "");
467
468
        prog_version = PROG_VERSION;
469
        set_startup_dir();
470
471
#ifdef G_OS_WIN32
472
        /* include startup directory into %PATH% for GSpawn */
473
        newpath = g_strconcat(get_startup_dir(), ";", g_getenv("PATH"), NULL);
474
        g_setenv("PATH", newpath, TRUE);
475
        g_free(newpath);
476
#endif
477
478
        if (g_path_is_absolute(LOCALEDIR))
479
                bindtextdomain(PACKAGE, LOCALEDIR);
480
        else {
481
                gchar *locale_dir;
482
483
                locale_dir = g_strconcat(get_startup_dir(), G_DIR_SEPARATOR_S,
484
                                         LOCALEDIR, NULL);
485
#ifdef G_OS_WIN32
486
                {
487
                        gchar *locale_dir_;
488
489
                        locale_dir_ = g_locale_from_utf8(locale_dir, -1,
490
                                                         NULL, NULL, NULL);
491
                        if (locale_dir_) {
492
                                g_free(locale_dir);
493
                                locale_dir = locale_dir_;
494
                        }
495
                }
496
#endif
497
                bindtextdomain(PACKAGE, locale_dir);
498
                g_free(locale_dir);
499
        }
500
501
        bind_textdomain_codeset(PACKAGE, CS_UTF_8);
502
        textdomain(PACKAGE);
503
504
        sock_init();
505
#if USE_SSL
506
        ssl_init();
507
#endif
508
509
#ifdef G_OS_UNIX
510
        /* ignore SIGPIPE signal for preventing sudden death of program */
511
        signal(SIGPIPE, SIG_IGN);
512
#endif
513
}
514
515
static void parse_gtkrc_files(void)
516
{
517
        gchar *userrc;
518
519
        /* parse gtkrc files */
520
        userrc = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S, ".gtkrc-2.0",
521
                             NULL);
522
        gtk_rc_parse(userrc);
523
        g_free(userrc);
524
        userrc = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S, ".gtk",
525
                             G_DIR_SEPARATOR_S, "gtkrc-2.0", NULL);
526
        gtk_rc_parse(userrc);
527
        g_free(userrc);
528
        userrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, "gtkrc", NULL);
529
        gtk_rc_parse(userrc);
530
        g_free(userrc);
531
532
        userrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MENU_RC, NULL);
533
        gtk_accel_map_load(userrc);
534
        g_free(userrc);
535
}
536
537
static void setup_rc_dir(void)
538
{
539
#ifndef G_OS_WIN32
540
        CHDIR_EXIT_IF_FAIL(get_home_dir(), 1);
541
542
        /* backup if old rc file exists */
543
        if (!cmd.configdir && is_file_exist(RC_DIR)) {
544
                if (rename_force(RC_DIR, RC_DIR ".bak") < 0)
545
                        FILE_OP_ERROR(RC_DIR, "rename");
546
        }
547
548
        /* migration from ~/.sylpheed to ~/.sylpheed-2.0 */
549
        if (!cmd.configdir && !is_dir_exist(RC_DIR)) {
550
                const gchar *envstr;
551
                AlertValue val;
552
553
                /* check for filename encoding */
554
                if (conv_get_locale_charset() != C_UTF_8) {
555
                        envstr = g_getenv("G_FILENAME_ENCODING");
556
                        if (!envstr)
557
                                envstr = g_getenv("G_BROKEN_FILENAMES");
558
                        if (!envstr) {
559
                                val = alertpanel(_("Filename encoding"),
560
                                                 _("The locale encoding is not UTF-8, but the environmental variable G_FILENAME_ENCODING is not set.\n"
561
                                                   "If the locale encoding is used for file name or directory name, it will not work correctly.\n"
562
                                                   "In that case, you must set the following environmental variable (see README for detail):\n"
563
                                                   "\n"
564
                                                   "\tG_FILENAME_ENCODING=@locale\n"
565
                                                   "\n"
566
                                                   "Continue?"),
567
                                                 GTK_STOCK_OK, GTK_STOCK_QUIT,
568
                                                 NULL);
569
                                if (G_ALERTDEFAULT != val)
570
                                        exit(1);
571
                        }
572
                }
573
574
                if (make_dir(RC_DIR) < 0)
575
                        exit(1);
576
                if (is_dir_exist(OLD_RC_DIR))
577
                        migrate_old_config();
578
        }
579
#endif /* !G_OS_WIN32 */
580
581
        if (!is_dir_exist(get_rc_dir())) {
582
                if (make_dir_hier(get_rc_dir()) < 0)
583
                        exit(1);
584
        }
585
586
        MAKE_DIR_IF_NOT_EXIST(get_mail_base_dir());
587
588
        CHDIR_EXIT_IF_FAIL(get_rc_dir(), 1);
589
590
        MAKE_DIR_IF_NOT_EXIST(get_imap_cache_dir());
591
        MAKE_DIR_IF_NOT_EXIST(get_news_cache_dir());
592
        MAKE_DIR_IF_NOT_EXIST(get_mime_tmp_dir());
593
        MAKE_DIR_IF_NOT_EXIST(get_tmp_dir());
594
        MAKE_DIR_IF_NOT_EXIST(UIDL_DIR);
595
596
        /* remove temporary files */
597
        remove_all_files(get_tmp_dir());
598
        remove_all_files(get_mime_tmp_dir());
599
}
600
601
void app_will_exit(gboolean force)
602
{
603
        MainWindow *mainwin;
604
        gchar *filename;
605
        static gboolean on_exit = FALSE;
606
        GList *cur;
607
608
        if (on_exit)
609
                return;
610
        on_exit = TRUE;
611
612
        mainwin = main_window_get();
613
614
        if (!force && compose_get_compose_list()) {
615
                if (alertpanel(_("Notice"),
616
                               _("Composing message exists. Really quit?"),
617
                               GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL)
618
                    != G_ALERTDEFAULT) {
619
                        on_exit = FALSE;
620
                        return;
621
                }
622
                manage_window_focus_in(mainwin->window, NULL, NULL);
623
        }
624
625
        if (!force &&
626
            prefs_common.warn_queued_on_exit && get_queued_message_num() > 0) {
627
                if (alertpanel(_("Queued messages"),
628
                               _("Some unsent messages are queued. Exit now?"),
629
                               GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL)
630
                    != G_ALERTDEFAULT) {
631
                        on_exit = FALSE;
632
                        return;
633
                }
634
                manage_window_focus_in(mainwin->window, NULL, NULL);
635
        }
636
637
        inc_autocheck_timer_remove();
638
639
        if (prefs_common.clean_on_exit)
640
                main_window_empty_trash(mainwin,
641
                                        !force && prefs_common.ask_on_clean);
642
643
        for (cur = account_get_list(); cur != NULL; cur = cur->next) {
644
                PrefsAccount *ac = (PrefsAccount *)cur->data;
645
                if (ac->protocol == A_IMAP4 && ac->imap_clear_cache_on_exit &&
646
                    ac->folder)
647
                        procmsg_remove_all_cached_messages(FOLDER(ac->folder));
648
        }
649
650
        /* save all state before exiting */
651
        folder_write_list();
652
        summary_write_cache(mainwin->summaryview);
653
654
        main_window_get_size(mainwin);
655
        main_window_get_position(mainwin);
656
        prefs_common_write_config();
657
        filter_write_config();
658
        account_write_config_all();
659
        addressbook_export_to_file();
660
661
        filename = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MENU_RC, NULL);
662
        gtk_accel_map_save(filename);
663
        g_free(filename);
664
665
        /* remove temporary files */
666
        remove_all_files(get_tmp_dir());
667
        remove_all_files(get_mime_tmp_dir());
668
669
        set_log_handlers(FALSE);
670
        close_log_file();
671
        lock_socket_remove();
672
673
#if USE_SSL
674
        ssl_done();
675
#endif
676
677
        cleanup_console();
678
        sock_cleanup();
679
680
        if (gtk_main_level() > 0)
681
                gtk_main_quit();
682
}
683
684
#if 0
685
#if USE_GPGME
686
static void idle_function_for_gpgme(void)
687
{
688
        while (gtk_events_pending())
689
                gtk_main_iteration();
690
}
691
#endif /* USE_GPGME */
692
#endif /* 0 */
693
694
static void check_gpg(void)
695
{
696
#if USE_GPGME
697
        if (gpgme_check_version("0.4.5") &&
698
            !gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP)) {
699
                /* Also does some gpgme init */
700
                gpgme_engine_info_t engineInfo;
701
702
                gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
703
                gpgme_set_locale(NULL, LC_MESSAGES,
704
                                 setlocale(LC_MESSAGES, NULL));
705
706
                if (!gpgme_get_engine_info(&engineInfo)) {
707
                        while (engineInfo) {
708
                                debug_print("GpgME Protocol: %s\n      Version: %s\n",
709
                                            gpgme_get_protocol_name
710
                                                (engineInfo->protocol),
711
                                            engineInfo->version ?
712
                                            engineInfo->version : "(unknown)");
713
                                engineInfo = engineInfo->next;
714
                        }
715
                }
716
717
                procmsg_set_decrypt_message_func
718
                        (rfc2015_open_message_decrypted);
719
        } else {
720
                rfc2015_disable_all();
721
722
                if (prefs_common.gpg_warning) {
723
                        AlertValue val;
724
725
                        val = alertpanel_message_with_disable
726
                                (_("Warning"),
727
                                 _("GnuPG is not installed properly, or its version is too old.\n"
728
                                   "OpenPGP support disabled."),
729
                                 ALERT_WARNING);
730
                        if (val & G_ALERTDISABLE)
731
                                prefs_common.gpg_warning = FALSE;
732
                }
733
        }
734
        /* FIXME: This function went away.  We can either block until gpgme
735
         * operations finish (currently implemented) or register callbacks
736
         * with the gtk main loop via the gpgme io callback interface instead.
737
         *
738
         * gpgme_register_idle(idle_function_for_gpgme);
739
         */
740
#endif
741
}
742
743
static void default_log_func(const gchar *log_domain, GLogLevelFlags log_level,
744
                             const gchar *message, gpointer user_data)
745
{
746
        gchar *prefix = "";
747
        gchar *file_prefix = "";
748
        LogType level = LOG_NORMAL;
749
        gchar *str;
750
        const gchar *message_;
751
752
        switch (log_level) {
753
        case G_LOG_LEVEL_ERROR:
754
                prefix = "ERROR";
755
                file_prefix = "*** ";
756
                level = LOG_ERROR;
757
                break;
758
        case G_LOG_LEVEL_CRITICAL:
759
                prefix = "CRITICAL";
760
                file_prefix = "** ";
761
                level = LOG_WARN;
762
                break;
763
        case G_LOG_LEVEL_WARNING:
764
                prefix = "WARNING";
765
                file_prefix = "** ";
766
                level = LOG_WARN;
767
                break;
768
        case G_LOG_LEVEL_MESSAGE:
769
                prefix = "Message";
770
                file_prefix = "* ";
771
                level = LOG_MSG;
772
                break;
773
        case G_LOG_LEVEL_INFO:
774
                prefix = "INFO";
775
                file_prefix = "* ";
776
                level = LOG_MSG;
777
                break;
778
        case G_LOG_LEVEL_DEBUG:
779
                prefix = "DEBUG";
780
                break;
781
        default:
782
                prefix = "LOG";
783
                break;
784
        }
785
786
        if (!message)
787
                message_ = "(NULL) message";
788
        else
789
                message_ = message;
790
        if (log_domain)
791
                str = g_strconcat(log_domain, "-", prefix, ": ", message_, "\n",
792
                                  NULL);
793
        else
794
                str = g_strconcat(prefix, ": ", message_, "\n", NULL);
795
        log_window_append(str, level);
796
        log_write(str, file_prefix);
797
        g_free(str);
798
799
        g_log_default_handler(log_domain, log_level, message, user_data);
800
}
801
802
static void set_log_handlers(gboolean enable)
803
{
804
#if GLIB_CHECK_VERSION(2, 6, 0)
805
        if (enable)
806
                g_log_set_default_handler(default_log_func, NULL);
807
        else
808
                g_log_set_default_handler(g_log_default_handler, NULL);
809
#else
810
        static guint handler_id[4] = {0, 0, 0, 0};
811
812
        if (enable) {
813
                handler_id[0] = g_log_set_handler
814
                        ("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
815
                         | G_LOG_FLAG_RECURSION, default_log_func, NULL);
816
                handler_id[1] = g_log_set_handler
817
                        ("Gtk", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
818
                         | G_LOG_FLAG_RECURSION, default_log_func, NULL);
819
                handler_id[2] = g_log_set_handler
820
                        ("LibSylph", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
821
                         | G_LOG_FLAG_RECURSION, default_log_func, NULL);
822
                handler_id[3] = g_log_set_handler
823
                        ("Sylpheed", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
824
                         | G_LOG_FLAG_RECURSION, default_log_func, NULL);
825
        } else {
826
                g_log_remove_handler("GLib", handler_id[0]);
827
                g_log_remove_handler("Gtk", handler_id[1]);
828
                g_log_remove_handler("LibSylph", handler_id[2]);
829
                g_log_remove_handler("Sylpheed", handler_id[3]);
830
                handler_id[0] = 0;
831
                handler_id[1] = 0;
832
                handler_id[2] = 0;
833
                handler_id[3] = 0;
834
        }
835
#endif
836
}
837
838
static gchar *get_socket_name(void)
839
{
840
        static gchar *filename = NULL;
841
842
        if (filename == NULL) {
843
                filename = g_strdup_printf("%s%csylpheed-%d",
844
                                           g_get_tmp_dir(), G_DIR_SEPARATOR,
845
#if HAVE_GETUID
846
                                           getuid());
847
#else
848
                                           0);
849
#endif
850
        }
851
852
        return filename;
853
}
854
855
static gint prohibit_duplicate_launch(void)
856
{
857
        gint sock;
858
859
#ifdef G_OS_WIN32
860
        HANDLE hmutex;
861
862
        hmutex = CreateMutexA(NULL, FALSE, "Sylpheed");
863
        if (!hmutex) {
864
                g_warning("cannot create Mutex\n");
865
                return -1;
866
        }
867
        if (GetLastError() != ERROR_ALREADY_EXISTS) {
868
                sock = fd_open_inet(REMOTE_CMD_PORT);
869
                if (sock < 0)
870
                        return 0;
871
                return sock;
872
        }
873
874
        sock = fd_connect_inet(REMOTE_CMD_PORT);
875
        if (sock < 0)
876
                return -1;
877
#else
878
        gchar *path;
879
880
        path = get_socket_name();
881
        sock = fd_connect_unix(path);
882
        if (sock < 0) {
883
                g_unlink(path);
884
                return fd_open_unix(path);
885
        }
886
#endif
887
888
        /* remote command mode */
889
890
        debug_print(_("another Sylpheed is already running.\n"));
891
892
        if (cmd.receive_all)
893
                fd_write_all(sock, "receive_all\n", 12);
894
        else if (cmd.receive)
895
                fd_write_all(sock, "receive\n", 8);
896
        else if (cmd.compose && cmd.attach_files) {
897
                gchar *str, *compose_str;
898
                gint i;
899
900
                if (cmd.compose_mailto)
901
                        compose_str = g_strdup_printf("compose_attach %s\n",
902
                                                      cmd.compose_mailto);
903
                else
904
                        compose_str = g_strdup("compose_attach\n");
905
906
                fd_write_all(sock, compose_str, strlen(compose_str));
907
                g_free(compose_str);
908
909
                for (i = 0; i < cmd.attach_files->len; i++) {
910
                        str = g_ptr_array_index(cmd.attach_files, i);
911
                        fd_write_all(sock, str, strlen(str));
912
                        fd_write_all(sock, "\n", 1);
913
                }
914
915
                fd_write_all(sock, ".\n", 2);
916
        } else if (cmd.compose) {
917
                gchar *compose_str;
918
919
                if (cmd.compose_mailto)
920
                        compose_str = g_strdup_printf
921
                                ("compose %s\n", cmd.compose_mailto);
922
                else
923
                        compose_str = g_strdup("compose\n");
924
925
                fd_write_all(sock, compose_str, strlen(compose_str));
926
                g_free(compose_str);
927
        } else if (cmd.send) {
928
                fd_write_all(sock, "send\n", 5);
929
        } else if (cmd.status || cmd.status_full) {
930
                gchar buf[BUFFSIZE];
931
                gint i;
932
                const gchar *command;
933
                GPtrArray *folders;
934
                gchar *folder;
935
936
                command = cmd.status_full ? "status-full\n" : "status\n";
937
                folders = cmd.status_full ? cmd.status_full_folders :
938
                        cmd.status_folders;
939
940
                fd_write_all(sock, command, strlen(command));
941
                for (i = 0; folders && i < folders->len; ++i) {
942
                        folder = g_ptr_array_index(folders, i);
943
                        fd_write_all(sock, folder, strlen(folder));
944
                        fd_write_all(sock, "\n", 1);
945
                }
946
                fd_write_all(sock, ".\n", 2);
947
                for (;;) {
948
                        fd_gets(sock, buf, sizeof(buf));
949
                        if (!strncmp(buf, ".\n", 2)) break;
950
                        fputs(buf, stdout);
951
                }
952
        } else if (cmd.exit) {
953
                fd_write_all(sock, "exit\n", 5);
954
        } else {
955
#ifdef G_OS_WIN32
956
                HWND hwnd;
957
958
                fd_write_all(sock, "popup\n", 6);
959
                if (fd_read(sock, (gchar *)&hwnd, sizeof(hwnd)) == sizeof(hwnd))
960
                        SetForegroundWindow(hwnd);
961
#else
962
                fd_write_all(sock, "popup\n", 6);
963
#endif
964
        }
965
966
        fd_close(sock);
967
        return -1;
968
}
969
970
static gint lock_socket_remove(void)
971
{
972
#ifndef G_OS_WIN32
973
        gchar *filename;
974
#endif
975
976
        if (lock_socket < 0) return -1;
977
978
        if (lock_socket_tag > 0)
979
                g_source_remove(lock_socket_tag);
980
        if (lock_ch) {
981
                g_io_channel_shutdown(lock_ch, FALSE, NULL);
982
                g_io_channel_unref(lock_ch);
983
                lock_ch = NULL;
984
        }
985
986
#ifndef G_OS_WIN32
987
        filename = get_socket_name();
988
        g_unlink(filename);
989
#endif
990
991
        return 0;
992
}
993
994
static GPtrArray *get_folder_item_list(gint sock)
995
{
996
        gchar buf[BUFFSIZE];
997
        FolderItem *item;
998
        GPtrArray *folders = NULL;
999
1000
        for (;;) {
1001
                fd_gets(sock, buf, sizeof(buf));
1002
                if (!strncmp(buf, ".\n", 2)) break;
1003
                strretchomp(buf);
1004
                if (!folders) folders = g_ptr_array_new();
1005
                item = folder_find_item_from_identifier(buf);
1006
                if (item)
1007
                        g_ptr_array_add(folders, item);
1008
                else
1009
                        g_warning("no such folder: %s\n", buf);
1010
        }
1011
1012
        return folders;
1013
}
1014
1015
static gboolean lock_socket_input_cb(GIOChannel *source, GIOCondition condition,
1016
                                     gpointer data)
1017
{
1018
        MainWindow *mainwin = (MainWindow *)data;
1019
        gint fd, sock;
1020
        gchar buf[BUFFSIZE];
1021
1022
        fd = g_io_channel_unix_get_fd(source);
1023
        sock = fd_accept(fd);
1024
        fd_gets(sock, buf, sizeof(buf));
1025
1026
        if (!strncmp(buf, "popup", 5)) {
1027
#ifdef G_OS_WIN32
1028
                HWND hwnd;
1029
1030
                hwnd = (HWND)gdk_win32_drawable_get_handle
1031
                        (GDK_DRAWABLE(mainwin->window->window));
1032
                fd_write(sock, (gchar *)&hwnd, sizeof(hwnd));
1033
                if (mainwin->window_hidden)
1034
                        main_window_popup(mainwin);
1035
#else
1036
                main_window_popup(mainwin);
1037
#endif
1038
        } else if (!strncmp(buf, "receive_all", 11)) {
1039
                main_window_popup(mainwin);
1040
                inc_all_account_mail(mainwin, FALSE);
1041
        } else if (!strncmp(buf, "receive", 7)) {
1042
                main_window_popup(mainwin);
1043
                inc_mail(mainwin);
1044
        } else if (!strncmp(buf, "compose_attach", 14)) {
1045
                GPtrArray *files;
1046
                gchar *mailto;
1047
1048
                mailto = g_strdup(buf + strlen("compose_attach") + 1);
1049
                files = g_ptr_array_new();
1050
                while (fd_gets(sock, buf, sizeof(buf)) > 0) {
1051
                        if (buf[0] == '.' && buf[1] == '\n') break;
1052
                        strretchomp(buf);
1053
                        g_ptr_array_add(files, g_strdup(buf));
1054
                }
1055
                open_compose_new(mailto, files);
1056
                ptr_array_free_strings(files);
1057
                g_ptr_array_free(files, TRUE);
1058
                g_free(mailto);
1059
        } else if (!strncmp(buf, "compose", 7)) {
1060
                open_compose_new(buf + strlen("compose") + 1, NULL);
1061
        } else if (!strncmp(buf, "send", 4)) {
1062
                send_queue();
1063
        } else if (!strncmp(buf, "status-full", 11) ||
1064
                   !strncmp(buf, "status", 6)) {
1065
                gchar *status;
1066
                GPtrArray *folders;
1067
1068
                folders = get_folder_item_list(sock);
1069
                status = folder_get_status
1070
                        (folders, !strncmp(buf, "status-full", 11));
1071
                fd_write_all(sock, status, strlen(status));
1072
                fd_write_all(sock, ".\n", 2);
1073
                g_free(status);
1074
                if (folders) g_ptr_array_free(folders, TRUE);
1075
        } else if (!strncmp(buf, "exit", 4)) {
1076
                app_will_exit(TRUE);
1077
        }
1078
1079
        fd_close(sock);
1080
1081
        return TRUE;
1082
}
1083
1084
static void remote_command_exec(void)
1085
{
1086
        MainWindow *mainwin;
1087
1088
        mainwin = main_window_get();
1089
1090
        if (cmd.receive_all)
1091
                inc_all_account_mail(mainwin, FALSE);
1092
        else if (prefs_common.chk_on_startup)
1093
                inc_all_account_mail(mainwin, TRUE);
1094
        else if (cmd.receive)
1095
                inc_mail(mainwin);
1096
1097
        if (cmd.compose)
1098
                open_compose_new(cmd.compose_mailto, cmd.attach_files);
1099
        if (cmd.attach_files) {
1100
                ptr_array_free_strings(cmd.attach_files);
1101
                g_ptr_array_free(cmd.attach_files, TRUE);
1102
                cmd.attach_files = NULL;
1103
        }
1104
        if (cmd.send)
1105
                send_queue();
1106
        if (cmd.status_folders) {
1107
                g_ptr_array_free(cmd.status_folders, TRUE);
1108
                cmd.status_folders = NULL;
1109
        }
1110
        if (cmd.status_full_folders) {
1111
                g_ptr_array_free(cmd.status_full_folders, TRUE);
1112
                cmd.status_full_folders = NULL;
1113
        }
1114
        if (cmd.exit) {
1115
                app_will_exit(TRUE);
1116
                exit(0);
1117
        }
1118
}
1119
1120
static void migrate_old_config(void)
1121
{
1122
        GDir *dir;
1123
        const gchar *dir_name;
1124
        GPatternSpec *pspec;
1125
1126
        if (alertpanel(_("Migration of configuration"),
1127
                       _("The previous version of configuration found.\n"
1128
                         "Do you want to migrate it?"),
1129
                       GTK_STOCK_YES, GTK_STOCK_NO, NULL) != G_ALERTDEFAULT)
1130
                return;
1131
1132
        debug_print("Migrating old configuration...\n");
1133
1134
#define COPY_FILE(rcfile)                                                \
1135
        if (is_file_exist(OLD_RC_DIR G_DIR_SEPARATOR_S rcfile)) {        \
1136
                conv_copy_file(OLD_RC_DIR G_DIR_SEPARATOR_S rcfile,        \
1137
                               RC_DIR G_DIR_SEPARATOR_S rcfile,                \
1138
                               conv_get_locale_charset_str());                \
1139
        }
1140
1141
        COPY_FILE(ACCOUNT_RC);
1142
        COPY_FILE(ACTIONS_RC);
1143
        COPY_FILE(COMMON_RC);
1144
        COPY_FILE(CUSTOM_HEADER_RC);
1145
        COPY_FILE(DISPLAY_HEADER_RC);
1146
        COPY_FILE(FILTER_HEADER_RC);
1147
        COPY_FILE(COMMAND_HISTORY);
1148
1149
#undef COPY_FILE
1150
1151
        if (is_file_exist(OLD_RC_DIR G_DIR_SEPARATOR_S FILTER_LIST))
1152
                copy_file(OLD_RC_DIR G_DIR_SEPARATOR_S FILTER_LIST,
1153
                          RC_DIR G_DIR_SEPARATOR_S FILTER_LIST, FALSE);
1154
        if (is_file_exist(OLD_RC_DIR G_DIR_SEPARATOR_S FOLDER_LIST))
1155
                copy_file(OLD_RC_DIR G_DIR_SEPARATOR_S FOLDER_LIST,
1156
                          RC_DIR G_DIR_SEPARATOR_S FOLDER_LIST, FALSE);
1157
        if (is_file_exist(OLD_RC_DIR G_DIR_SEPARATOR_S "mime.types"))
1158
                copy_file(OLD_RC_DIR G_DIR_SEPARATOR_S "mime.types",
1159
                          RC_DIR G_DIR_SEPARATOR_S "mime.types", FALSE);
1160
1161
        if (is_dir_exist(OLD_RC_DIR G_DIR_SEPARATOR_S TEMPLATE_DIR))
1162
                conv_copy_dir(OLD_RC_DIR G_DIR_SEPARATOR_S TEMPLATE_DIR,
1163
                              RC_DIR G_DIR_SEPARATOR_S TEMPLATE_DIR,
1164
                              conv_get_locale_charset_str());
1165
        if (is_dir_exist(OLD_RC_DIR G_DIR_SEPARATOR_S UIDL_DIR))
1166
                copy_dir(OLD_RC_DIR G_DIR_SEPARATOR_S UIDL_DIR,
1167
                         RC_DIR G_DIR_SEPARATOR_S UIDL_DIR);
1168
1169
        if (!is_file_exist(OLD_RC_DIR G_DIR_SEPARATOR_S ADDRESSBOOK_INDEX_FILE))
1170
                return;
1171
1172
        if ((dir = g_dir_open(OLD_RC_DIR, 0, NULL)) == NULL) {
1173
                g_warning("failed to open directory: %s\n", OLD_RC_DIR);
1174
                return;
1175
        }
1176
1177
        pspec = g_pattern_spec_new("addrbook-*.xml");
1178
1179
        while ((dir_name = g_dir_read_name(dir)) != NULL) {
1180
                if (g_pattern_match_string(pspec, dir_name)) {
1181
                        gchar *old_file;
1182
                        gchar *new_file;
1183
1184
                        old_file = g_strconcat(OLD_RC_DIR G_DIR_SEPARATOR_S,
1185
                                               dir_name, NULL);
1186
                        new_file = g_strconcat(RC_DIR G_DIR_SEPARATOR_S,
1187
                                               dir_name, NULL);
1188
                        copy_file(old_file, new_file, FALSE);
1189
                        g_free(new_file);
1190
                        g_free(old_file);
1191
                }
1192
        }
1193
1194
        g_pattern_spec_free(pspec);
1195
        g_dir_close(dir);
1196
}
1197
1198
static void open_compose_new(const gchar *address, GPtrArray *attach_files)
1199
{
1200
        gchar *utf8addr = NULL;
1201
#ifdef G_OS_WIN32
1202
        GPtrArray *utf8files = NULL;
1203
#endif
1204
1205
        if (address) {
1206
                utf8addr = g_locale_to_utf8(address, -1, NULL, NULL, NULL);
1207
                if (utf8addr)
1208
                        g_strstrip(utf8addr);
1209
        }
1210
1211
#ifdef G_OS_WIN32
1212
        if (attach_files) {
1213
                gint i;
1214
                gchar *file, *utf8file;
1215
1216
                utf8files = g_ptr_array_new();
1217
                for (i = 0; i < attach_files->len; i++) {
1218
                        file = g_ptr_array_index(attach_files, i);
1219
                        utf8file = g_locale_to_utf8(file, -1, NULL, NULL, NULL);
1220
                        if (utf8file)
1221
                                g_ptr_array_add(utf8files, utf8file);
1222
                }
1223
        }
1224
1225
        compose_new(NULL, NULL, utf8addr, utf8files);
1226
        if (utf8files) {
1227
                ptr_array_free_strings(utf8files);
1228
                g_ptr_array_free(utf8files, TRUE);
1229
        }
1230
#else
1231
        compose_new(NULL, NULL, utf8addr, attach_files);
1232
#endif
1233
1234
        g_free(utf8addr);
1235
}
1236
1237
static void send_queue(void)
1238
{
1239
        GList *list;
1240
1241
        if (!main_window_toggle_online_if_offline(main_window_get()))
1242
                return;
1243
1244
        for (list = folder_get_list(); list != NULL; list = list->next) {
1245
                Folder *folder = list->data;
1246
1247
                if (folder->queue) {
1248
                        gint ret;
1249
1250
                        ret = send_message_queue_all(folder->queue,
1251
                                                     prefs_common.savemsg,
1252
                                                     prefs_common.filter_sent);
1253
                        statusbar_pop_all();
1254
                        if (ret > 0)
1255
                                folder_item_scan(folder->queue);
1256
                }
1257
        }
1258
1259
        folderview_update_all_updated(TRUE);
1260
}