diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 721 |
1 files changed, 721 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c new file mode 100644 index 00000000..0f46186a --- /dev/null +++ b/src/main.c @@ -0,0 +1,721 @@ +/* + * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client + * Copyright (C) 1999-2004 Hiroyuki Yamamoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "defs.h" + +#include <glib.h> +#include <gtk/gtkmain.h> +#include <gtk/gtkrc.h> + +#if HAVE_GDK_IMLIB +# include <gdk_imlib.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <time.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <signal.h> + +#if HAVE_LOCALE_H +# include <locale.h> +#endif + +#if USE_GPGME +# include <gpgme.h> +#endif + +#include "intl.h" +#include "main.h" +#include "mainwindow.h" +#include "folderview.h" +#include "summaryview.h" +#include "prefs_common.h" +#include "prefs_account.h" +#include "prefs_actions.h" +#include "prefs_display_header.h" +#include "account.h" +#include "procmsg.h" +#include "filter.h" +#include "inc.h" +#include "import.h" +#include "manage_window.h" +#include "alertpanel.h" +#include "statusbar.h" +#include "addressbook.h" +#include "compose.h" +#include "folder.h" +#include "setup.h" +#include "utils.h" +#include "gtkutils.h" +#include "socket.h" + +#if USE_GPGME +# include "rfc2015.h" +#endif +#if USE_SSL +# include "ssl.h" +#endif + +#include "version.h" + +gchar *prog_version; +gchar *startup_dir; +gboolean debug_mode = FALSE; + +static gint lock_socket = -1; +static gint lock_socket_tag = 0; + +static struct RemoteCmd { + gboolean receive; + gboolean receive_all; + gboolean compose; + const gchar *compose_mailto; + GPtrArray *attach_files; + gboolean status; + gboolean status_full; + GPtrArray *status_folders; + GPtrArray *status_full_folders; + gboolean send; +} cmd; + +static void parse_cmd_opt(int argc, char *argv[]); + +#if USE_GPGME +static void idle_function_for_gpgme(void); +#endif /* USE_GPGME */ + +static gint prohibit_duplicate_launch (void); +static gint lock_socket_remove (void); +static void lock_socket_input_cb (gpointer data, + gint source, + GdkInputCondition condition); +static gchar *get_socket_name (void); + +static void open_compose_new (const gchar *address, + GPtrArray *attach_files); + +static void send_queue (void); + +#if 0 +/* for gettext */ +_("File `%s' already exists.\n" + "Can't create folder.") +#endif + +#define MAKE_DIR_IF_NOT_EXIST(dir) \ +{ \ + if (!is_dir_exist(dir)) { \ + if (is_file_exist(dir)) { \ + alertpanel_warning \ + (_("File `%s' already exists.\n" \ + "Can't create folder."), \ + dir); \ + return 1; \ + } \ + if (make_dir(dir) < 0) \ + return 1; \ + } \ +} + +int main(int argc, char *argv[]) +{ + gchar *userrc; + MainWindow *mainwin; + FolderView *folderview; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + bind_textdomain_codeset(PACKAGE, CS_UTF_8); + textdomain(PACKAGE); + + prog_version = PROG_VERSION; + startup_dir = g_get_current_dir(); + + parse_cmd_opt(argc, argv); + + /* check and create unix domain socket for remote operation */ + lock_socket = prohibit_duplicate_launch(); + if (lock_socket < 0) return 0; + + if (cmd.status || cmd.status_full) { + puts("0 Sylpheed not running."); + lock_socket_remove(); + return 0; + } + + gtk_set_locale(); + gtk_init(&argc, &argv); + + gdk_rgb_init(); + gtk_widget_set_default_colormap(gdk_rgb_get_cmap()); + gtk_widget_set_default_visual(gdk_rgb_get_visual()); + +#if USE_THREADS || USE_LDAP + g_thread_init(NULL); + if (!g_thread_supported()) + g_error(_("g_thread is not supported by glib.\n")); +#endif + +#if HAVE_GDK_IMLIB + gdk_imlib_init(); + gtk_widget_push_visual(gdk_imlib_get_visual()); + gtk_widget_push_colormap(gdk_imlib_get_colormap()); +#endif + +#if USE_SSL + ssl_init(); +#endif + + srandom((gint)time(NULL)); + + /* parse gtkrc files */ + userrc = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S, ".gtkrc-2.0", + NULL); + gtk_rc_parse(userrc); + g_free(userrc); + userrc = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S, ".gtk", + G_DIR_SEPARATOR_S, "gtkrc-2.0", NULL); + gtk_rc_parse(userrc); + g_free(userrc); + userrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, "gtkrc", NULL); + gtk_rc_parse(userrc); + g_free(userrc); + + userrc = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MENU_RC, NULL); + gtk_accel_map_load(userrc); + g_free(userrc); + + CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), 1); + + /* backup if old rc file exists */ + if (is_file_exist(RC_DIR)) { + if (rename(RC_DIR, RC_DIR ".bak") < 0) + FILE_OP_ERROR(RC_DIR, "rename"); + } + MAKE_DIR_IF_NOT_EXIST(RC_DIR); + MAKE_DIR_IF_NOT_EXIST(get_imap_cache_dir()); + MAKE_DIR_IF_NOT_EXIST(get_news_cache_dir()); + MAKE_DIR_IF_NOT_EXIST(get_mime_tmp_dir()); + MAKE_DIR_IF_NOT_EXIST(get_tmp_dir()); + MAKE_DIR_IF_NOT_EXIST(RC_DIR G_DIR_SEPARATOR_S "uidl"); + + if (is_file_exist(RC_DIR G_DIR_SEPARATOR_S "sylpheed.log")) { + if (rename(RC_DIR G_DIR_SEPARATOR_S "sylpheed.log", + RC_DIR G_DIR_SEPARATOR_S "sylpheed.log.bak") < 0) + FILE_OP_ERROR("sylpheed.log", "rename"); + } + set_log_file(RC_DIR G_DIR_SEPARATOR_S "sylpheed.log"); + + prefs_common_read_config(); + +#if USE_GPGME + if (gpgme_check_engine()) { /* Also does some gpgme init */ + rfc2015_disable_all(); + debug_print("gpgme_engine_version:\n%s\n", + gpgme_get_engine_info()); + + if (prefs_common.gpg_warning) { + AlertValue val; + + val = alertpanel_message_with_disable + (_("Warning"), + _("GnuPG is not installed properly, or its version is too old.\n" + "OpenPGP support disabled."), + ALERT_WARNING); + if (val & G_ALERTDISABLE) + prefs_common.gpg_warning = FALSE; + } + } + gpgme_register_idle(idle_function_for_gpgme); +#endif + + sock_set_io_timeout(prefs_common.io_timeout_secs); + + prefs_filter_read_config(); + prefs_actions_read_config(); + prefs_display_header_read_config(); + + gtkut_widget_init(); + + mainwin = main_window_create + (prefs_common.sep_folder | prefs_common.sep_msg << 1); + folderview = mainwin->folderview; + + /* register the callback of unix domain socket input */ + lock_socket_tag = gdk_input_add(lock_socket, + GDK_INPUT_READ | GDK_INPUT_EXCEPTION, + lock_socket_input_cb, + mainwin); + + account_read_config_all(); + + if (folder_read_list() < 0) { + setup(mainwin); + folder_write_list(); + } + if (!account_get_list()) { + account_edit_open(); + account_add(); + } + + account_set_missing_folder(); + folder_set_missing_folders(); + folderview_set(folderview); + + addressbook_read_file(); + + inc_autocheck_timer_init(mainwin); + + /* ignore SIGPIPE signal for preventing sudden death of program */ + signal(SIGPIPE, SIG_IGN); + + if (cmd.receive_all) + inc_all_account_mail(mainwin, FALSE); + else if (prefs_common.chk_on_startup) + inc_all_account_mail(mainwin, TRUE); + else if (cmd.receive) + inc_mail(mainwin); + else + gtk_widget_grab_focus(folderview->ctree); + + if (cmd.compose) + open_compose_new(cmd.compose_mailto, cmd.attach_files); + if (cmd.attach_files) { + ptr_array_free_strings(cmd.attach_files); + g_ptr_array_free(cmd.attach_files, TRUE); + cmd.attach_files = NULL; + } + if (cmd.send) + send_queue(); + if (cmd.status_folders) { + g_ptr_array_free(cmd.status_folders, TRUE); + cmd.status_folders = NULL; + } + if (cmd.status_full_folders) { + g_ptr_array_free(cmd.status_full_folders, TRUE); + cmd.status_full_folders = NULL; + } + + gtk_main(); + + return 0; +} + +static void parse_cmd_opt(int argc, char *argv[]) +{ + gint i; + + for (i = 1; i < argc; i++) { + if (!strncmp(argv[i], "--debug", 7)) + debug_mode = TRUE; + else if (!strncmp(argv[i], "--receive-all", 13)) + cmd.receive_all = TRUE; + else if (!strncmp(argv[i], "--receive", 9)) + cmd.receive = TRUE; + else if (!strncmp(argv[i], "--compose", 9)) { + const gchar *p = argv[i + 1]; + + cmd.compose = TRUE; + cmd.compose_mailto = NULL; + if (p && *p != '\0' && *p != '-') { + if (!strncmp(p, "mailto:", 7)) + cmd.compose_mailto = p + 7; + else + cmd.compose_mailto = p; + i++; + } + } else if (!strncmp(argv[i], "--attach", 8)) { + const gchar *p = argv[i + 1]; + gchar *file; + + while (p && *p != '\0' && *p != '-') { + if (!cmd.attach_files) + cmd.attach_files = g_ptr_array_new(); + if (*p != G_DIR_SEPARATOR) + file = g_strconcat(startup_dir, + G_DIR_SEPARATOR_S, + p, NULL); + else + file = g_strdup(p); + g_ptr_array_add(cmd.attach_files, file); + i++; + p = argv[i + 1]; + } + } else if (!strncmp(argv[i], "--send", 6)) { + cmd.send = TRUE; + } else if (!strncmp(argv[i], "--version", 9)) { + puts("Sylpheed version " VERSION); + exit(0); + } else if (!strncmp(argv[i], "--status-full", 13)) { + const gchar *p = argv[i + 1]; + + cmd.status_full = TRUE; + while (p && *p != '\0' && *p != '-') { + if (!cmd.status_full_folders) + cmd.status_full_folders = + g_ptr_array_new(); + g_ptr_array_add(cmd.status_full_folders, + g_strdup(p)); + i++; + p = argv[i + 1]; + } + } else if (!strncmp(argv[i], "--status", 8)) { + const gchar *p = argv[i + 1]; + + cmd.status = TRUE; + while (p && *p != '\0' && *p != '-') { + if (!cmd.status_folders) + cmd.status_folders = g_ptr_array_new(); + g_ptr_array_add(cmd.status_folders, + g_strdup(p)); + i++; + p = argv[i + 1]; + } + } else if (!strncmp(argv[i], "--help", 6)) { + g_print(_("Usage: %s [OPTION]...\n"), + g_basename(argv[0])); + + puts(_(" --compose [address] open composition window")); + puts(_(" --attach file1 [file2]...\n" + " open composition window with specified files\n" + " attached")); + puts(_(" --receive receive new messages")); + puts(_(" --receive-all receive new messages of all accounts")); + puts(_(" --send send all queued messages")); + puts(_(" --status [folder]... show the total number of messages")); + puts(_(" --status-full [folder]...\n" + " show the status of each folder")); + puts(_(" --debug debug mode")); + puts(_(" --help display this help and exit")); + puts(_(" --version output version information and exit")); + + exit(1); + } + } + + if (cmd.attach_files && cmd.compose == FALSE) { + cmd.compose = TRUE; + cmd.compose_mailto = NULL; + } +} + +static gint get_queued_message_num(void) +{ + FolderItem *queue; + + queue = folder_get_default_queue(); + if (!queue) return -1; + + folder_item_scan(queue); + return queue->total; +} + +void app_will_exit(GtkWidget *widget, gpointer data) +{ + MainWindow *mainwin = data; + gchar *filename; + + if (compose_get_compose_list()) { + if (alertpanel(_("Notice"), + _("Composing message exists. Really quit?"), + _("OK"), _("Cancel"), NULL) != G_ALERTDEFAULT) + return; + manage_window_focus_in(mainwin->window, NULL, NULL); + } + + if (prefs_common.warn_queued_on_exit && get_queued_message_num() > 0) { + if (alertpanel(_("Queued messages"), + _("Some unsent messages are queued. Exit now?"), + _("OK"), _("Cancel"), NULL) != G_ALERTDEFAULT) + return; + manage_window_focus_in(mainwin->window, NULL, NULL); + } + + inc_autocheck_timer_remove(); + + if (prefs_common.clean_on_exit) + main_window_empty_trash(mainwin, prefs_common.ask_on_clean); + + /* save all state before exiting */ + folder_write_list(); + summary_write_cache(mainwin->summaryview); + + main_window_get_size(mainwin); + main_window_get_position(mainwin); + prefs_common_write_config(); + prefs_filter_write_config(); + account_write_config_all(); + addressbook_export_to_file(); + + filename = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MENU_RC, NULL); + gtk_accel_map_save(filename); + g_free(filename); + + /* delete temporary files */ + remove_all_files(get_mime_tmp_dir()); + + close_log_file(); + lock_socket_remove(); + +#if USE_SSL + ssl_done(); +#endif + + gtk_main_quit(); +} + +#if USE_GPGME +static void idle_function_for_gpgme(void) +{ + while (gtk_events_pending()) + gtk_main_iteration(); +} +#endif /* USE_GPGME */ + +static gchar *get_socket_name(void) +{ + static gchar *filename = NULL; + + if (filename == NULL) { + filename = g_strdup_printf("%s%csylpheed-%d", + g_get_tmp_dir(), G_DIR_SEPARATOR, + getuid()); + } + + return filename; +} + +static gint prohibit_duplicate_launch(void) +{ + gint uxsock; + gchar *path; + + path = get_socket_name(); + uxsock = fd_connect_unix(path); + if (uxsock < 0) { + unlink(path); + return fd_open_unix(path); + } + + /* remote command mode */ + + debug_print(_("another Sylpheed is already running.\n")); + + if (cmd.receive_all) + fd_write_all(uxsock, "receive_all\n", 12); + else if (cmd.receive) + fd_write_all(uxsock, "receive\n", 8); + else if (cmd.compose && cmd.attach_files) { + gchar *str, *compose_str; + gint i; + + if (cmd.compose_mailto) + compose_str = g_strdup_printf("compose_attach %s\n", + cmd.compose_mailto); + else + compose_str = g_strdup("compose_attach\n"); + + fd_write_all(uxsock, compose_str, strlen(compose_str)); + g_free(compose_str); + + for (i = 0; i < cmd.attach_files->len; i++) { + str = g_ptr_array_index(cmd.attach_files, i); + fd_write_all(uxsock, str, strlen(str)); + fd_write_all(uxsock, "\n", 1); + } + + fd_write_all(uxsock, ".\n", 2); + } else if (cmd.compose) { + gchar *compose_str; + + if (cmd.compose_mailto) + compose_str = g_strdup_printf + ("compose %s\n", cmd.compose_mailto); + else + compose_str = g_strdup("compose\n"); + + fd_write_all(uxsock, compose_str, strlen(compose_str)); + g_free(compose_str); + } else if (cmd.send) { + fd_write_all(uxsock, "send\n", 5); + } else if (cmd.status || cmd.status_full) { + gchar buf[BUFFSIZE]; + gint i; + const gchar *command; + GPtrArray *folders; + gchar *folder; + + command = cmd.status_full ? "status-full\n" : "status\n"; + folders = cmd.status_full ? cmd.status_full_folders : + cmd.status_folders; + + fd_write_all(uxsock, command, strlen(command)); + for (i = 0; folders && i < folders->len; ++i) { + folder = g_ptr_array_index(folders, i); + fd_write_all(uxsock, folder, strlen(folder)); + fd_write_all(uxsock, "\n", 1); + } + fd_write_all(uxsock, ".\n", 2); + for (;;) { + fd_gets(uxsock, buf, sizeof(buf)); + if (!strncmp(buf, ".\n", 2)) break; + fputs(buf, stdout); + } + } else + fd_write_all(uxsock, "popup\n", 6); + + fd_close(uxsock); + return -1; +} + +static gint lock_socket_remove(void) +{ + gchar *filename; + + if (lock_socket < 0) return -1; + + if (lock_socket_tag > 0) + gdk_input_remove(lock_socket_tag); + fd_close(lock_socket); + filename = get_socket_name(); + unlink(filename); + + return 0; +} + +static GPtrArray *get_folder_item_list(gint sock) +{ + gchar buf[BUFFSIZE]; + FolderItem *item; + GPtrArray *folders = NULL; + + for (;;) { + fd_gets(sock, buf, sizeof(buf)); + if (!strncmp(buf, ".\n", 2)) break; + strretchomp(buf); + if (!folders) folders = g_ptr_array_new(); + item = folder_find_item_from_identifier(buf); + if (item) + g_ptr_array_add(folders, item); + else + g_warning("no such folder: %s\n", buf); + } + + return folders; +} + +static void lock_socket_input_cb(gpointer data, + gint source, + GdkInputCondition condition) +{ + MainWindow *mainwin = (MainWindow *)data; + gint sock; + gchar buf[BUFFSIZE]; + + sock = fd_accept(source); + fd_gets(sock, buf, sizeof(buf)); + + if (!strncmp(buf, "popup", 5)) { + main_window_popup(mainwin); + } else if (!strncmp(buf, "receive_all", 11)) { + main_window_popup(mainwin); + inc_all_account_mail(mainwin, FALSE); + } else if (!strncmp(buf, "receive", 7)) { + main_window_popup(mainwin); + inc_mail(mainwin); + } else if (!strncmp(buf, "compose_attach", 14)) { + GPtrArray *files; + gchar *mailto; + + mailto = g_strdup(buf + strlen("compose_attach") + 1); + files = g_ptr_array_new(); + while (fd_gets(sock, buf, sizeof(buf)) > 0) { + if (buf[0] == '.' && buf[1] == '\n') break; + strretchomp(buf); + g_ptr_array_add(files, g_strdup(buf)); + } + open_compose_new(mailto, files); + ptr_array_free_strings(files); + g_ptr_array_free(files, TRUE); + g_free(mailto); + } else if (!strncmp(buf, "compose", 7)) { + open_compose_new(buf + strlen("compose") + 1, NULL); + } else if (!strncmp(buf, "send", 4)) { + send_queue(); + } else if (!strncmp(buf, "status-full", 11) || + !strncmp(buf, "status", 6)) { + gchar *status; + GPtrArray *folders; + + folders = get_folder_item_list(sock); + status = folder_get_status + (folders, !strncmp(buf, "status-full", 11)); + fd_write_all(sock, status, strlen(status)); + fd_write_all(sock, ".\n", 2); + g_free(status); + if (folders) g_ptr_array_free(folders, TRUE); + } + + fd_close(sock); +} + +static void open_compose_new(const gchar *address, GPtrArray *attach_files) +{ + gchar *addr = NULL; + + if (address) { + Xstrdup_a(addr, address, return); + g_strstrip(addr); + } + + compose_new(NULL, NULL, addr, attach_files); +} + +static void send_queue(void) +{ + GList *list; + + if (!main_window_toggle_online_if_offline(main_window_get())) + return; + + for (list = folder_get_list(); list != NULL; list = list->next) { + Folder *folder = list->data; + + if (folder->queue) { + gint ret; + + ret = procmsg_send_queue(folder->queue, + prefs_common.savemsg); + statusbar_pop_all(); + if (ret > 0) + folder_item_scan(folder->queue); + } + } + + folderview_update_all_updated(TRUE); +} |