Statistics
| Revision:

root / src / main.c @ 940

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