diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 18 | ||||
-rw-r--r-- | src/account.c | 416 | ||||
-rw-r--r-- | src/account.h | 61 | ||||
-rw-r--r-- | src/customheader.c | 233 | ||||
-rw-r--r-- | src/customheader.h | 45 | ||||
-rw-r--r-- | src/defs.h | 122 | ||||
-rw-r--r-- | src/enums.h | 55 | ||||
-rw-r--r-- | src/filter.c | 1421 | ||||
-rw-r--r-- | src/filter.h | 214 | ||||
-rw-r--r-- | src/folder.c | 1583 | ||||
-rw-r--r-- | src/folder.h | 395 | ||||
-rw-r--r-- | src/imap.c | 4105 | ||||
-rw-r--r-- | src/imap.h | 114 | ||||
-rw-r--r-- | src/main.c | 3 | ||||
-rw-r--r-- | src/md5.c | 433 | ||||
-rw-r--r-- | src/md5.h | 49 | ||||
-rw-r--r-- | src/mh.c | 1431 | ||||
-rw-r--r-- | src/mh.h | 38 | ||||
-rw-r--r-- | src/news.c | 1062 | ||||
-rw-r--r-- | src/news.h | 59 | ||||
-rw-r--r-- | src/nntp.c | 431 | ||||
-rw-r--r-- | src/nntp.h | 109 | ||||
-rw-r--r-- | src/pop.c | 857 | ||||
-rw-r--r-- | src/pop.h | 153 | ||||
-rw-r--r-- | src/prefs_account.c | 254 | ||||
-rw-r--r-- | src/prefs_account.h | 182 | ||||
-rw-r--r-- | src/prefs_common.c | 429 | ||||
-rw-r--r-- | src/prefs_common.h | 257 | ||||
-rw-r--r-- | src/procheader.c | 799 | ||||
-rw-r--r-- | src/procheader.h | 93 | ||||
-rw-r--r-- | src/procmime.c | 1170 | ||||
-rw-r--r-- | src/procmime.h | 188 | ||||
-rw-r--r-- | src/procmsg.c | 1446 | ||||
-rw-r--r-- | src/procmsg.h | 282 | ||||
-rw-r--r-- | src/rfc2015.c | 50 | ||||
-rw-r--r-- | src/rfc2015.h | 5 | ||||
-rw-r--r-- | src/smtp.c | 613 | ||||
-rw-r--r-- | src/smtp.h | 117 |
38 files changed, 58 insertions, 19234 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index c567b8b9..ae8991a2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,8 +3,6 @@ SUBDIRS = icons bin_PROGRAMS = sylpheed sylpheed_SOURCES = \ - defs.h \ - enums.h \ version.h \ main.c main.h \ mainwindow.c mainwindow.h \ @@ -18,21 +16,15 @@ sylpheed_SOURCES = \ summary_search.c summary_search.h \ message_search.c message_search.h \ colorlabel.c colorlabel.h \ - folder.c folder.h \ - procmsg.c procmsg.h \ - procheader.c procheader.h \ - filter.c filter.h \ action.c action.h \ compose.c compose.h \ gtkshruler.c gtkshruler.h \ menu.c menu.h \ stock_pixmap.c stock_pixmap.h \ prefs_ui.c prefs_ui.h \ - prefs_common.c prefs_common.h \ prefs_common_dialog.c prefs_common_dialog.h \ prefs_filter.c prefs_filter.h \ prefs_filter_edit.c prefs_filter_edit.h \ - prefs_account.c prefs_account.h \ prefs_account_dialog.c prefs_account_dialog.h \ prefs_folder_item.c prefs_folder_item.h \ prefs_display_header.c prefs_display_header.h \ @@ -40,10 +32,8 @@ sylpheed_SOURCES = \ prefs_summary_column.c prefs_summary_column.h \ prefs_template.c prefs_template.h \ prefs_actions.c prefs_actions.h \ - account.c account.h \ account_dialog.c account_dialog.h \ displayheader.c displayheader.h \ - customheader.c customheader.h \ template.c template.h \ addressbook.c addressbook.h \ addr_compl.c addr_compl.h \ @@ -80,19 +70,11 @@ sylpheed_SOURCES = \ about.c about.h \ setup.c setup.h \ gtkutils.c gtkutils.h \ - md5.c md5.h \ - smtp.c smtp.h \ - pop.c pop.h \ - mh.c mh.h \ mbox.c mbox.h \ send_message.c send_message.h \ inc.c inc.h \ import.c import.h \ export.c export.h \ - nntp.c nntp.h \ - news.c news.h \ - imap.c imap.h \ - procmime.c procmime.h \ rfc2015.c rfc2015.h \ passphrase.c passphrase.h \ select-keys.c select-keys.h \ diff --git a/src/account.c b/src/account.c deleted file mode 100644 index 2ae0ca43..00000000 --- a/src/account.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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 <glib/gi18n.h> -#include <stdio.h> -#include <errno.h> - -#include "folder.h" -#include "account.h" -#include "prefs.h" -#include "prefs_account.h" -#include "procmsg.h" -#include "procheader.h" -#include "utils.h" - -#define PREFSBUFSIZE 1024 - -PrefsAccount *cur_account; - -static GList *account_list = NULL; - - -void account_read_config_all(void) -{ - GSList *ac_label_list = NULL, *cur; - gchar *rcpath; - FILE *fp; - gchar buf[PREFSBUFSIZE]; - PrefsAccount *ac_prefs; - - debug_print(_("Reading all config for each account...\n")); - - rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ACCOUNT_RC, NULL); - if ((fp = g_fopen(rcpath, "rb")) == NULL) { - if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen"); - g_free(rcpath); - return; - } - g_free(rcpath); - - while (fgets(buf, sizeof(buf), fp) != NULL) { - if (!strncmp(buf, "[Account: ", 10)) { - strretchomp(buf); - memmove(buf, buf + 1, strlen(buf)); - buf[strlen(buf) - 1] = '\0'; - debug_print("Found label: %s\n", buf); - ac_label_list = g_slist_append(ac_label_list, - g_strdup(buf)); - } - } - fclose(fp); - - /* read config data from file */ - cur_account = NULL; - for (cur = ac_label_list; cur != NULL; cur = cur->next) { - ac_prefs = prefs_account_new(); - prefs_account_read_config(ac_prefs, (gchar *)cur->data); - account_list = g_list_append(account_list, ac_prefs); - if (ac_prefs->is_default) - cur_account = ac_prefs; - } - /* if default is not set, assume first account as default */ - if (!cur_account && account_list) { - ac_prefs = (PrefsAccount *)account_list->data; - account_set_as_default(ac_prefs); - cur_account = ac_prefs; - } - - while (ac_label_list) { - g_free(ac_label_list->data); - ac_label_list = g_slist_remove(ac_label_list, - ac_label_list->data); - } -} - -void account_write_config_all(void) -{ - prefs_account_write_config_all(account_list); -} - -PrefsAccount *account_find_from_smtp_server(const gchar *address, - const gchar *smtp_server) -{ - GList *cur; - PrefsAccount *ac; - - g_return_val_if_fail(address != NULL, NULL); - g_return_val_if_fail(smtp_server != NULL, NULL); - - for (cur = account_list; cur != NULL; cur = cur->next) { - ac = (PrefsAccount *)cur->data; - if (!strcmp2(address, ac->address) && - !strcmp2(smtp_server, ac->smtp_server)) - return ac; - } - - return NULL; -} - -/* - * account_find_from_address: - * @address: Email address string. - * - * Find a mail (not news) account with the specified email address. - * - * Return value: The found account, or NULL if not found. - */ -PrefsAccount *account_find_from_address(const gchar *address) -{ - GList *cur; - PrefsAccount *ac; - - g_return_val_if_fail(address != NULL, NULL); - - for (cur = account_list; cur != NULL; cur = cur->next) { - ac = (PrefsAccount *)cur->data; - if (ac->protocol != A_NNTP && ac->address && - strcasestr(address, ac->address) != NULL) - return ac; - } - - return NULL; -} - -PrefsAccount *account_find_from_id(gint id) -{ - GList *cur; - PrefsAccount *ac; - - for (cur = account_list; cur != NULL; cur = cur->next) { - ac = (PrefsAccount *)cur->data; - if (id == ac->account_id) - return ac; - } - - return NULL; -} - -PrefsAccount *account_find_from_item(FolderItem *item) -{ - PrefsAccount *ac; - - g_return_val_if_fail(item != NULL, NULL); - - ac = item->account; - if (!ac) { - FolderItem *cur_item = item->parent; - while (cur_item != NULL) { - if (cur_item->account && cur_item->ac_apply_sub) { - ac = cur_item->account; - break; - } - cur_item = cur_item->parent; - } - } - if (!ac) - ac = item->folder->account; - - return ac; -} - -PrefsAccount *account_find_from_message_file(const gchar *file) -{ - static HeaderEntry hentry[] = {{"From:", NULL, FALSE}, - {"X-Sylpheed-Account-Id:", NULL, FALSE}, - {"AID:", NULL, FALSE}, - {NULL, NULL, FALSE}}; - - enum - { - H_FROM = 0, - H_X_SYLPHEED_ACCOUNT_ID = 1, - H_AID = 2 - }; - - PrefsAccount *ac = NULL; - FILE *fp; - gchar *str; - gchar buf[BUFFSIZE]; - gint hnum; - - g_return_val_if_fail(file != NULL, NULL); - - if ((fp = g_fopen(file, "rb")) == NULL) { - FILE_OP_ERROR(file, "fopen"); - return NULL; - } - - while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry)) - != -1) { - str = buf + strlen(hentry[hnum].name); - if (hnum == H_FROM) - ac = account_find_from_address(str); - else if (hnum == H_X_SYLPHEED_ACCOUNT_ID || hnum == H_AID) { - PrefsAccount *tmp_ac; - - tmp_ac = account_find_from_id(atoi(str)); - if (tmp_ac) { - ac = tmp_ac; - break; - } - } - } - - fclose(fp); - return ac; -} - -PrefsAccount *account_find_from_msginfo(MsgInfo *msginfo) -{ - gchar *file; - PrefsAccount *ac; - - file = procmsg_get_message_file(msginfo); - ac = account_find_from_message_file(file); - g_free(file); - - if (!ac && msginfo->folder) - ac = account_find_from_item(msginfo->folder); - - return ac; -} - -void account_foreach(AccountFunc func, gpointer user_data) -{ - GList *cur; - - for (cur = account_list; cur != NULL; cur = cur->next) - if (func((PrefsAccount *)cur->data, user_data) != 0) - return; -} - -GList *account_get_list(void) -{ - return account_list; -} - -void account_list_free(void) -{ - g_list_free(account_list); - account_list = NULL; -} - -void account_append(PrefsAccount *ac_prefs) -{ - account_list = g_list_append(account_list, ac_prefs); -} - -void account_set_as_default(PrefsAccount *ac_prefs) -{ - PrefsAccount *ap; - GList *cur; - - for (cur = account_list; cur != NULL; cur = cur->next) { - ap = (PrefsAccount *)cur->data; - if (ap->is_default) - ap->is_default = FALSE; - } - - ac_prefs->is_default = TRUE; -} - -PrefsAccount *account_get_default(void) -{ - PrefsAccount *ap; - GList *cur; - - for (cur = account_list; cur != NULL; cur = cur->next) { - ap = (PrefsAccount *)cur->data; - if (ap->is_default) - return ap; - } - - return NULL; -} - -#if 0 -void account_set_missing_folder(void) -{ - PrefsAccount *ap; - GList *cur; - - for (cur = account_list; cur != NULL; cur = cur->next) { - ap = (PrefsAccount *)cur->data; - if ((ap->protocol == A_IMAP4 || ap->protocol == A_NNTP) && - !ap->folder) { - Folder *folder; - - if (ap->protocol == A_IMAP4) { - folder = folder_new(F_IMAP, ap->account_name, - ap->recv_server); - } else { - folder = folder_new(F_NEWS, ap->account_name, - ap->nntp_server); - } - - folder->account = ap; - ap->folder = REMOTE_FOLDER(folder); - folder_add(folder); - if (ap->protocol == A_IMAP4) { - if (main_window_toggle_online_if_offline - (main_window_get())) { - folder->klass->create_tree(folder); - statusbar_pop_all(); - } - } - } - } -} -#endif - -FolderItem *account_get_special_folder(PrefsAccount *ac_prefs, - SpecialFolderItemType type) -{ - FolderItem *item = NULL; - - g_return_val_if_fail(ac_prefs != NULL, NULL); - - switch (type) { - case F_INBOX: - if (ac_prefs->folder) - item = FOLDER(ac_prefs->folder)->inbox; - if (!item) - item = folder_get_default_inbox(); - break; - case F_OUTBOX: - if (ac_prefs->set_sent_folder && ac_prefs->sent_folder) { - item = folder_find_item_from_identifier - (ac_prefs->sent_folder); - } - if (!item) { - if (ac_prefs->folder) - item = FOLDER(ac_prefs->folder)->outbox; - if (!item) - item = folder_get_default_outbox(); - } - break; - case F_DRAFT: - if (ac_prefs->set_draft_folder && ac_prefs->draft_folder) { - item = folder_find_item_from_identifier - (ac_prefs->draft_folder); - } - if (!item) { - if (ac_prefs->folder) - item = FOLDER(ac_prefs->folder)->draft; - if (!item) - item = folder_get_default_draft(); - } - break; - case F_QUEUE: - if (ac_prefs->folder) - item = FOLDER(ac_prefs->folder)->queue; - if (!item) - item = folder_get_default_queue(); - break; - case F_TRASH: - if (ac_prefs->set_trash_folder && ac_prefs->trash_folder) { - item = folder_find_item_from_identifier - (ac_prefs->trash_folder); - } - if (!item) { - if (ac_prefs->folder) - item = FOLDER(ac_prefs->folder)->trash; - if (!item) - item = folder_get_default_trash(); - } - break; - default: - break; - } - - return item; -} - -void account_destroy(PrefsAccount *ac_prefs) -{ - g_return_if_fail(ac_prefs != NULL); - - folder_unref_account_all(ac_prefs); - - prefs_account_free(ac_prefs); - account_list = g_list_remove(account_list, ac_prefs); - - if (cur_account == ac_prefs) cur_account = NULL; - if (!cur_account && account_list) { - cur_account = account_get_default(); - if (!cur_account) { - ac_prefs = (PrefsAccount *)account_list->data; - account_set_as_default(ac_prefs); - cur_account = ac_prefs; - } - } -} diff --git a/src/account.h b/src/account.h deleted file mode 100644 index 0cef7c50..00000000 --- a/src/account.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __ACCOUNT_H__ -#define __ACCOUNT_H__ - -#include <glib.h> - -#include "prefs.h" -#include "prefs_account.h" -#include "folder.h" -#include "procmsg.h" - -typedef gint (*AccountFunc) (PrefsAccount *ac_prefs, - gpointer user_data); - -extern PrefsAccount *cur_account; - -void account_read_config_all (void); -void account_write_config_all (void); - -PrefsAccount *account_find_from_smtp_server (const gchar *address, - const gchar *smtp_server); -PrefsAccount *account_find_from_address (const gchar *address); -PrefsAccount *account_find_from_id (gint id); -PrefsAccount *account_find_from_item (FolderItem *item); -PrefsAccount *account_find_from_message_file (const gchar *file); -PrefsAccount *account_find_from_msginfo (MsgInfo *msginfo); - -void account_foreach (AccountFunc func, - gpointer user_data); -GList *account_get_list (void); -void account_list_free (void); -void account_append (PrefsAccount *ac_prefs); - -void account_set_as_default (PrefsAccount *ac_prefs); -PrefsAccount *account_get_default (void); - -//void account_set_missing_folder(void); -FolderItem *account_get_special_folder(PrefsAccount *ac_prefs, - SpecialFolderItemType type); - -void account_destroy (PrefsAccount *ac_prefs); - -#endif /* __ACCOUNT_H__ */ diff --git a/src/customheader.c b/src/customheader.c deleted file mode 100644 index c145484d..00000000 --- a/src/customheader.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 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 <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> - -#include "customheader.h" -#include "prefs.h" -#include "prefs_account.h" -#include "utils.h" - - -void custom_header_read_config(PrefsAccount *ac) -{ - gchar *rcpath; - FILE *fp; - gchar buf[PREFSBUFSIZE]; - CustomHeader *ch; - - debug_print("Reading custom header configuration...\n"); - - rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, - CUSTOM_HEADER_RC, NULL); - if ((fp = g_fopen(rcpath, "rb")) == NULL) { - if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen"); - g_free(rcpath); - ac->customhdr_list = NULL; - return; - } - g_free(rcpath); - - /* remove all previous headers list */ - while (ac->customhdr_list != NULL) { - ch = (CustomHeader *)ac->customhdr_list->data; - custom_header_free(ch); - ac->customhdr_list = g_slist_remove(ac->customhdr_list, ch); - } - - while (fgets(buf, sizeof(buf), fp) != NULL) { - ch = custom_header_read_str(buf); - if (ch) { - if (ch->account_id == ac->account_id) { - ac->customhdr_list = - g_slist_append(ac->customhdr_list, ch); - } else - custom_header_free(ch); - } - } - - fclose(fp); -} - -void custom_header_write_config(PrefsAccount *ac) -{ - gchar *rcpath; - PrefFile *pfile; - GSList *cur; - gchar buf[PREFSBUFSIZE]; - FILE * fp; - CustomHeader *ch; - - GSList *all_hdrs = NULL; - - debug_print("Writing custom header configuration...\n"); - - rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, - CUSTOM_HEADER_RC, NULL); - - if ((fp = g_fopen(rcpath, "rb")) == NULL) { - if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen"); - } else { - all_hdrs = NULL; - - while (fgets(buf, sizeof(buf), fp) != NULL) { - ch = custom_header_read_str(buf); - if (ch) { - if (ch->account_id != ac->account_id) - all_hdrs = - g_slist_append(all_hdrs, ch); - else - custom_header_free(ch); - } - } - - fclose(fp); - } - - if ((pfile = prefs_file_open(rcpath)) == NULL) { - g_warning("failed to write configuration to file\n"); - g_free(rcpath); - return; - } - - for (cur = all_hdrs; cur != NULL; cur = cur->next) { - CustomHeader *hdr = (CustomHeader *)cur->data; - gchar *chstr; - - chstr = custom_header_get_str(hdr); - if (fputs(chstr, pfile->fp) == EOF || - fputc('\n', pfile->fp) == EOF) { - FILE_OP_ERROR(rcpath, "fputs || fputc"); - prefs_file_close_revert(pfile); - g_free(rcpath); - g_free(chstr); - return; - } - g_free(chstr); - } - - for (cur = ac->customhdr_list; cur != NULL; cur = cur->next) { - CustomHeader *hdr = (CustomHeader *)cur->data; - gchar *chstr; - - chstr = custom_header_get_str(hdr); - if (fputs(chstr, pfile->fp) == EOF || - fputc('\n', pfile->fp) == EOF) { - FILE_OP_ERROR(rcpath, "fputs || fputc"); - prefs_file_close_revert(pfile); - g_free(rcpath); - g_free(chstr); - return; - } - g_free(chstr); - } - - g_free(rcpath); - - while (all_hdrs != NULL) { - ch = (CustomHeader *)all_hdrs->data; - custom_header_free(ch); - all_hdrs = g_slist_remove(all_hdrs, ch); - } - - if (prefs_file_close(pfile) < 0) { - g_warning("failed to write configuration to file\n"); - return; - } -} - -gchar *custom_header_get_str(CustomHeader *ch) -{ - return g_strdup_printf("%i:%s: %s", - ch->account_id, ch->name, - ch->value ? ch->value : ""); -} - -CustomHeader *custom_header_read_str(const gchar *buf) -{ - CustomHeader *ch; - gchar *account_id_str; - gint id; - gchar *name; - gchar *value; - gchar *tmp; - - Xstrdup_a(tmp, buf, return NULL); - - account_id_str = tmp; - - name = strchr(account_id_str, ':'); - if (!name) - return NULL; - else { - gchar *endp; - - *name++ = '\0'; - id = strtol(account_id_str, &endp, 10); - if (*endp != '\0') return NULL; - } - - value = strchr(name, ':'); - if (!value) return NULL; - - *value++ = '\0'; - - g_strstrip(name); - g_strstrip(value); - - ch = g_new0(CustomHeader, 1); - ch->account_id = id; - ch->name = *name ? g_strdup(name) : NULL; - ch->value = *value ? g_strdup(value) : NULL; - - return ch; -} - -CustomHeader *custom_header_find(GSList *header_list, const gchar *header) -{ - GSList *cur; - CustomHeader *chdr; - - for (cur = header_list; cur != NULL; cur = cur->next) { - chdr = (CustomHeader *)cur->data; - if (!g_ascii_strcasecmp(chdr->name, header)) - return chdr; - } - - return NULL; -} - -void custom_header_free(CustomHeader *ch) -{ - if (!ch) return; - - g_free(ch->name); - g_free(ch->value); - g_free(ch); -} diff --git a/src/customheader.h b/src/customheader.h deleted file mode 100644 index 27ae9373..00000000 --- a/src/customheader.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __CUSTOMHEADER_H__ -#define __CUSTOMHEADER_H__ - -#include <glib.h> - -typedef struct _CustomHeader CustomHeader; - -#include "prefs_account.h" - -struct _CustomHeader -{ - gint account_id; - gchar *name; - gchar *value; -}; - -void custom_header_read_config (PrefsAccount *ac); -void custom_header_write_config (PrefsAccount *ac); - -gchar *custom_header_get_str (CustomHeader *ch); -CustomHeader *custom_header_read_str (const gchar *buf); -CustomHeader *custom_header_find (GSList *header_list, - const gchar *header); -void custom_header_free (CustomHeader *ch); - -#endif /* __CUSTOMHEADER_H__ */ diff --git a/src/defs.h b/src/defs.h deleted file mode 100644 index 9683c28d..00000000 --- a/src/defs.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __DEFS_H__ -#define __DEFS_H__ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <glibconfig.h> - -#ifdef G_OS_WIN32 -# include <glib/gwin32.h> -#endif - -#if HAVE_PATHS_H -# include <paths.h> -#endif - -#if HAVE_SYS_PARAM_H -# include <sys/param.h> -#endif - -#define INBOX_DIR "inbox" -#define OUTBOX_DIR "sent" -#define QUEUE_DIR "queue" -#define DRAFT_DIR "draft" -#define TRASH_DIR "trash" -#ifdef G_OS_WIN32 -# define RC_DIR "Sylpheed" -#else -# define RC_DIR ".sylpheed-2.0" -#endif -#define OLD_RC_DIR ".sylpheed" -#define NEWS_CACHE_DIR "newscache" -#define IMAP_CACHE_DIR "imapcache" -#define MIME_TMP_DIR "mimetmp" -#define COMMON_RC "sylpheedrc" -#define ACCOUNT_RC "accountrc" -#define FILTER_RC "filterrc" -#define FILTER_LIST "filter.xml" -#define FILTER_HEADER_RC "filterheaderrc" -#define CUSTOM_HEADER_RC "customheaderrc" -#define DISPLAY_HEADER_RC "dispheaderrc" -#define MENU_RC "menurc" -#define ACTIONS_RC "actionsrc" -#define COMMAND_HISTORY "command_history" -#define TEMPLATE_DIR "templates" -#define TMP_DIR "tmp" -#define UIDL_DIR "uidl" -#define NEWSGROUP_LIST ".newsgroup_list" -#define ADDRESS_BOOK "addressbook.xml" -#define MANUAL_HTML_INDEX "sylpheed.html" -#define FAQ_HTML_INDEX "sylpheed-faq.html" -#define HOMEPAGE_URI "http://sylpheed.good-day.net/" -#define FOLDER_LIST "folderlist.xml" -#define CACHE_FILE ".sylpheed_cache" -#define MARK_FILE ".sylpheed_mark" -#define CACHE_VERSION 0x21 -#define MARK_VERSION 2 - -#ifdef G_OS_WIN32 -# define DEFAULT_SIGNATURE "signature.txt" -#else -# define DEFAULT_SIGNATURE ".signature" -#endif -#define DEFAULT_INC_PATH "/usr/bin/mh/inc" -#define DEFAULT_INC_PROGRAM "inc" -/* #define DEFAULT_INC_PATH "/usr/bin/imget" */ -/* #define DEFAULT_INC_PROGRAM "imget" */ -#define DEFAULT_SENDMAIL_CMD "/usr/sbin/sendmail -t -i" -#define DEFAULT_BROWSER_CMD "mozilla-firefox -remote 'openURL(%s,new-window)'" - -#ifdef _PATH_MAILDIR -# define DEFAULT_SPOOL_PATH _PATH_MAILDIR -#else -# define DEFAULT_SPOOL_PATH "/var/spool/mail" -#endif - -#define BUFFSIZE 8192 - -#ifndef MAXPATHLEN -# define MAXPATHLEN 4095 -#endif - -#define DEFAULT_HEIGHT 460 -#define DEFAULT_FOLDERVIEW_WIDTH 179 -#define DEFAULT_MAINVIEW_WIDTH 600 -#define DEFAULT_SUMMARY_HEIGHT 140 -#define DEFAULT_HEADERVIEW_HEIGHT 40 -#define DEFAULT_COMPOSE_HEIGHT 560 -#define BORDER_WIDTH 2 -#define CTREE_INDENT 18 -#define FOLDER_SPACING 4 -#define MAX_ENTRY_LENGTH 8191 -#define COLOR_DIM 35000 -#define UI_REFRESH_INTERVAL 50000 /* usec */ -#define FOLDER_UPDATE_INTERVAL 1500 /* msec */ -#define PROGRESS_UPDATE_INTERVAL 200 /* msec */ -#define SESSION_TIMEOUT_INTERVAL 60 /* sec */ -#define MAX_HISTORY_SIZE 16 - -#define DEFAULT_MESSAGE_FONT "Monospace 12" - -#endif /* __DEFS_H__ */ diff --git a/src/enums.h b/src/enums.h deleted file mode 100644 index 13ac2a18..00000000 --- a/src/enums.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __ENUMS_H__ -#define __ENUMS_H__ - -typedef enum -{ - TOOLBAR_NONE, - TOOLBAR_ICON, - TOOLBAR_TEXT, - TOOLBAR_BOTH -} ToolbarStyle; - -typedef enum -{ - S_COL_MARK, - S_COL_UNREAD, - S_COL_MIME, - S_COL_SUBJECT, - S_COL_FROM, - S_COL_DATE, - S_COL_SIZE, - S_COL_NUMBER, - - S_COL_MSG_INFO, - - S_COL_LABEL, - S_COL_TO, - - S_COL_FOREGROUND, - S_COL_BOLD, - - N_SUMMARY_COLS -} SummaryColumnType; - -#define N_SUMMARY_VISIBLE_COLS S_COL_MSG_INFO - -#endif /* __ENUMS_H__ */ diff --git a/src/filter.c b/src/filter.c deleted file mode 100644 index efc2fa02..00000000 --- a/src/filter.c +++ /dev/null @@ -1,1421 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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 <glib/gi18n.h> -#include <string.h> -#include <strings.h> -#include <stdlib.h> -#include <sys/types.h> -#if HAVE_REGEX_H -# include <regex.h> -#endif -#include <time.h> - -#include "filter.h" -#include "procmsg.h" -#include "procheader.h" -#include "folder.h" -#include "utils.h" -#include "xml.h" -#include "prefs.h" -#include "prefs_common.h" -#include "prefs_account.h" -#include "account.h" - -typedef enum -{ - FLT_O_CONTAIN = 1 << 0, - FLT_O_CASE_SENS = 1 << 1, - FLT_O_REGEX = 1 << 2 -} FilterOldFlag; - -static gboolean filter_match_cond (FilterCond *cond, - MsgInfo *msginfo, - GSList *hlist, - FilterInfo *fltinfo); -static gboolean filter_match_header_cond(FilterCond *cond, - GSList *hlist); - -static void filter_cond_free (FilterCond *cond); -static void filter_action_free (FilterAction *action); - - -gint filter_apply(GSList *fltlist, const gchar *file, FilterInfo *fltinfo) -{ - MsgInfo *msginfo; - gint ret = 0; - - g_return_val_if_fail(file != NULL, -1); - g_return_val_if_fail(fltinfo != NULL, -1); - - if (!fltlist) return 0; - - msginfo = procheader_parse_file(file, fltinfo->flags, FALSE); - if (!msginfo) return 0; - msginfo->file_path = g_strdup(file); - - ret = filter_apply_msginfo(fltlist, msginfo, fltinfo); - - procmsg_msginfo_free(msginfo); - - return ret; -} - -gint filter_apply_msginfo(GSList *fltlist, MsgInfo *msginfo, - FilterInfo *fltinfo) -{ - gchar *file; - GSList *hlist, *cur; - FilterRule *rule; - gint ret = 0; - - g_return_val_if_fail(msginfo != NULL, -1); - g_return_val_if_fail(fltinfo != NULL, -1); - - if (!fltlist) return 0; - - file = procmsg_get_message_file(msginfo); - hlist = procheader_get_header_list_from_file(file); - if (!hlist) { - g_free(file); - return 0; - } - - for (cur = fltlist; cur != NULL; cur = cur->next) { - rule = (FilterRule *)cur->data; - if (!rule->enabled) continue; - if (filter_match_rule(rule, msginfo, hlist, fltinfo)) { - ret = filter_action_exec(rule, msginfo, file, fltinfo); - if (ret < 0) { - g_warning("filter_action_exec() returned error\n"); - break; - } - if (fltinfo->drop_done == TRUE || - fltinfo->actions[FLT_ACTION_STOP_EVAL] == TRUE) - break; - } - } - - procheader_header_list_destroy(hlist); - g_free(file); - - return ret; -} - -gint filter_action_exec(FilterRule *rule, MsgInfo *msginfo, const gchar *file, - FilterInfo *fltinfo) -{ - FolderItem *dest_folder = NULL; - FilterAction *action; - GSList *cur; - gchar *cmdline; - gboolean copy_to_self = FALSE; - - g_return_val_if_fail(rule != NULL, -1); - g_return_val_if_fail(msginfo != NULL, -1); - g_return_val_if_fail(file != NULL, -1); - g_return_val_if_fail(fltinfo != NULL, -1); - - for (cur = rule->action_list; cur != NULL; cur = cur->next) { - action = (FilterAction *)cur->data; - - switch (action->type) { - case FLT_ACTION_MARK: - debug_print("filter_action_exec(): mark\n"); - MSG_SET_PERM_FLAGS(fltinfo->flags, MSG_MARKED); - fltinfo->actions[action->type] = TRUE; - break; - case FLT_ACTION_COLOR_LABEL: - debug_print("filter_action_exec(): color label: %d\n", - action->int_value); - MSG_UNSET_PERM_FLAGS(fltinfo->flags, - MSG_CLABEL_FLAG_MASK); - MSG_SET_COLORLABEL_VALUE(fltinfo->flags, - action->int_value); - fltinfo->actions[action->type] = TRUE; - break; - case FLT_ACTION_MARK_READ: - debug_print("filter_action_exec(): mark as read\n"); - if (msginfo->folder) { - if (MSG_IS_NEW(fltinfo->flags)) - msginfo->folder->new--; - if (MSG_IS_UNREAD(fltinfo->flags)) - msginfo->folder->unread--; - } - MSG_UNSET_PERM_FLAGS(fltinfo->flags, MSG_NEW|MSG_UNREAD); - fltinfo->actions[action->type] = TRUE; - break; - case FLT_ACTION_EXEC: - cmdline = g_strconcat(action->str_value, " ", file, - NULL); - execute_command_line(cmdline, FALSE); - g_free(cmdline); - fltinfo->actions[action->type] = TRUE; - break; - case FLT_ACTION_EXEC_ASYNC: - cmdline = g_strconcat(action->str_value, " ", file, - NULL); - execute_command_line(cmdline, TRUE); - g_free(cmdline); - fltinfo->actions[action->type] = TRUE; - break; - default: - break; - } - } - - for (cur = rule->action_list; cur != NULL; cur = cur->next) { - action = (FilterAction *)cur->data; - - switch (action->type) { - case FLT_ACTION_MOVE: - case FLT_ACTION_COPY: - dest_folder = folder_find_item_from_identifier - (action->str_value); - if (!dest_folder) { - g_warning("dest folder '%s' not found\n", - action->str_value); - return -1; - } - debug_print("filter_action_exec(): %s: dest_folder = %s\n", - action->type == FLT_ACTION_COPY ? - "copy" : "move", action->str_value); - - if (msginfo->folder) { - gint val; - - /* local filtering */ - if (msginfo->folder == dest_folder) - copy_to_self = TRUE; - else { - if (action->type == FLT_ACTION_COPY) { - val = folder_item_copy_msg - (dest_folder, msginfo); - if (val == -1) - return -1; - } - fltinfo->actions[action->type] = TRUE; - } - } else { - if (folder_item_add_msg(dest_folder, file, - &fltinfo->flags, - FALSE) < 0) - return -1; - fltinfo->actions[action->type] = TRUE; - } - - fltinfo->dest_list = g_slist_append(fltinfo->dest_list, - dest_folder); - if (action->type == FLT_ACTION_MOVE) { - fltinfo->move_dest = dest_folder; - fltinfo->drop_done = TRUE; - } - break; - default: - break; - } - } - - if (fltinfo->drop_done == TRUE) - return 0; - - for (cur = rule->action_list; cur != NULL; cur = cur->next) { - action = (FilterAction *)cur->data; - - switch (action->type) { - case FLT_ACTION_NOT_RECEIVE: - debug_print("filter_action_exec(): don't receive\n"); - fltinfo->drop_done = TRUE; - fltinfo->actions[action->type] = TRUE; - return 0; - case FLT_ACTION_DELETE: - debug_print("filter_action_exec(): delete\n"); - if (msginfo->folder) { - /* local filtering */ - if (copy_to_self == FALSE) - fltinfo->actions[action->type] = TRUE; - } else - fltinfo->actions[action->type] = TRUE; - - fltinfo->drop_done = TRUE; - return 0; - case FLT_ACTION_STOP_EVAL: - debug_print("filter_action_exec(): stop evaluation\n"); - fltinfo->actions[action->type] = TRUE; - return 0; - default: - break; - } - } - - return 0; -} - -static gboolean strmatch_regex(const gchar *haystack, const gchar *needle) -{ -#if HAVE_REGEX_H && HAVE_REGCOMP - gint ret = 0; - regex_t preg; - regmatch_t pmatch[1]; - - ret = regcomp(&preg, needle, REG_EXTENDED|REG_ICASE); - if (ret != 0) return FALSE; - - ret = regexec(&preg, haystack, 1, pmatch, 0); - regfree(&preg); - - if (ret == REG_NOMATCH) return FALSE; - - if (pmatch[0].rm_so != -1) - return TRUE; - else -#endif - return FALSE; -} - -gboolean filter_match_rule(FilterRule *rule, MsgInfo *msginfo, GSList *hlist, - FilterInfo *fltinfo) -{ - FilterCond *cond; - GSList *cur; - gboolean matched; - - g_return_val_if_fail(rule->cond_list != NULL, FALSE); - g_return_val_if_fail(rule->action_list != NULL, FALSE); - - switch (rule->timing) { - case FLT_TIMING_ANY: - break; - case FLT_TIMING_ON_RECEIVE: - if (msginfo->folder != NULL) - return FALSE; - break; - case FLT_TIMING_MANUAL: - if (msginfo->folder == NULL) - return FALSE; - break; - default: - break; - } - - if (rule->bool_op == FLT_AND) { - for (cur = rule->cond_list; cur != NULL; cur = cur->next) { - cond = (FilterCond *)cur->data; - matched = filter_match_cond(cond, msginfo, hlist, - fltinfo); - if (matched == FALSE) - return FALSE; - } - - return TRUE; - } else if (rule->bool_op == FLT_OR) { - for (cur = rule->cond_list; cur != NULL; cur = cur->next) { - cond = (FilterCond *)cur->data; - matched = filter_match_cond(cond, msginfo, hlist, - fltinfo); - if (matched == TRUE) - return TRUE; - } - - return FALSE; - } - - return FALSE; -} - -static gboolean filter_match_cond(FilterCond *cond, MsgInfo *msginfo, - GSList *hlist, FilterInfo *fltinfo) -{ - gboolean matched = FALSE; - gchar *file; - gchar *cmdline; - PrefsAccount *cond_ac; - - switch (cond->type) { - case FLT_COND_HEADER: - case FLT_COND_ANY_HEADER: - case FLT_COND_TO_OR_CC: - return filter_match_header_cond(cond, hlist); - case FLT_COND_BODY: - matched = procmime_find_string(msginfo, cond->str_value, - cond->match_func); - break; - case FLT_COND_CMD_TEST: - file = procmsg_get_message_file(msginfo); - cmdline = g_strconcat(cond->str_value, " ", file, NULL); - matched = (execute_command_line(cmdline, FALSE) == 0); - g_free(cmdline); - g_free(file); - break; - case FLT_COND_SIZE_GREATER: - matched = (msginfo->size > cond->int_value * 1024); - break; - case FLT_COND_AGE_GREATER: - matched = (time(NULL) - msginfo->date_t > - cond->int_value * 24 * 60 * 60); - break; - case FLT_COND_ACCOUNT: - cond_ac = account_find_from_id(cond->int_value); - matched = (cond_ac != NULL && cond_ac == fltinfo->account); - break; - default: - g_warning("filter_match_cond(): unknown condition: %d\n", - cond->type); - return FALSE; - } - - if (FLT_IS_NOT_MATCH(cond->match_flag)) - matched = !matched; - - return matched; -} - -static gboolean filter_match_header_cond(FilterCond *cond, GSList *hlist) -{ - gboolean matched = FALSE; - GSList *cur; - Header *header; - - for (cur = hlist; cur != NULL; cur = cur->next) { - header = (Header *)cur->data; - - switch (cond->type) { - case FLT_COND_HEADER: - if (!g_ascii_strcasecmp - (header->name, cond->header_name)) { - if (!cond->str_value || - cond->match_func(header->body, - cond->str_value)) - matched = TRUE; - } - break; - case FLT_COND_ANY_HEADER: - if (!cond->str_value || - cond->match_func(header->body, cond->str_value)) - matched = TRUE; - break; - case FLT_COND_TO_OR_CC: - if (!g_ascii_strcasecmp(header->name, "To") || - !g_ascii_strcasecmp(header->name, "Cc")) { - if (!cond->str_value || - cond->match_func(header->body, - cond->str_value)) - matched = TRUE; - } - break; - default: - break; - } - - if (matched == TRUE) - break; - } - - if (FLT_IS_NOT_MATCH(cond->match_flag)) - matched = !matched; - - return matched; -} - -#define RETURN_IF_TAG_NOT_MATCH(tag_name) \ - if (strcmp2(xmlnode->tag->tag, tag_name) != 0) { \ - g_warning("tag name != \"" tag_name "\"\n"); \ - filter_cond_list_free(cond_list); \ - filter_action_list_free(cond_list); \ - return FALSE; \ - } \ - -#define STR_SWITCH(sw) { const gchar *sw_str = sw; -#define STR_CASE_BEGIN(str) if (!strcmp(sw_str, str)) { -#define STR_CASE(str) } else if (!strcmp(sw_str, str)) { -#define STR_CASE_END } } - -static gboolean filter_xml_node_func(GNode *node, gpointer data) -{ - XMLNode *xmlnode; - GList *list; - const gchar *name = NULL; - FilterTiming timing = FLT_TIMING_ANY; - gboolean enabled = TRUE; - FilterRule *rule; - FilterBoolOp bool_op = FLT_OR; - GSList *cond_list = NULL; - GSList *action_list = NULL; - GNode *child, *cond_child, *action_child; - GSList **fltlist = (GSList **)data; - - if (g_node_depth(node) != 2) return FALSE; - g_return_val_if_fail(node->data != NULL, FALSE); - - xmlnode = node->data; - RETURN_IF_TAG_NOT_MATCH("rule"); - - for (list = xmlnode->tag->attr; list != NULL; list = list->next) { - XMLAttr *attr = (XMLAttr *)list->data; - - if (!attr || !attr->name || !attr->value) continue; - if (!strcmp(attr->name, "name")) - name = attr->value; - else if (!strcmp(attr->name, "timing")) { - if (!strcmp(attr->value, "any")) - timing = FLT_TIMING_ANY; - else if (!strcmp(attr->value, "receive")) - timing = FLT_TIMING_ON_RECEIVE; - else if (!strcmp(attr->value, "manual")) - timing = FLT_TIMING_MANUAL; - } else if (!strcmp(attr->name, "enabled")) { - if (!strcmp(attr->value, "true")) - enabled = TRUE; - else - enabled = FALSE; - } - } - - /* condition list */ - child = node->children; - if (!child) { - g_warning("<rule> must have children\n"); - return FALSE; - } - xmlnode = child->data; - RETURN_IF_TAG_NOT_MATCH("condition-list"); - for (list = xmlnode->tag->attr; list != NULL; list = list->next) { - XMLAttr *attr = (XMLAttr *)list->data; - - if (attr && attr->name && attr->value && - !strcmp(attr->name, "bool")) { - if (!strcmp(attr->value, "or")) - bool_op = FLT_OR; - else - bool_op = FLT_AND; - } - } - - for (cond_child = child->children; cond_child != NULL; - cond_child = cond_child->next) { - const gchar *type = NULL; - const gchar *name = NULL; - const gchar *value = NULL; - FilterCond *cond; - FilterCondType cond_type = FLT_COND_HEADER; - FilterMatchType match_type = FLT_CONTAIN; - FilterMatchFlag match_flag = 0; - - xmlnode = cond_child->data; - if (!xmlnode || !xmlnode->tag || !xmlnode->tag->tag) continue; - - for (list = xmlnode->tag->attr; list != NULL; list = list->next) { - XMLAttr *attr = (XMLAttr *)list->data; - - if (!attr || !attr->name || !attr->value) continue; - if (!strcmp(attr->name, "type")) - type = attr->value; - else if (!strcmp(attr->name, "name")) - name = attr->value; - } - - if (type) { - filter_rule_match_type_str_to_enum - (type, &match_type, &match_flag); - } - value = xmlnode->element; - - STR_SWITCH(xmlnode->tag->tag) - STR_CASE_BEGIN("match-header") - cond_type = FLT_COND_HEADER; - STR_CASE("match-any-header") - cond_type = FLT_COND_ANY_HEADER; - STR_CASE("match-to-or-cc") - cond_type = FLT_COND_TO_OR_CC; - STR_CASE("match-body-text") - cond_type = FLT_COND_BODY; - STR_CASE("command-test") - cond_type = FLT_COND_CMD_TEST; - STR_CASE("size") - cond_type = FLT_COND_SIZE_GREATER; - STR_CASE("age") - cond_type = FLT_COND_AGE_GREATER; - STR_CASE("account-id") - cond_type = FLT_COND_ACCOUNT; - STR_CASE_END - - cond = filter_cond_new(cond_type, match_type, match_flag, - name, value); - cond_list = g_slist_append(cond_list, cond); - } - - /* action list */ - child = child->next; - if (!child) { - g_warning("<rule> must have multiple children\n"); - filter_cond_list_free(cond_list); - return FALSE; - } - xmlnode = child->data; - RETURN_IF_TAG_NOT_MATCH("action-list"); - - for (action_child = child->children; action_child != NULL; - action_child = action_child->next) { - FilterAction *action; - FilterActionType action_type = FLT_ACTION_NONE; - - xmlnode = action_child->data; - if (!xmlnode || !xmlnode->tag || !xmlnode->tag->tag) continue; - - STR_SWITCH(xmlnode->tag->tag) - STR_CASE_BEGIN("move") - action_type = FLT_ACTION_MOVE; - STR_CASE("copy") - action_type = FLT_ACTION_COPY; - STR_CASE("not-receive") - action_type = FLT_ACTION_NOT_RECEIVE; - STR_CASE("delete") - action_type = FLT_ACTION_DELETE; - STR_CASE("exec") - action_type = FLT_ACTION_EXEC; - STR_CASE("exec-async") - action_type = FLT_ACTION_EXEC_ASYNC; - STR_CASE("mark") - action_type = FLT_ACTION_MARK; - STR_CASE("color-label") - action_type = FLT_ACTION_COLOR_LABEL; - STR_CASE("mark-as-read") - action_type = FLT_ACTION_MARK_READ; - STR_CASE("forward") - action_type = FLT_ACTION_FORWARD; - STR_CASE("forward-as-attachment") - action_type = FLT_ACTION_FORWARD_AS_ATTACHMENT; - STR_CASE("redirect") - action_type = FLT_ACTION_REDIRECT; - STR_CASE("stop-eval") - action_type = FLT_ACTION_STOP_EVAL; - STR_CASE_END - - action = filter_action_new(action_type, xmlnode->element); - action_list = g_slist_append(action_list, action); - } - - if (name && cond_list && action_list) { - rule = filter_rule_new(name, bool_op, cond_list, action_list); - rule->timing = timing; - rule->enabled = enabled; - *fltlist = g_slist_prepend(*fltlist, rule); - } - - return FALSE; -} - -#undef RETURN_IF_TAG_NOT_MATCH -#undef STR_SWITCH -#undef STR_CASE_BEGIN -#undef STR_CASE -#undef STR_CASE_END - -GSList *filter_xml_node_to_filter_list(GNode *node) -{ - GSList *fltlist = NULL; - - g_return_val_if_fail(node != NULL, NULL); - - g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, 2, - filter_xml_node_func, &fltlist); - fltlist = g_slist_reverse(fltlist); - - return fltlist; -} - -void filter_read_config(void) -{ - gchar *rcpath; - GNode *node; - FilterRule *rule; - - debug_print("Reading filter configuration...\n"); - - /* remove all previous filter list */ - while (prefs_common.fltlist != NULL) { - rule = (FilterRule *)prefs_common.fltlist->data; - filter_rule_free(rule); - prefs_common.fltlist = g_slist_remove(prefs_common.fltlist, - rule); - } - - rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_LIST, - NULL); - if (!is_file_exist(rcpath)) { - g_free(rcpath); - return; - } - - node = xml_parse_file(rcpath); - if (!node) { - g_warning("Can't parse %s\n", rcpath); - g_free(rcpath); - return; - } - g_free(rcpath); - - prefs_common.fltlist = filter_xml_node_to_filter_list(node); - - xml_free_tree(node); -} - -#define NODE_NEW(tag, text) \ - node = xml_node_new(xml_tag_new(tag), text) -#define ADD_ATTR(name, value) \ - xml_tag_add_attr(node->tag, xml_attr_new(name, value)) - -void filter_write_config(void) -{ - gchar *rcpath; - PrefFile *pfile; - GSList *cur; - - debug_print("Writing filter configuration...\n"); - - rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTER_LIST, - NULL); - if ((pfile = prefs_file_open(rcpath)) == NULL) { - g_warning("failed to write filter configuration to file\n"); - g_free(rcpath); - return; - } - - xml_file_put_xml_decl(pfile->fp); - fputs("\n<filter>\n", pfile->fp); - - for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) { - FilterRule *rule = (FilterRule *)cur->data; - GSList *cur_cond; - GSList *cur_action; - gchar match_type[16]; - - fputs(" <rule name=\"", pfile->fp); - xml_file_put_escape_str(pfile->fp, rule->name); - fprintf(pfile->fp, "\" timing=\"%s\"", - rule->timing == FLT_TIMING_ON_RECEIVE ? "receive" : - rule->timing == FLT_TIMING_MANUAL ? "manual" : "any"); - fprintf(pfile->fp, " enabled=\"%s\">\n", - rule->enabled ? "true" : "false"); - - fprintf(pfile->fp, " <condition-list bool=\"%s\">\n", - rule->bool_op == FLT_OR ? "or" : "and"); - - for (cur_cond = rule->cond_list; cur_cond != NULL; - cur_cond = cur_cond->next) { - FilterCond *cond = (FilterCond *)cur_cond->data; - XMLNode *node = NULL; - - switch (cond->match_type) { - case FLT_CONTAIN: - strcpy(match_type, - FLT_IS_NOT_MATCH(cond->match_flag) - ? "not-contain" : "contains"); - break; - case FLT_EQUAL: - strcpy(match_type, - FLT_IS_NOT_MATCH(cond->match_flag) - ? "is-not" : "is"); - break; - case FLT_REGEX: - strcpy(match_type, - FLT_IS_NOT_MATCH(cond->match_flag) - ? "not-regex" : "regex"); - break; - default: - match_type[0] = '\0'; - break; - } - - switch (cond->type) { - case FLT_COND_HEADER: - NODE_NEW("match-header", cond->str_value); - ADD_ATTR("type", match_type); - ADD_ATTR("name", cond->header_name); - break; - case FLT_COND_ANY_HEADER: - NODE_NEW("match-any-header", cond->str_value); - ADD_ATTR("type", match_type); - break; - case FLT_COND_TO_OR_CC: - NODE_NEW("match-to-or-cc", cond->str_value); - ADD_ATTR("type", match_type); - break; - case FLT_COND_BODY: - NODE_NEW("match-body-text", cond->str_value); - ADD_ATTR("type", match_type); - break; - case FLT_COND_CMD_TEST: - NODE_NEW("command-test", cond->str_value); - break; - case FLT_COND_SIZE_GREATER: - NODE_NEW("size", itos(cond->int_value)); - ADD_ATTR("type", - FLT_IS_NOT_MATCH(cond->match_flag) - ? "lt" : "gt"); - break; - case FLT_COND_AGE_GREATER: - NODE_NEW("age", itos(cond->int_value)); - ADD_ATTR("type", - FLT_IS_NOT_MATCH(cond->match_flag) - ? "lt" : "gt"); - break; - case FLT_COND_ACCOUNT: - NODE_NEW("account-id", itos(cond->int_value)); - break; - default: - break; - } - - if (node) { - fputs(" ", pfile->fp); - xml_file_put_node(pfile->fp, node); - xml_free_node(node); - } - } - - fputs(" </condition-list>\n", pfile->fp); - - fputs(" <action-list>\n", pfile->fp); - - for (cur_action = rule->action_list; cur_action != NULL; - cur_action = cur_action->next) { - FilterAction *action = (FilterAction *)cur_action->data; - XMLNode *node = NULL; - - switch (action->type) { - case FLT_ACTION_MOVE: - NODE_NEW("move", action->str_value); - break; - case FLT_ACTION_COPY: - NODE_NEW("copy", action->str_value); - break; - case FLT_ACTION_NOT_RECEIVE: - NODE_NEW("not-receive", NULL); - break; - case FLT_ACTION_DELETE: - NODE_NEW("delete", NULL); - break; - case FLT_ACTION_EXEC: - NODE_NEW("exec", action->str_value); - break; - case FLT_ACTION_EXEC_ASYNC: - NODE_NEW("exec-async", action->str_value); - break; - case FLT_ACTION_MARK: - NODE_NEW("mark", NULL); - break; - case FLT_ACTION_COLOR_LABEL: - NODE_NEW("color-label", action->str_value); - break; - case FLT_ACTION_MARK_READ: - NODE_NEW("mark-as-read", NULL); - break; - case FLT_ACTION_FORWARD: - NODE_NEW("forward", action->str_value); - break; - case FLT_ACTION_FORWARD_AS_ATTACHMENT: - NODE_NEW("forward-as-attachment", - action->str_value); - break; - case FLT_ACTION_REDIRECT: - NODE_NEW("redirect", action->str_value); - break; - case FLT_ACTION_STOP_EVAL: - NODE_NEW("stop-eval", NULL); - break; - default: - break; - } - - if (node) { - fputs(" ", pfile->fp); - xml_file_put_node(pfile->fp, node); - xml_free_node(node); - } - } - - fputs(" </action-list>\n", pfile->fp); - - fputs(" </rule>\n", pfile->fp); - } - - fputs("</filter>\n", pfile->fp); - - g_free(rcpath); - - if (prefs_file_close(pfile) < 0) { - g_warning(_("failed to write configuration to file\n")); - return; - } -} - -#undef NODE_NEW -#undef ADD_ATTR - -gchar *filter_get_str(FilterRule *rule) -{ - gchar *str; - FilterCond *cond1, *cond2; - FilterAction *action = NULL; - GSList *cur; - gint flag1 = 0, flag2 = 0; - - cond1 = (FilterCond *)rule->cond_list->data; - if (rule->cond_list->next) - cond2 = (FilterCond *)rule->cond_list->next->data; - else - cond2 = NULL; - - /* new -> old flag conversion */ - switch (cond1->match_type) { - case FLT_CONTAIN: - case FLT_EQUAL: - flag1 = FLT_IS_NOT_MATCH(cond1->match_flag) ? 0 : FLT_O_CONTAIN; - if (FLT_IS_CASE_SENS(cond1->match_flag)) - flag1 |= FLT_O_CASE_SENS; - break; - case FLT_REGEX: - flag1 = FLT_O_REGEX; break; - default: - break; - } - if (cond2) { - switch (cond2->match_type) { - case FLT_CONTAIN: - case FLT_EQUAL: - flag2 = FLT_IS_NOT_MATCH(cond2->match_flag) ? 0 : FLT_O_CONTAIN; - if (FLT_IS_CASE_SENS(cond2->match_flag)) - flag2 |= FLT_O_CASE_SENS; - break; - case FLT_REGEX: - flag2 = FLT_O_REGEX; break; - default: - break; - } - } else - flag2 = FLT_O_CONTAIN; - - for (cur = rule->action_list; cur != NULL; cur = cur->next) { - action = (FilterAction *)cur->data; - if (action->type == FLT_ACTION_MOVE || - action->type == FLT_ACTION_NOT_RECEIVE || - action->type == FLT_ACTION_DELETE) - break; - } - - str = g_strdup_printf - ("%s:%s:%c:%s:%s:%s:%d:%d:%c", - cond1->header_name, cond1->str_value ? cond1->str_value : "", - (cond2 && cond2->header_name) ? - (rule->bool_op == FLT_AND ? '&' : '|') : ' ', - (cond2 && cond2->header_name) ? cond2->header_name : "", - (cond2 && cond2->str_value) ? cond2->str_value : "", - (action && action->str_value) ? action->str_value : "", - flag1, flag2, - (action && action->type == FLT_ACTION_MOVE) ? 'm' : - (action && action->type == FLT_ACTION_NOT_RECEIVE) ? 'n' : - (action && action->type == FLT_ACTION_DELETE) ? 'd' : ' '); - - return str; -} - -#define PARSE_ONE_PARAM(p, srcp) \ -{ \ - p = strchr(srcp, '\t'); \ - if (!p) return NULL; \ - else \ - *p++ = '\0'; \ -} - -FilterRule *filter_read_str(const gchar *str) -{ - FilterRule *rule; - FilterBoolOp bool_op; - gint flag; - FilterCond *cond; - FilterMatchType match_type; - FilterMatchFlag match_flag; - FilterAction *action; - GSList *cond_list = NULL; - GSList *action_list = NULL; - gchar *tmp; - gchar *rule_name; - gchar *name1, *body1, *op, *name2, *body2, *dest; - gchar *flag1 = NULL, *flag2 = NULL, *action1 = NULL; - - Xstrdup_a(tmp, str, return NULL); - - name1 = tmp; - PARSE_ONE_PARAM(body1, name1); - PARSE_ONE_PARAM(op, body1); - PARSE_ONE_PARAM(name2, op); - PARSE_ONE_PARAM(body2, name2); - PARSE_ONE_PARAM(dest, body2); - if (strchr(dest, '\t')) { - gchar *p; - - PARSE_ONE_PARAM(flag1, dest); - PARSE_ONE_PARAM(flag2, flag1); - PARSE_ONE_PARAM(action1, flag2); - if ((p = strchr(action1, '\t'))) *p = '\0'; - } - - bool_op = (*op == '&') ? FLT_AND : FLT_OR; - - if (*name1) { - if (flag1) - flag = (FilterOldFlag)strtoul(flag1, NULL, 10); - else - flag = FLT_O_CONTAIN; - match_type = FLT_CONTAIN; - match_flag = 0; - if (flag & FLT_O_REGEX) - match_type = FLT_REGEX; - else if (!(flag & FLT_O_CONTAIN)) - match_flag = FLT_NOT_MATCH; - if (flag & FLT_O_CASE_SENS) - match_flag |= FLT_CASE_SENS; - cond = filter_cond_new(FLT_COND_HEADER, match_type, match_flag, - name1, body1); - cond_list = g_slist_append(cond_list, cond); - } - if (*name2) { - if (flag2) - flag = (FilterOldFlag)strtoul(flag2, NULL, 10); - else - flag = FLT_O_CONTAIN; - match_type = FLT_CONTAIN; - match_flag = 0; - if (flag & FLT_O_REGEX) - match_type = FLT_REGEX; - else if (!(flag & FLT_O_CONTAIN)) - match_flag = FLT_NOT_MATCH; - if (flag & FLT_O_CASE_SENS) - match_flag |= FLT_CASE_SENS; - cond = filter_cond_new(FLT_COND_HEADER, match_type, match_flag, - name2, body2); - cond_list = g_slist_append(cond_list, cond); - } - - action = filter_action_new(FLT_ACTION_MOVE, - *dest ? g_strdup(dest) : NULL); - if (action1) { - switch (*action1) { - case 'm': action->type = FLT_ACTION_MOVE; break; - case 'n': action->type = FLT_ACTION_NOT_RECEIVE; break; - case 'd': action->type = FLT_ACTION_DELETE; break; - default: g_warning("Invalid action: `%c'\n", *action1); - } - } - action_list = g_slist_append(action_list, action); - - Xstrdup_a(rule_name, str, return NULL); - subst_char(rule_name, '\t', ':'); - - rule = filter_rule_new(rule_name, bool_op, cond_list, action_list); - - return rule; -} - -FilterRule *filter_rule_new(const gchar *name, FilterBoolOp bool_op, - GSList *cond_list, GSList *action_list) -{ - FilterRule *rule; - - rule = g_new0(FilterRule, 1); - rule->name = g_strdup(name); - rule->bool_op = bool_op; - rule->cond_list = cond_list; - rule->action_list = action_list; - rule->timing = FLT_TIMING_ANY; - rule->enabled = TRUE; - - return rule; -} - -FilterCond *filter_cond_new(FilterCondType type, - FilterMatchType match_type, - FilterMatchFlag match_flag, - const gchar *header, const gchar *value) -{ - FilterCond *cond; - - cond = g_new0(FilterCond, 1); - cond->type = type; - cond->match_type = match_type; - cond->match_flag = match_flag; - - if (type == FLT_COND_HEADER) - cond->header_name = - (header && *header) ? g_strdup(header) : NULL; - else - cond->header_name = NULL; - - cond->str_value = (value && *value) ? g_strdup(value) : NULL; - if (type == FLT_COND_SIZE_GREATER || type == FLT_COND_AGE_GREATER) - cond->int_value = atoi(value); - else - cond->int_value = 0; - - if (match_type == FLT_REGEX) - cond->match_func = strmatch_regex; - else if (match_type == FLT_EQUAL) { - if (FLT_IS_CASE_SENS(match_flag)) - cond->match_func = str_find_equal; - else - cond->match_func = str_case_find_equal; - } else { - if (FLT_IS_CASE_SENS(match_flag)) - cond->match_func = str_find; - else - cond->match_func = str_case_find; - } - - return cond; -} - -FilterAction *filter_action_new(FilterActionType type, const gchar *str) -{ - FilterAction *action; - - action = g_new0(FilterAction, 1); - action->type = type; - - action->str_value = (str && *str) ? g_strdup(str) : NULL; - if (type == FLT_ACTION_COLOR_LABEL && str) - action->int_value = atoi(str); - else - action->int_value = 0; - - return action; -} - -FilterInfo *filter_info_new(void) -{ - FilterInfo *fltinfo; - - fltinfo = g_new0(FilterInfo, 1); - fltinfo->dest_list = NULL; - fltinfo->move_dest = NULL; - fltinfo->drop_done = FALSE; - - return fltinfo; -} - -void filter_rule_rename_dest_path(FilterRule *rule, const gchar *old_path, - const gchar *new_path) -{ - FilterAction *action; - GSList *cur; - gchar *base; - gchar *dest_path; - gint oldpathlen; - - oldpathlen = strlen(old_path); - - for (cur = rule->action_list; cur != NULL; cur = cur->next) { - action = (FilterAction *)cur->data; - - if (action->type != FLT_ACTION_MOVE && - action->type != FLT_ACTION_COPY) - continue; - - if (action->str_value && - !strncmp(old_path, action->str_value, oldpathlen)) { - base = action->str_value + oldpathlen; - if (*base != G_DIR_SEPARATOR && *base != '\0') - continue; - while (*base == G_DIR_SEPARATOR) base++; - if (*base == '\0') - dest_path = g_strdup(new_path); - else - dest_path = g_strconcat(new_path, - G_DIR_SEPARATOR_S, - base, NULL); - debug_print("filter_rule_rename_dest_path(): " - "renaming %s -> %s\n", - action->str_value, dest_path); - g_free(action->str_value); - action->str_value = dest_path; - } - } -} - -void filter_rule_delete_action_by_dest_path(FilterRule *rule, const gchar *path) -{ - FilterAction *action; - GSList *cur; - GSList *next; - gint pathlen; - - pathlen = strlen(path); - - for (cur = rule->action_list; cur != NULL; cur = next) { - action = (FilterAction *)cur->data; - next = cur->next; - - if (action->type != FLT_ACTION_MOVE && - action->type != FLT_ACTION_COPY) - continue; - - if (action->str_value && - !strncmp(path, action->str_value, pathlen) && - (action->str_value[pathlen] == G_DIR_SEPARATOR || - action->str_value[pathlen] == '\0')) { - debug_print("filter_rule_delete_action_by_dest_path(): " - "deleting %s\n", action->str_value); - rule->action_list = g_slist_remove - (rule->action_list, action); - filter_action_free(action); - } - } -} - -void filter_list_rename_path(const gchar *old_path, const gchar *new_path) -{ - GSList *cur; - - g_return_if_fail(old_path != NULL); - g_return_if_fail(new_path != NULL); - - for (cur = prefs_common.fltlist; cur != NULL; cur = cur->next) { - FilterRule *rule = (FilterRule *)cur->data; - filter_rule_rename_dest_path(rule, old_path, new_path); - } - - filter_write_config(); -} - -void filter_list_delete_path(const gchar *path) -{ - GSList *cur; - GSList *next; - - g_return_if_fail(path != NULL); - - for (cur = prefs_common.fltlist; cur != NULL; cur = next) { - FilterRule *rule = (FilterRule *)cur->data; - next = cur->next; - - filter_rule_delete_action_by_dest_path(rule, path); - if (!rule->action_list) { - prefs_common.fltlist = - g_slist_remove(prefs_common.fltlist, rule); - filter_rule_free(rule); - } - } - - filter_write_config(); -} - -void filter_rule_match_type_str_to_enum(const gchar *match_type, - FilterMatchType *type, - FilterMatchFlag *flag) -{ - g_return_if_fail(match_type != NULL); - - *type = FLT_CONTAIN; - *flag = 0; - - if (!strcmp(match_type, "contains")) { - *type = FLT_CONTAIN; - } else if (!strcmp(match_type, "not-contain")) { - *type = FLT_CONTAIN; - *flag = FLT_NOT_MATCH; - } else if (!strcmp(match_type, "is")) { - *type = FLT_EQUAL; - } else if (!strcmp(match_type, "is-not")) { - *type = FLT_EQUAL; - *flag = FLT_NOT_MATCH; - } else if (!strcmp(match_type, "regex")) { - *type = FLT_REGEX; - } else if (!strcmp(match_type, "not-regex")) { - *type = FLT_REGEX; - *flag = FLT_NOT_MATCH; - } else if (!strcmp(match_type, "gt")) { - } else if (!strcmp(match_type, "lt")) { - *flag = FLT_NOT_MATCH; - } -} - -void filter_get_keyword_from_msg(MsgInfo *msginfo, gchar **header, gchar **key, - FilterCreateType type) -{ - static HeaderEntry hentry[] = {{"List-Id:", NULL, TRUE}, - {"X-ML-Name:", NULL, TRUE}, - {"X-List:", NULL, TRUE}, - {"X-Mailing-list:", NULL, TRUE}, - {"X-Sequence:", NULL, TRUE}, - {NULL, NULL, FALSE}}; - enum - { - H_LIST_ID = 0, - H_X_ML_NAME = 1, - H_X_LIST = 2, - H_X_MAILING_LIST = 3, - H_X_SEQUENCE = 4 - }; - - FILE *fp; - - g_return_if_fail(msginfo != NULL); - g_return_if_fail(header != NULL); - g_return_if_fail(key != NULL); - - *header = NULL; - *key = NULL; - - switch (type) { - case FLT_BY_NONE: - return; - case FLT_BY_AUTO: - if ((fp = procmsg_open_message(msginfo)) == NULL) - return; - procheader_get_header_fields(fp, hentry); - fclose(fp); - -#define SET_FILTER_KEY(hstr, idx) \ -{ \ - *header = g_strdup(hstr); \ - *key = hentry[idx].body; \ - hentry[idx].body = NULL; \ -} - - if (hentry[H_LIST_ID].body != NULL) { - SET_FILTER_KEY("List-Id", H_LIST_ID); - extract_list_id_str(*key); - } else if (hentry[H_X_ML_NAME].body != NULL) { - SET_FILTER_KEY("X-ML-Name", H_X_ML_NAME); - } else if (hentry[H_X_LIST].body != NULL) { - SET_FILTER_KEY("X-List", H_X_LIST); - } else if (hentry[H_X_MAILING_LIST].body != NULL) { - SET_FILTER_KEY("X-Mailing-list", H_X_MAILING_LIST); - } else if (hentry[H_X_SEQUENCE].body != NULL) { - gchar *p; - - SET_FILTER_KEY("X-Sequence", H_X_SEQUENCE); - p = *key; - while (*p != '\0') { - while (*p != '\0' && !g_ascii_isspace(*p)) p++; - while (g_ascii_isspace(*p)) p++; - if (g_ascii_isdigit(*p)) { - *p = '\0'; - break; - } - } - g_strstrip(*key); - } else if (msginfo->subject) { - *header = g_strdup("Subject"); - *key = g_strdup(msginfo->subject); - } - -#undef SET_FILTER_KEY - - g_free(hentry[H_LIST_ID].body); - hentry[H_LIST_ID].body = NULL; - g_free(hentry[H_X_ML_NAME].body); - hentry[H_X_ML_NAME].body = NULL; - g_free(hentry[H_X_LIST].body); - hentry[H_X_LIST].body = NULL; - g_free(hentry[H_X_MAILING_LIST].body); - hentry[H_X_MAILING_LIST].body = NULL; - - break; - case FLT_BY_FROM: - *header = g_strdup("From"); - *key = g_strdup(msginfo->from); - break; - case FLT_BY_TO: - *header = g_strdup("To"); - *key = g_strdup(msginfo->to); - break; - case FLT_BY_SUBJECT: - *header = g_strdup("Subject"); - *key = g_strdup(msginfo->subject); - break; - default: - break; - } -} - -void filter_rule_list_free(GSList *fltlist) -{ - GSList *cur; - - for (cur = fltlist; cur != NULL; cur = cur->next) - filter_rule_free((FilterRule *)cur->data); - g_slist_free(fltlist); -} - -void filter_rule_free(FilterRule *rule) -{ - if (!rule) return; - - g_free(rule->name); - - filter_cond_list_free(rule->cond_list); - filter_action_list_free(rule->action_list); - - g_free(rule); -} - -void filter_cond_list_free(GSList *cond_list) -{ - GSList *cur; - - for (cur = cond_list; cur != NULL; cur = cur->next) - filter_cond_free((FilterCond *)cur->data); - g_slist_free(cond_list); -} - -void filter_action_list_free(GSList *action_list) -{ - GSList *cur; - - for (cur = action_list; cur != NULL; cur = cur->next) - filter_action_free((FilterAction *)cur->data); - g_slist_free(action_list); -} - -static void filter_cond_free(FilterCond *cond) -{ - g_free(cond->header_name); - g_free(cond->str_value); - g_free(cond); -} - -static void filter_action_free(FilterAction *action) -{ - g_free(action->str_value); - g_free(action); -} - -void filter_info_free(FilterInfo *fltinfo) -{ - g_slist_free(fltinfo->dest_list); - g_free(fltinfo); -} diff --git a/src/filter.h b/src/filter.h deleted file mode 100644 index dc38047e..00000000 --- a/src/filter.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __FILTER_H__ -#define __FILTER_H__ - -#include <glib.h> - -#include "folder.h" -#include "procmsg.h" -#include "utils.h" - -typedef struct _FilterCond FilterCond; -typedef struct _FilterAction FilterAction; -typedef struct _FilterRule FilterRule; -typedef struct _FilterInfo FilterInfo; - -typedef enum -{ - FLT_TIMING_ANY, - FLT_TIMING_ON_RECEIVE, - FLT_TIMING_MANUAL -} FilterTiming; - -typedef enum -{ - FLT_COND_HEADER, - FLT_COND_ANY_HEADER, - FLT_COND_TO_OR_CC, - FLT_COND_BODY, - FLT_COND_CMD_TEST, - FLT_COND_SIZE_GREATER, - FLT_COND_AGE_GREATER, - FLT_COND_ACCOUNT -} FilterCondType; - -typedef enum -{ - FLT_CONTAIN, - FLT_EQUAL, - FLT_REGEX -} FilterMatchType; - -typedef enum -{ - FLT_NOT_MATCH = 1 << 0, - FLT_CASE_SENS = 1 << 1 -} FilterMatchFlag; - -typedef enum -{ - FLT_OR, - FLT_AND -} FilterBoolOp; - -typedef enum -{ - FLT_ACTION_MOVE, - FLT_ACTION_COPY, - FLT_ACTION_NOT_RECEIVE, - FLT_ACTION_DELETE, - FLT_ACTION_EXEC, - FLT_ACTION_EXEC_ASYNC, - FLT_ACTION_MARK, - FLT_ACTION_COLOR_LABEL, - FLT_ACTION_MARK_READ, - FLT_ACTION_FORWARD, - FLT_ACTION_FORWARD_AS_ATTACHMENT, - FLT_ACTION_REDIRECT, - FLT_ACTION_STOP_EVAL, - FLT_ACTION_NONE -} FilterActionType; - -typedef enum -{ - FLT_BY_NONE, - FLT_BY_AUTO, - FLT_BY_FROM, - FLT_BY_TO, - FLT_BY_SUBJECT -} FilterCreateType; - -#define FLT_IS_NOT_MATCH(flag) ((flag & FLT_NOT_MATCH) != 0) -#define FLT_IS_CASE_SENS(flag) ((flag & FLT_CASE_SENS) != 0) - -struct _FilterCond -{ - FilterCondType type; - - gchar *header_name; - - gchar *str_value; - gint int_value; - - FilterMatchType match_type; - FilterMatchFlag match_flag; - - StrFindFunc match_func; -}; - -struct _FilterAction -{ - FilterActionType type; - - gchar *str_value; - gint int_value; -}; - -struct _FilterRule -{ - gchar *name; - - FilterBoolOp bool_op; - - GSList *cond_list; - GSList *action_list; - - FilterTiming timing; - gboolean enabled; -}; - -struct _FilterInfo -{ - PrefsAccount *account; - MsgFlags flags; - - gboolean actions[FLT_ACTION_NONE]; - GSList *dest_list; - FolderItem *move_dest; - gboolean drop_done; -}; - -gint filter_apply (GSList *fltlist, - const gchar *file, - FilterInfo *fltinfo); -gint filter_apply_msginfo (GSList *fltlist, - MsgInfo *msginfo, - FilterInfo *fltinfo); - -gint filter_action_exec (FilterRule *rule, - MsgInfo *msginfo, - const gchar *file, - FilterInfo *fltinfo); - -gboolean filter_match_rule (FilterRule *rule, - MsgInfo *msginfo, - GSList *hlist, - FilterInfo *fltinfo); - -/* read / write config */ -GSList *filter_xml_node_to_filter_list (GNode *node); -void filter_read_config (void); -void filter_write_config (void); - -/* for old filterrc */ -gchar *filter_get_str (FilterRule *rule); -FilterRule *filter_read_str (const gchar *str); - -FilterRule *filter_rule_new (const gchar *name, - FilterBoolOp bool_op, - GSList *cond_list, - GSList *action_list); -FilterCond *filter_cond_new (FilterCondType type, - FilterMatchType match_type, - FilterMatchFlag match_flag, - const gchar *header, - const gchar *body); -FilterAction *filter_action_new (FilterActionType type, - const gchar *str); -FilterInfo *filter_info_new (void); - -void filter_rule_rename_dest_path (FilterRule *rule, - const gchar *old_path, - const gchar *new_path); -void filter_rule_delete_action_by_dest_path - (FilterRule *rule, - const gchar *path); - -void filter_list_rename_path (const gchar *old_path, - const gchar *new_path); -void filter_list_delete_path (const gchar *path); - -void filter_rule_match_type_str_to_enum (const gchar *type_str, - FilterMatchType *type, - FilterMatchFlag *flag); - -void filter_get_keyword_from_msg (MsgInfo *msginfo, - gchar **header, - gchar **key, - FilterCreateType type); - -void filter_rule_list_free (GSList *fltlist); -void filter_rule_free (FilterRule *rule); -void filter_cond_list_free (GSList *cond_list); -void filter_action_list_free (GSList *action_list); -void filter_info_free (FilterInfo *info); - -#endif /* __FILTER_H__ */ diff --git a/src/folder.c b/src/folder.c deleted file mode 100644 index 25db6b24..00000000 --- a/src/folder.c +++ /dev/null @@ -1,1583 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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 <glib/gi18n.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#include "folder.h" -#include "session.h" -#include "imap.h" -#include "news.h" -#include "mh.h" -#include "utils.h" -#include "xml.h" -#include "codeconv.h" -#include "prefs.h" -#include "account.h" -#include "prefs_account.h" - -static GList *folder_list = NULL; - -static void folder_init (Folder *folder, - const gchar *name); - -static gboolean folder_read_folder_func (GNode *node, - gpointer data); -static gchar *folder_get_list_path (void); -static void folder_write_list_recursive (GNode *node, - gpointer data); - - -Folder *folder_new(FolderType type, const gchar *name, const gchar *path) -{ - Folder *folder = NULL; - - name = name ? name : path; - switch (type) { - case F_MH: - folder = mh_get_class()->folder_new(name, path); - break; - case F_IMAP: - folder = imap_get_class()->folder_new(name, path); - break; - case F_NEWS: - folder = news_get_class()->folder_new(name, path); - break; - default: - return NULL; - } - - return folder; -} - -static void folder_init(Folder *folder, const gchar *name) -{ - FolderItem *item; - - g_return_if_fail(folder != NULL); - - folder_set_name(folder, name); - folder->account = NULL; - folder->inbox = NULL; - folder->outbox = NULL; - folder->draft = NULL; - folder->queue = NULL; - folder->trash = NULL; - folder->ui_func = NULL; - folder->ui_func_data = NULL; - item = folder_item_new(name, NULL); - item->folder = folder; - folder->node = item->node = g_node_new(item); - folder->data = NULL; -} - -void folder_local_folder_init(Folder *folder, const gchar *name, - const gchar *path) -{ - folder_init(folder, name); - LOCAL_FOLDER(folder)->rootpath = g_strdup(path); -} - -void folder_remote_folder_init(Folder *folder, const gchar *name, - const gchar *path) -{ - folder_init(folder, name); - REMOTE_FOLDER(folder)->session = NULL; -} - -void folder_destroy(Folder *folder) -{ - g_return_if_fail(folder != NULL); - g_return_if_fail(folder->klass->destroy != NULL); - - folder->klass->destroy(folder); - - folder_list = g_list_remove(folder_list, folder); - - folder_tree_destroy(folder); - g_free(folder->name); - g_free(folder); -} - -void folder_local_folder_destroy(LocalFolder *lfolder) -{ - g_return_if_fail(lfolder != NULL); - - g_free(lfolder->rootpath); -} - -void folder_remote_folder_destroy(RemoteFolder *rfolder) -{ - g_return_if_fail(rfolder != NULL); - - if (rfolder->session) - session_destroy(rfolder->session); -} - -#if 0 -Folder *mbox_folder_new(const gchar *name, const gchar *path) -{ - /* not yet implemented */ - return NULL; -} - -Folder *maildir_folder_new(const gchar *name, const gchar *path) -{ - /* not yet implemented */ - return NULL; -} -#endif - -FolderItem *folder_item_new(const gchar *name, const gchar *path) -{ - FolderItem *item; - - item = g_new0(FolderItem, 1); - - item->stype = F_NORMAL; - item->name = g_strdup(name); - item->path = g_strdup(path); - item->mtime = 0; - item->new = 0; - item->unread = 0; - item->total = 0; - item->unmarked_num = 0; - item->last_num = -1; - item->no_sub = FALSE; - item->no_select = FALSE; - item->collapsed = FALSE; - item->threaded = TRUE; - item->opened = FALSE; - item->updated = FALSE; - item->cache_dirty = FALSE; - item->mark_dirty = FALSE; - item->node = NULL; - item->parent = NULL; - item->folder = NULL; - item->account = NULL; - item->ac_apply_sub = FALSE; - item->auto_to = NULL; - item->use_auto_to_on_reply = FALSE; - item->auto_cc = NULL; - item->auto_bcc = NULL; - item->auto_replyto = NULL; - item->mark_queue = NULL; - item->data = NULL; - - return item; -} - -void folder_item_append(FolderItem *parent, FolderItem *item) -{ - g_return_if_fail(parent != NULL); - g_return_if_fail(parent->folder != NULL); - g_return_if_fail(parent->node != NULL); - g_return_if_fail(item != NULL); - - item->parent = parent; - item->folder = parent->folder; - item->node = g_node_append_data(parent->node, item); -} - -static gboolean folder_item_remove_func(GNode *node, gpointer data) -{ - FolderItem *item = FOLDER_ITEM(node->data); - - folder_item_destroy(item); - return FALSE; -} - -void folder_item_remove(FolderItem *item) -{ - GNode *node; - - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - g_return_if_fail(item->node != NULL); - - node = item->node; - - if (item->folder->node == node) - item->folder->node = NULL; - - g_node_traverse(node, G_POST_ORDER, G_TRAVERSE_ALL, -1, - folder_item_remove_func, NULL); - g_node_destroy(node); -} - -void folder_item_remove_children(FolderItem *item) -{ - GNode *node, *next; - - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - g_return_if_fail(item->node != NULL); - - node = item->node->children; - while (node != NULL) { - next = node->next; - folder_item_remove(FOLDER_ITEM(node->data)); - node = next; - } -} - -void folder_item_destroy(FolderItem *item) -{ - Folder *folder; - - g_return_if_fail(item != NULL); - - folder = item->folder; - if (folder) { - if (folder->inbox == item) - folder->inbox = NULL; - else if (folder->outbox == item) - folder->outbox = NULL; - else if (folder->draft == item) - folder->draft = NULL; - else if (folder->queue == item) - folder->queue = NULL; - else if (folder->trash == item) - folder->trash = NULL; - } - - g_free(item->name); - g_free(item->path); - g_free(item->auto_to); - g_free(item->auto_cc); - g_free(item->auto_bcc); - g_free(item->auto_replyto); - g_free(item); -} - -gint folder_item_compare(FolderItem *item_a, FolderItem *item_b) -{ - gint ret; - gchar *str_a, *str_b; - - if (!item_a || !item_b) - return 0; - if (!item_a->parent || !item_b->parent) - return 0; - if (!item_a->name || !item_b->name) - return 0; - - /* if both a and b are special folders, sort them according to - * their types (which is in-order). Note that this assumes that - * there are no multiple folders of a special type. */ - if (item_a->stype != F_NORMAL && item_b->stype != F_NORMAL) - return item_a->stype - item_b->stype; - - /* if b is normal folder, and a is not, b is smaller (ends up - * lower in the list) */ - if (item_a->stype != F_NORMAL && item_b->stype == F_NORMAL) - return item_b->stype - item_a->stype; - - /* if b is special folder, and a is not, b is larger (ends up - * higher in the list) */ - if (item_a->stype == F_NORMAL && item_b->stype != F_NORMAL) - return item_b->stype - item_a->stype; - - /* otherwise just compare the folder names */ - str_a = g_utf8_casefold(item_a->name, -1); - str_b = g_utf8_casefold(item_b->name, -1); - ret = g_utf8_collate(str_a, str_b); - g_free(str_b); - g_free(str_a); - - return ret; -} - -void folder_set_ui_func(Folder *folder, FolderUIFunc func, gpointer data) -{ - g_return_if_fail(folder != NULL); - - folder->ui_func = func; - folder->ui_func_data = data; -} - -void folder_set_name(Folder *folder, const gchar *name) -{ - g_return_if_fail(folder != NULL); - - g_free(folder->name); - folder->name = name ? g_strdup(name) : NULL; - if (folder->node && folder->node->data) { - FolderItem *item = (FolderItem *)folder->node->data; - - g_free(item->name); - item->name = name ? g_strdup(name) : NULL; - } -} - -void folder_tree_destroy(Folder *folder) -{ - g_return_if_fail(folder != NULL); - - if (folder->node) - folder_item_remove(FOLDER_ITEM(folder->node->data)); -} - -void folder_add(Folder *folder) -{ - Folder *cur_folder; - GList *cur; - gint i; - - g_return_if_fail(folder != NULL); - - for (i = 0, cur = folder_list; cur != NULL; cur = cur->next, i++) { - cur_folder = FOLDER(cur->data); - if (FOLDER_TYPE(folder) == F_MH) { - if (FOLDER_TYPE(cur_folder) != F_MH) break; - } else if (FOLDER_TYPE(folder) == F_IMAP) { - if (FOLDER_TYPE(cur_folder) != F_MH && - FOLDER_TYPE(cur_folder) != F_IMAP) break; - } else if (FOLDER_TYPE(folder) == F_NEWS) { - if (FOLDER_TYPE(cur_folder) != F_MH && - FOLDER_TYPE(cur_folder) != F_IMAP && - FOLDER_TYPE(cur_folder) != F_NEWS) break; - } - } - - folder_list = g_list_insert(folder_list, folder, i); -} - -GList *folder_get_list(void) -{ - return folder_list; -} - -gint folder_read_list(void) -{ - GNode *node; - XMLNode *xmlnode; - gchar *path; - - path = folder_get_list_path(); - if (!is_file_exist(path)) return -1; - node = xml_parse_file(path); - if (!node) return -1; - - xmlnode = node->data; - if (strcmp2(xmlnode->tag->tag, "folderlist") != 0) { - g_warning("wrong folder list\n"); - xml_free_tree(node); - return -1; - } - - g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, 2, - folder_read_folder_func, NULL); - - xml_free_tree(node); - if (folder_list) - return 0; - else - return -1; -} - -void folder_write_list(void) -{ - GList *list; - Folder *folder; - gchar *path; - PrefFile *pfile; - - path = folder_get_list_path(); - if ((pfile = prefs_file_open(path)) == NULL) return; - - fprintf(pfile->fp, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", - CS_INTERNAL); - fputs("\n<folderlist>\n", pfile->fp); - - for (list = folder_list; list != NULL; list = list->next) { - folder = list->data; - folder_write_list_recursive(folder->node, pfile->fp); - } - - fputs("</folderlist>\n", pfile->fp); - - if (prefs_file_close(pfile) < 0) - g_warning("failed to write folder list.\n"); -} - -struct TotalMsgStatus -{ - guint new; - guint unread; - guint total; - GString *str; -}; - -static gboolean folder_get_status_full_all_func(GNode *node, gpointer data) -{ - FolderItem *item; - struct TotalMsgStatus *status = (struct TotalMsgStatus *)data; - gchar *id; - - g_return_val_if_fail(node->data != NULL, FALSE); - - item = FOLDER_ITEM(node->data); - - if (!item->path) return FALSE; - - status->new += item->new; - status->unread += item->unread; - status->total += item->total; - - if (status->str) { - id = folder_item_get_identifier(item); - g_string_sprintfa(status->str, "%5d %5d %5d %s\n", - item->new, item->unread, - item->total, id); - g_free(id); - } - - return FALSE; -} - -static void folder_get_status_full_all(GString *str, guint *new, guint *unread, - guint *total) -{ - GList *list; - Folder *folder; - struct TotalMsgStatus status; - - status.new = status.unread = status.total = 0; - status.str = str; - - debug_print("Counting total number of messages...\n"); - - for (list = folder_list; list != NULL; list = list->next) { - folder = FOLDER(list->data); - if (folder->node) - g_node_traverse(folder->node, G_PRE_ORDER, - G_TRAVERSE_ALL, -1, - folder_get_status_full_all_func, - &status); - } - - *new = status.new; - *unread = status.unread; - *total = status.total; -} - -gchar *folder_get_status(GPtrArray *folders, gboolean full) -{ - guint new, unread, total; - GString *str; - gint i; - gchar *ret; - - new = unread = total = 0; - - str = g_string_new(NULL); - - if (folders) { - for (i = 0; i < folders->len; i++) { - FolderItem *item; - - item = g_ptr_array_index(folders, i); - new += item->new; - unread += item->unread; - total += item->total; - - if (full) { - gchar *id; - - id = folder_item_get_identifier(item); - g_string_sprintfa(str, "%5d %5d %5d %s\n", - item->new, item->unread, - item->total, id); - g_free(id); - } - } - } else { - folder_get_status_full_all(full ? str : NULL, - &new, &unread, &total); - } - - if (full) - g_string_sprintfa(str, "%5d %5d %5d\n", new, unread, total); - else - g_string_sprintfa(str, "%d %d %d\n", new, unread, total); - - ret = str->str; - g_string_free(str, FALSE); - - return ret; -} - -Folder *folder_find_from_path(const gchar *path) -{ - GList *list; - Folder *folder; - - for (list = folder_list; list != NULL; list = list->next) { - folder = list->data; - if (FOLDER_TYPE(folder) == F_MH && - !path_cmp(LOCAL_FOLDER(folder)->rootpath, path)) - return folder; - } - - return NULL; -} - -Folder *folder_find_from_name(const gchar *name, FolderType type) -{ - GList *list; - Folder *folder; - - for (list = folder_list; list != NULL; list = list->next) { - folder = list->data; - if (FOLDER_TYPE(folder) == type && - strcmp2(name, folder->name) == 0) - return folder; - } - - return NULL; -} - -static gboolean folder_item_find_func(GNode *node, gpointer data) -{ - FolderItem *item = node->data; - gpointer *d = data; - const gchar *path = d[0]; - - if (path_cmp(path, item->path) != 0) - return FALSE; - - d[1] = item; - - return TRUE; -} - -FolderItem *folder_find_item_from_path(const gchar *path) -{ - Folder *folder; - gpointer d[2]; - - folder = folder_get_default_folder(); - g_return_val_if_fail(folder != NULL, NULL); - - d[0] = (gpointer)path; - d[1] = NULL; - g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, - folder_item_find_func, d); - return d[1]; -} - -FolderItem *folder_find_child_item_by_name(FolderItem *item, const gchar *name) -{ - GNode *node; - FolderItem *child; - - for (node = item->node->children; node != NULL; node = node->next) { - child = FOLDER_ITEM(node->data); - if (strcmp2(g_basename(child->path), name) == 0) - return child; - } - - return NULL; -} - -static const struct { - gchar *str; - FolderType type; -} type_str_table[] = { - {"#mh" , F_MH}, - {"#mbox" , F_MBOX}, - {"#maildir", F_MAILDIR}, - {"#imap" , F_IMAP}, - {"#news" , F_NEWS} -}; - -static gchar *folder_get_type_string(FolderType type) -{ - gint i; - - for (i = 0; i < sizeof(type_str_table) / sizeof(type_str_table[0]); - i++) { - if (type_str_table[i].type == type) - return type_str_table[i].str; - } - - return NULL; -} - -static FolderType folder_get_type_from_string(const gchar *str) -{ - gint i; - - for (i = 0; i < sizeof(type_str_table) / sizeof(type_str_table[0]); - i++) { - if (g_ascii_strcasecmp(type_str_table[i].str, str) == 0) - return type_str_table[i].type; - } - - return F_UNKNOWN; -} - -gchar *folder_get_identifier(Folder *folder) -{ - gchar *type_str; - - g_return_val_if_fail(folder != NULL, NULL); - - type_str = folder_get_type_string(FOLDER_TYPE(folder)); - return g_strconcat(type_str, "/", folder->name, NULL); -} - -gchar *folder_item_get_identifier(FolderItem *item) -{ - gchar *id; - gchar *folder_id; - - g_return_val_if_fail(item != NULL, NULL); - - if (!item->path) { - if (!item->parent) - return folder_get_identifier(item->folder); - else - return NULL; - } - - folder_id = folder_get_identifier(item->folder); - id = g_strconcat(folder_id, "/", item->path, NULL); -#ifdef G_OS_WIN32 - subst_char(id, G_DIR_SEPARATOR, '/'); -#endif - g_free(folder_id); - - return id; -} - -FolderItem *folder_find_item_from_identifier(const gchar *identifier) -{ - Folder *folder; - gpointer d[2]; - gchar *str; - gchar *p; - gchar *name; - gchar *path; - FolderType type; - - g_return_val_if_fail(identifier != NULL, NULL); - - if (*identifier != '#') - return folder_find_item_from_path(identifier); - - Xstrdup_a(str, identifier, return NULL); - - p = strchr(str, '/'); - if (!p) - return folder_find_item_from_path(identifier); - *p = '\0'; - p++; - type = folder_get_type_from_string(str); - if (type == F_UNKNOWN) - return folder_find_item_from_path(identifier); - - name = p; - p = strchr(p, '/'); - if (!p) - return folder_find_item_from_path(identifier); - *p = '\0'; - p++; - - folder = folder_find_from_name(name, type); - if (!folder) - return folder_find_item_from_path(identifier); - - path = p; - - d[0] = (gpointer)path; - d[1] = NULL; - g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, - folder_item_find_func, d); - return d[1]; -} - -Folder *folder_get_default_folder(void) -{ - return folder_list ? FOLDER(folder_list->data) : NULL; -} - -FolderItem *folder_get_default_inbox(void) -{ - Folder *folder; - - if (!folder_list) return NULL; - folder = FOLDER(folder_list->data); - g_return_val_if_fail(folder != NULL, NULL); - return folder->inbox; -} - -FolderItem *folder_get_default_outbox(void) -{ - Folder *folder; - - if (!folder_list) return NULL; - folder = FOLDER(folder_list->data); - g_return_val_if_fail(folder != NULL, NULL); - return folder->outbox; -} - -FolderItem *folder_get_default_draft(void) -{ - Folder *folder; - - if (!folder_list) return NULL; - folder = FOLDER(folder_list->data); - g_return_val_if_fail(folder != NULL, NULL); - return folder->draft; -} - -FolderItem *folder_get_default_queue(void) -{ - Folder *folder; - - if (!folder_list) return NULL; - folder = FOLDER(folder_list->data); - g_return_val_if_fail(folder != NULL, NULL); - return folder->queue; -} - -FolderItem *folder_get_default_trash(void) -{ - Folder *folder; - - if (!folder_list) return NULL; - folder = FOLDER(folder_list->data); - g_return_val_if_fail(folder != NULL, NULL); - return folder->trash; -} - -#define CREATE_FOLDER_IF_NOT_EXIST(member, dir, type) \ -{ \ - if (!folder->member) { \ - item = folder_item_new(dir, dir); \ - item->stype = type; \ - folder_item_append(rootitem, item); \ - folder->member = item; \ - } \ -} - -void folder_set_missing_folders(void) -{ - Folder *folder; - FolderItem *rootitem; - FolderItem *item; - GList *list; - - for (list = folder_list; list != NULL; list = list->next) { - folder = list->data; - if (FOLDER_TYPE(folder) != F_MH) continue; - rootitem = FOLDER_ITEM(folder->node->data); - g_return_if_fail(rootitem != NULL); - - if (folder->inbox && folder->outbox && folder->draft && - folder->queue && folder->trash) - continue; - - if (folder->klass->create_tree(folder) < 0) { - g_warning("%s: can't create the folder tree.\n", - LOCAL_FOLDER(folder)->rootpath); - continue; - } - - CREATE_FOLDER_IF_NOT_EXIST(inbox, INBOX_DIR, F_INBOX); - CREATE_FOLDER_IF_NOT_EXIST(outbox, OUTBOX_DIR, F_OUTBOX); - CREATE_FOLDER_IF_NOT_EXIST(draft, DRAFT_DIR, F_DRAFT); - CREATE_FOLDER_IF_NOT_EXIST(queue, QUEUE_DIR, F_QUEUE); - CREATE_FOLDER_IF_NOT_EXIST(trash, TRASH_DIR, F_TRASH); - } -} - -static gboolean folder_unref_account_func(GNode *node, gpointer data) -{ - FolderItem *item = node->data; - PrefsAccount *account = data; - - if (item->account == account) - item->account = NULL; - - return FALSE; -} - -void folder_unref_account_all(PrefsAccount *account) -{ - Folder *folder; - GList *list; - - if (!account) return; - - for (list = folder_list; list != NULL; list = list->next) { - folder = list->data; - if (folder->account == account) - folder->account = NULL; - g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, - folder_unref_account_func, account); - } -} - -#undef CREATE_FOLDER_IF_NOT_EXIST - -gchar *folder_get_path(Folder *folder) -{ - gchar *path; - - g_return_val_if_fail(folder != NULL, NULL); - - if (FOLDER_TYPE(folder) == F_MH) { - path = g_filename_from_utf8(LOCAL_FOLDER(folder)->rootpath, - -1, NULL, NULL, NULL); - if (!path) { - g_warning("folder_get_path: faild to convert character set\n"); - path = g_strdup(LOCAL_FOLDER(folder)->rootpath); - } - } else if (FOLDER_TYPE(folder) == F_IMAP) { - g_return_val_if_fail(folder->account != NULL, NULL); - path = g_strconcat(get_imap_cache_dir(), - G_DIR_SEPARATOR_S, - folder->account->recv_server, - G_DIR_SEPARATOR_S, - folder->account->userid, - NULL); - } else if (FOLDER_TYPE(folder) == F_NEWS) { - g_return_val_if_fail(folder->account != NULL, NULL); - path = g_strconcat(get_news_cache_dir(), - G_DIR_SEPARATOR_S, - folder->account->nntp_server, - NULL); - } else - path = NULL; - - return path; -} - -gchar *folder_item_get_path(FolderItem *item) -{ - gchar *folder_path; - gchar *item_path = NULL, *path; - - g_return_val_if_fail(item != NULL, NULL); - - folder_path = folder_get_path(item->folder); - g_return_val_if_fail(folder_path != NULL, NULL); - - if (item->path) { - item_path = g_filename_from_utf8(item->path, -1, - NULL, NULL, NULL); - if (!item_path) { - g_warning("folder_item_get_path: faild to convert character set\n"); - item_path = g_strdup(item->path); - } -#ifdef G_OS_WIN32 - subst_char(item_path, '/', G_DIR_SEPARATOR); -#endif - } - - if (g_path_is_absolute(folder_path)) { - if (item_path) - path = g_strconcat(folder_path, G_DIR_SEPARATOR_S, - item_path, NULL); - else - path = g_strdup(folder_path); - } else { - if (item_path) - path = g_strconcat(get_mail_base_dir(), - G_DIR_SEPARATOR_S, folder_path, - G_DIR_SEPARATOR_S, item_path, NULL); - else - path = g_strconcat(get_mail_base_dir(), - G_DIR_SEPARATOR_S, folder_path, - NULL); - } - - g_free(item_path); - g_free(folder_path); - return path; -} - -gint folder_item_scan(FolderItem *item) -{ - Folder *folder; - - g_return_val_if_fail(item != NULL, -1); - - folder = item->folder; - return folder->klass->scan(folder, item); -} - -static void folder_item_scan_foreach_func(gpointer key, gpointer val, - gpointer data) -{ - folder_item_scan(FOLDER_ITEM(key)); -} - -void folder_item_scan_foreach(GHashTable *table) -{ - g_hash_table_foreach(table, folder_item_scan_foreach_func, NULL); -} - -GSList *folder_item_get_msg_list(FolderItem *item, gboolean use_cache) -{ - Folder *folder; - - g_return_val_if_fail(item != NULL, NULL); - - folder = item->folder; - return folder->klass->get_msg_list(folder, item, use_cache); -} - -gchar *folder_item_fetch_msg(FolderItem *item, gint num) -{ - Folder *folder; - - g_return_val_if_fail(item != NULL, NULL); - - folder = item->folder; - - return folder->klass->fetch_msg(folder, item, num); -} - -gint folder_item_fetch_all_msg(FolderItem *item) -{ - Folder *folder; - GSList *mlist; - GSList *cur; - gint num = 0; - gint ret = 0; - - g_return_val_if_fail(item != NULL, -1); - - debug_print("fetching all messages in %s ...\n", item->path); - - folder = item->folder; - - if (folder->ui_func) - folder->ui_func(folder, item, folder->ui_func_data ? - folder->ui_func_data : GINT_TO_POINTER(num)); - - mlist = folder_item_get_msg_list(item, TRUE); - - for (cur = mlist; cur != NULL; cur = cur->next) { - MsgInfo *msginfo = (MsgInfo *)cur->data; - gchar *msg; - - num++; - if (folder->ui_func) - folder->ui_func(folder, item, - folder->ui_func_data ? - folder->ui_func_data : - GINT_TO_POINTER(num)); - - msg = folder_item_fetch_msg(item, msginfo->msgnum); - if (!msg) { - g_warning("Can't fetch message %d. Aborting.\n", - msginfo->msgnum); - ret = -1; - break; - } - g_free(msg); - } - - procmsg_msg_list_free(mlist); - - return ret; -} - -MsgInfo *folder_item_get_msginfo(FolderItem *item, gint num) -{ - Folder *folder; - - g_return_val_if_fail(item != NULL, NULL); - - folder = item->folder; - - return folder->klass->get_msginfo(folder, item, num); -} - -gint folder_item_add_msg(FolderItem *dest, const gchar *file, MsgFlags *flags, - gboolean remove_source) -{ - Folder *folder; - - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(file != NULL, -1); - g_return_val_if_fail(dest->folder->klass->add_msg != NULL, -1); - - folder = dest->folder; - - return folder->klass->add_msg(folder, dest, file, flags, remove_source); -} - -gint folder_item_add_msgs(FolderItem *dest, GSList *file_list, - gboolean remove_source, gint *first) -{ - Folder *folder; - - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(file_list != NULL, -1); - g_return_val_if_fail(dest->folder->klass->add_msgs != NULL, -1); - - folder = dest->folder; - - return folder->klass->add_msgs(folder, dest, file_list, remove_source, - first); -} - -gint folder_item_move_msg(FolderItem *dest, MsgInfo *msginfo) -{ - Folder *folder; - - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(msginfo != NULL, -1); - g_return_val_if_fail(dest->folder->klass->move_msg != NULL, -1); - - folder = dest->folder; - - return folder->klass->move_msg(folder, dest, msginfo); -} - -gint folder_item_move_msgs(FolderItem *dest, GSList *msglist) -{ - Folder *folder; - - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(msglist != NULL, -1); - g_return_val_if_fail(dest->folder->klass->move_msgs != NULL, -1); - - folder = dest->folder; - - return folder->klass->move_msgs(folder, dest, msglist); -} - -gint folder_item_copy_msg(FolderItem *dest, MsgInfo *msginfo) -{ - Folder *folder; - - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(msginfo != NULL, -1); - g_return_val_if_fail(dest->folder->klass->copy_msg != NULL, -1); - - folder = dest->folder; - - return folder->klass->copy_msg(folder, dest, msginfo); -} - -gint folder_item_copy_msgs(FolderItem *dest, GSList *msglist) -{ - Folder *folder; - - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(msglist != NULL, -1); - g_return_val_if_fail(dest->folder->klass->copy_msgs != NULL, -1); - - folder = dest->folder; - - return folder->klass->copy_msgs(folder, dest, msglist); -} - -gint folder_item_remove_msg(FolderItem *item, MsgInfo *msginfo) -{ - Folder *folder; - - g_return_val_if_fail(item != NULL, -1); - g_return_val_if_fail(item->folder->klass->remove_msg != NULL, -1); - - folder = item->folder; - - return folder->klass->remove_msg(folder, item, msginfo); -} - -gint folder_item_remove_msgs(FolderItem *item, GSList *msglist) -{ - Folder *folder; - gint ret = 0; - - g_return_val_if_fail(item != NULL, -1); - - folder = item->folder; - if (folder->klass->remove_msgs) { - return folder->klass->remove_msgs(folder, item, msglist); - } - - while (msglist != NULL) { - MsgInfo *msginfo = (MsgInfo *)msglist->data; - - ret = folder_item_remove_msg(item, msginfo); - if (ret != 0) break; - msglist = msglist->next; - } - - return ret; -} - -gint folder_item_remove_all_msg(FolderItem *item) -{ - Folder *folder; - - g_return_val_if_fail(item != NULL, -1); - g_return_val_if_fail(item->folder->klass->remove_all_msg != NULL, -1); - - folder = item->folder; - - return folder->klass->remove_all_msg(folder, item); -} - -gboolean folder_item_is_msg_changed(FolderItem *item, MsgInfo *msginfo) -{ - Folder *folder; - - g_return_val_if_fail(item != NULL, FALSE); - g_return_val_if_fail(item->folder->klass->is_msg_changed != NULL, - FALSE); - - folder = item->folder; - return folder->klass->is_msg_changed(folder, item, msginfo); -} - -gint folder_item_close(FolderItem *item) -{ - Folder *folder; - - g_return_val_if_fail(item != NULL, -1); - - item->opened = FALSE; - folder = item->folder; - return folder->klass->close(folder, item); -} - -gchar *folder_item_get_cache_file(FolderItem *item) -{ - gchar *path; - gchar *file; - - g_return_val_if_fail(item != NULL, NULL); - g_return_val_if_fail(item->path != NULL, NULL); - - path = folder_item_get_path(item); - g_return_val_if_fail(path != NULL, NULL); - if (!is_dir_exist(path)) - make_dir_hier(path); - file = g_strconcat(path, G_DIR_SEPARATOR_S, CACHE_FILE, NULL); - g_free(path); - - return file; -} - -gchar *folder_item_get_mark_file(FolderItem *item) -{ - gchar *path; - gchar *file; - - g_return_val_if_fail(item != NULL, NULL); - g_return_val_if_fail(item->path != NULL, NULL); - - path = folder_item_get_path(item); - g_return_val_if_fail(path != NULL, NULL); - if (!is_dir_exist(path)) - make_dir_hier(path); - file = g_strconcat(path, G_DIR_SEPARATOR_S, MARK_FILE, NULL); - g_free(path); - - return file; -} - -static gboolean folder_build_tree(GNode *node, gpointer data) -{ - Folder *folder = FOLDER(data); - FolderItem *item; - XMLNode *xmlnode; - GList *list; - SpecialFolderItemType stype = F_NORMAL; - const gchar *name = NULL; - const gchar *path = NULL; - PrefsAccount *account = NULL; - gboolean no_sub = FALSE, no_select = FALSE, collapsed = FALSE, - threaded = TRUE, ac_apply_sub = FALSE; - FolderSortKey sort_key = SORT_BY_NONE; - FolderSortType sort_type = SORT_ASCENDING; - gint new = 0, unread = 0, total = 0; - time_t mtime = 0; - gboolean use_auto_to_on_reply = FALSE; - gchar *auto_to = NULL, *auto_cc = NULL, *auto_bcc = NULL, - *auto_replyto = NULL; - gboolean trim_summary_subject = FALSE, trim_compose_subject = FALSE; - - g_return_val_if_fail(node->data != NULL, FALSE); - if (!node->parent) return FALSE; - - xmlnode = node->data; - if (strcmp2(xmlnode->tag->tag, "folderitem") != 0) { - g_warning("tag name != \"folderitem\"\n"); - return FALSE; - } - - list = xmlnode->tag->attr; - for (; list != NULL; list = list->next) { - XMLAttr *attr = list->data; - - if (!attr || !attr->name || !attr->value) continue; - if (!strcmp(attr->name, "type")) { - if (!g_ascii_strcasecmp(attr->value, "normal")) - stype = F_NORMAL; - else if (!g_ascii_strcasecmp(attr->value, "inbox")) - stype = F_INBOX; - else if (!g_ascii_strcasecmp(attr->value, "outbox")) - stype = F_OUTBOX; - else if (!g_ascii_strcasecmp(attr->value, "draft")) - stype = F_DRAFT; - else if (!g_ascii_strcasecmp(attr->value, "queue")) - stype = F_QUEUE; - else if (!g_ascii_strcasecmp(attr->value, "trash")) - stype = F_TRASH; - } else if (!strcmp(attr->name, "name")) - name = attr->value; - else if (!strcmp(attr->name, "path")) - path = attr->value; - else if (!strcmp(attr->name, "mtime")) - mtime = strtoul(attr->value, NULL, 10); - else if (!strcmp(attr->name, "new")) - new = atoi(attr->value); - else if (!strcmp(attr->name, "unread")) - unread = atoi(attr->value); - else if (!strcmp(attr->name, "total")) - total = atoi(attr->value); - else if (!strcmp(attr->name, "no_sub")) - no_sub = *attr->value == '1' ? TRUE : FALSE; - else if (!strcmp(attr->name, "no_select")) - no_select = *attr->value == '1' ? TRUE : FALSE; - else if (!strcmp(attr->name, "collapsed")) - collapsed = *attr->value == '1' ? TRUE : FALSE; - else if (!strcmp(attr->name, "threaded")) - threaded = *attr->value == '1' ? TRUE : FALSE; - else if (!strcmp(attr->name, "sort_key")) { - if (!strcmp(attr->value, "none")) - sort_key = SORT_BY_NONE; - else if (!strcmp(attr->value, "number")) - sort_key = SORT_BY_NUMBER; - else if (!strcmp(attr->value, "size")) - sort_key = SORT_BY_SIZE; - else if (!strcmp(attr->value, "date")) - sort_key = SORT_BY_DATE; - else if (!strcmp(attr->value, "from")) - sort_key = SORT_BY_FROM; - else if (!strcmp(attr->value, "subject")) - sort_key = SORT_BY_SUBJECT; - else if (!strcmp(attr->value, "score")) - sort_key = SORT_BY_SCORE; - else if (!strcmp(attr->value, "label")) - sort_key = SORT_BY_LABEL; - else if (!strcmp(attr->value, "mark")) - sort_key = SORT_BY_MARK; - else if (!strcmp(attr->value, "unread")) - sort_key = SORT_BY_UNREAD; - else if (!strcmp(attr->value, "mime")) - sort_key = SORT_BY_MIME; - else if (!strcmp(attr->value, "to")) - sort_key = SORT_BY_TO; - } else if (!strcmp(attr->name, "sort_type")) { - if (!strcmp(attr->value, "ascending")) - sort_type = SORT_ASCENDING; - else - sort_type = SORT_DESCENDING; - } else if (!strcmp(attr->name, "account_id")) { - account = account_find_from_id(atoi(attr->value)); - if (!account) g_warning("account_id: %s not found\n", - attr->value); - } else if (!strcmp(attr->name, "account_apply_sub")) - ac_apply_sub = *attr->value == '1' ? TRUE : FALSE; - else if (!strcmp(attr->name, "to")) - auto_to = g_strdup(attr->value); - else if (!strcmp(attr->name, "use_auto_to_on_reply")) - use_auto_to_on_reply = - *attr->value == '1' ? TRUE : FALSE; - else if (!strcmp(attr->name, "cc")) - auto_cc = g_strdup(attr->value); - else if (!strcmp(attr->name, "bcc")) - auto_bcc = g_strdup(attr->value); - else if (!strcmp(attr->name, "replyto")) - auto_replyto = g_strdup(attr->value); - else if (!strcmp(attr->name, "trim_summary_subject")) { - trim_summary_subject = - *attr->value == '1' ? TRUE : FALSE; - } else if (!strcmp(attr->name, "trim_compose_subject")) { - trim_compose_subject = - *attr->value = '1' ? TRUE : FALSE; - } - } - - item = folder_item_new(name, path); - item->stype = stype; - item->mtime = mtime; - item->new = new; - item->unread = unread; - item->total = total; - item->no_sub = no_sub; - item->no_select = no_select; - item->collapsed = collapsed; - item->threaded = threaded; - item->sort_key = sort_key; - item->sort_type = sort_type; - item->node = node; - item->parent = FOLDER_ITEM(node->parent->data); - item->folder = folder; - switch (stype) { - case F_INBOX: folder->inbox = item; break; - case F_OUTBOX: folder->outbox = item; break; - case F_DRAFT: folder->draft = item; break; - case F_QUEUE: folder->queue = item; break; - case F_TRASH: folder->trash = item; break; - default: break; - } - item->account = account; - item->ac_apply_sub = ac_apply_sub; - item->auto_to = auto_to; - item->use_auto_to_on_reply = use_auto_to_on_reply; - item->auto_cc = auto_cc; - item->auto_bcc = auto_bcc; - item->auto_replyto = auto_replyto; - item->trim_summary_subject = trim_summary_subject; - item->trim_compose_subject = trim_compose_subject; - node->data = item; - xml_free_node(xmlnode); - - return FALSE; -} - -static gboolean folder_read_folder_func(GNode *node, gpointer data) -{ - Folder *folder; - FolderItem *item; - XMLNode *xmlnode; - GList *list; - FolderType type = F_UNKNOWN; - const gchar *name = NULL; - const gchar *path = NULL; - PrefsAccount *account = NULL; - gboolean collapsed = FALSE, threaded = TRUE, ac_apply_sub = FALSE; - - if (g_node_depth(node) != 2) return FALSE; - g_return_val_if_fail(node->data != NULL, FALSE); - - xmlnode = node->data; - if (strcmp2(xmlnode->tag->tag, "folder") != 0) { - g_warning("tag name != \"folder\"\n"); - return TRUE; - } - g_node_unlink(node); - list = xmlnode->tag->attr; - for (; list != NULL; list = list->next) { - XMLAttr *attr = list->data; - - if (!attr || !attr->name || !attr->value) continue; - if (!strcmp(attr->name, "type")) { - if (!g_ascii_strcasecmp(attr->value, "mh")) - type = F_MH; - else if (!g_ascii_strcasecmp(attr->value, "mbox")) - type = F_MBOX; - else if (!g_ascii_strcasecmp(attr->value, "maildir")) - type = F_MAILDIR; - else if (!g_ascii_strcasecmp(attr->value, "imap")) - type = F_IMAP; - else if (!g_ascii_strcasecmp(attr->value, "news")) - type = F_NEWS; - } else if (!strcmp(attr->name, "name")) - name = attr->value; - else if (!strcmp(attr->name, "path")) - path = attr->value; - else if (!strcmp(attr->name, "collapsed")) - collapsed = *attr->value == '1' ? TRUE : FALSE; - else if (!strcmp(attr->name, "threaded")) - threaded = *attr->value == '1' ? TRUE : FALSE; - else if (!strcmp(attr->name, "account_id")) { - account = account_find_from_id(atoi(attr->value)); - if (!account) g_warning("account_id: %s not found\n", - attr->value); - } else if (!strcmp(attr->name, "account_apply_sub")) - ac_apply_sub = *attr->value == '1' ? TRUE : FALSE; - } - - folder = folder_new(type, name, path); - g_return_val_if_fail(folder != NULL, FALSE); - folder->account = account; - if (account && (type == F_IMAP || type == F_NEWS)) - account->folder = REMOTE_FOLDER(folder); - item = FOLDER_ITEM(folder->node->data); - node->data = item; - item->node = node; - g_node_destroy(folder->node); - folder->node = node; - folder_add(folder); - item->collapsed = collapsed; - item->threaded = threaded; - item->account = account; - item->ac_apply_sub = ac_apply_sub; - - g_node_traverse(node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, - folder_build_tree, folder); - - return FALSE; -} - -static gchar *folder_get_list_path(void) -{ - static gchar *filename = NULL; - - if (!filename) - filename = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, - FOLDER_LIST, NULL); - - return filename; -} - -#define PUT_ESCAPE_STR(fp, attr, str) \ -{ \ - fputs(" " attr "=\"", fp); \ - xml_file_put_escape_str(fp, str); \ - fputs("\"", fp); \ -} - -static void folder_write_list_recursive(GNode *node, gpointer data) -{ - FILE *fp = (FILE *)data; - FolderItem *item; - gint i, depth; - static gchar *folder_type_str[] = {"mh", "mbox", "maildir", "imap", - "news", "unknown"}; - static gchar *folder_item_stype_str[] = {"normal", "inbox", "outbox", - "draft", "queue", "trash"}; - static gchar *sort_key_str[] = {"none", "number", "size", "date", - "from", "subject", "score", "label", - "mark", "unread", "mime", "to"}; - - g_return_if_fail(node != NULL); - g_return_if_fail(fp != NULL); - - item = FOLDER_ITEM(node->data); - g_return_if_fail(item != NULL); - - depth = g_node_depth(node); - for (i = 0; i < depth; i++) - fputs(" ", fp); - if (depth == 1) { - Folder *folder = item->folder; - - fprintf(fp, "<folder type=\"%s\"", - folder_type_str[FOLDER_TYPE(folder)]); - if (folder->name) - PUT_ESCAPE_STR(fp, "name", folder->name); - if (FOLDER_TYPE(folder) == F_MH) - PUT_ESCAPE_STR(fp, "path", - LOCAL_FOLDER(folder)->rootpath); - if (item->collapsed && node->children) - fputs(" collapsed=\"1\"", fp); - if (folder->account) - fprintf(fp, " account_id=\"%d\"", - folder->account->account_id); - if (item->ac_apply_sub) - fputs(" account_apply_sub=\"1\"", fp); - } else { - fprintf(fp, "<folderitem type=\"%s\"", - folder_item_stype_str[item->stype]); - if (item->name) - PUT_ESCAPE_STR(fp, "name", item->name); - if (item->path) - PUT_ESCAPE_STR(fp, "path", item->path); - - if (item->no_sub) - fputs(" no_sub=\"1\"", fp); - if (item->no_select) - fputs(" no_select=\"1\"", fp); - if (item->collapsed && node->children) - fputs(" collapsed=\"1\"", fp); - if (item->threaded) - fputs(" threaded=\"1\"", fp); - else - fputs(" threaded=\"0\"", fp); - - if (item->sort_key != SORT_BY_NONE) { - fprintf(fp, " sort_key=\"%s\"", - sort_key_str[item->sort_key]); - if (item->sort_type == SORT_ASCENDING) - fprintf(fp, " sort_type=\"ascending\""); - else - fprintf(fp, " sort_type=\"descending\""); - } - - fprintf(fp, - " mtime=\"%lu\" new=\"%d\" unread=\"%d\" total=\"%d\"", - item->mtime, item->new, item->unread, item->total); - - if (item->account) - fprintf(fp, " account_id=\"%d\"", - item->account->account_id); - if (item->ac_apply_sub) - fputs(" account_apply_sub=\"1\"", fp); - - if (item->auto_to) - PUT_ESCAPE_STR(fp, "to", item->auto_to); - if (item->use_auto_to_on_reply) - fputs(" use_auto_to_on_reply=\"1\"", fp); - if (item->auto_cc) - PUT_ESCAPE_STR(fp, "cc", item->auto_cc); - if (item->auto_bcc) - PUT_ESCAPE_STR(fp, "bcc", item->auto_bcc); - if (item->auto_replyto) - PUT_ESCAPE_STR(fp, "replyto", item->auto_replyto); - - if (item->trim_summary_subject) - fputs(" trim_summary_subject=\"1\"", fp); - if (item->trim_compose_subject) - fputs(" trim_compose_subject=\"1\"", fp); - } - - if (node->children) { - GNode *child; - fputs(">\n", fp); - - child = node->children; - while (child) { - GNode *cur; - - cur = child; - child = cur->next; - folder_write_list_recursive(cur, data); - } - - for (i = 0; i < depth; i++) - fputs(" ", fp); - fprintf(fp, "</%s>\n", depth == 1 ? "folder" : "folderitem"); - } else - fputs(" />\n", fp); -} - -#undef PUT_ESCAPE_STR diff --git a/src/folder.h b/src/folder.h deleted file mode 100644 index 0908e241..00000000 --- a/src/folder.h +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __FOLDER_H__ -#define __FOLDER_H__ - -#include <glib.h> -#include <time.h> - -typedef struct _Folder Folder; -typedef struct _FolderClass FolderClass; - -typedef struct _LocalFolder LocalFolder; -typedef struct _RemoteFolder RemoteFolder; -#if 0 -typedef struct _MboxFolder MboxFolder; -typedef struct _MaildirFolder MaildirFolder; -#endif - -typedef struct _FolderItem FolderItem; - -#define FOLDER(obj) ((Folder *)obj) -#define FOLDER_CLASS(obj) (FOLDER(obj)->klass) -#define FOLDER_TYPE(obj) (FOLDER(obj)->klass->type) - -#define LOCAL_FOLDER(obj) ((LocalFolder *)obj) -#define REMOTE_FOLDER(obj) ((RemoteFolder *)obj) - -#define FOLDER_IS_LOCAL(obj) (FOLDER_TYPE(obj) == F_MH || \ - FOLDER_TYPE(obj) == F_MBOX || \ - FOLDER_TYPE(obj) == F_MAILDIR) - -#if 0 -#define MBOX_FOLDER(obj) ((MboxFolder *)obj) -#define MAILDIR_FOLDER(obj) ((MaildirFolder *)obj) -#endif - -#define FOLDER_ITEM(obj) ((FolderItem *)obj) - -#define FOLDER_ITEM_CAN_ADD(obj) \ - ((obj) && FOLDER_ITEM(obj)->folder && \ - FOLDER_ITEM(obj)->path && \ - (FOLDER_IS_LOCAL(FOLDER_ITEM(obj)->folder) || \ - FOLDER_TYPE(FOLDER_ITEM(obj)->folder) == F_IMAP) && \ - !FOLDER_ITEM(obj)->no_select) - -typedef enum -{ - F_MH, - F_MBOX, - F_MAILDIR, - F_IMAP, - F_NEWS, - F_UNKNOWN -} FolderType; - -typedef enum -{ - F_NORMAL, - F_INBOX, - F_OUTBOX, - F_DRAFT, - F_QUEUE, - F_TRASH -} SpecialFolderItemType; - -typedef enum -{ - SORT_BY_NONE, - SORT_BY_NUMBER, - SORT_BY_SIZE, - SORT_BY_DATE, - SORT_BY_FROM, - SORT_BY_SUBJECT, - SORT_BY_SCORE, - SORT_BY_LABEL, - SORT_BY_MARK, - SORT_BY_UNREAD, - SORT_BY_MIME, - SORT_BY_TO -} FolderSortKey; - -typedef enum -{ - SORT_ASCENDING, - SORT_DESCENDING -} FolderSortType; - -typedef void (*FolderUIFunc) (Folder *folder, - FolderItem *item, - gpointer data); -typedef void (*FolderDestroyNotify) (Folder *folder, - FolderItem *item, - gpointer data); - -#include "prefs_account.h" -#include "session.h" -#include "procmsg.h" - -struct _Folder -{ - FolderClass *klass; - - gchar *name; - PrefsAccount *account; - - FolderItem *inbox; - FolderItem *outbox; - FolderItem *draft; - FolderItem *queue; - FolderItem *trash; - - FolderUIFunc ui_func; - gpointer ui_func_data; - - GNode *node; - - gpointer data; -}; - -struct _FolderClass -{ - FolderType type; - - /* virtual functions */ - Folder * (*folder_new) (const gchar *name, - const gchar *path); - void (*destroy) (Folder *folder); - - gint (*scan_tree) (Folder *folder); - gint (*create_tree) (Folder *folder); - - GSList * (*get_msg_list) (Folder *folder, - FolderItem *item, - gboolean use_cache); - /* return value is locale charset */ - gchar * (*fetch_msg) (Folder *folder, - FolderItem *item, - gint num); - MsgInfo * (*get_msginfo) (Folder *folder, - FolderItem *item, - gint num); - gint (*add_msg) (Folder *folder, - FolderItem *dest, - const gchar *file, - MsgFlags *flags, - gboolean remove_source); - gint (*add_msgs) (Folder *folder, - FolderItem *dest, - GSList *file_list, - gboolean remove_source, - gint *first); - gint (*move_msg) (Folder *folder, - FolderItem *dest, - MsgInfo *msginfo); - gint (*move_msgs) (Folder *folder, - FolderItem *dest, - GSList *msglist); - gint (*copy_msg) (Folder *folder, - FolderItem *dest, - MsgInfo *msginfo); - gint (*copy_msgs) (Folder *folder, - FolderItem *dest, - GSList *msglist); - gint (*remove_msg) (Folder *folder, - FolderItem *item, - MsgInfo *msginfo); - gint (*remove_msgs) (Folder *folder, - FolderItem *item, - GSList *msglist); - gint (*remove_all_msg) (Folder *folder, - FolderItem *item); - gboolean (*is_msg_changed) (Folder *folder, - FolderItem *item, - MsgInfo *msginfo); - gint (*close) (Folder *folder, - FolderItem *item); - gint (*scan) (Folder *folder, - FolderItem *item); - - FolderItem * (*create_folder) (Folder *folder, - FolderItem *parent, - const gchar *name); - gint (*rename_folder) (Folder *folder, - FolderItem *item, - const gchar *name); - gint (*move_folder) (Folder *folder, - FolderItem *item, - FolderItem *new_parent); - gint (*remove_folder) (Folder *folder, - FolderItem *item); -}; - -struct _LocalFolder -{ - Folder folder; - - gchar *rootpath; -}; - -struct _RemoteFolder -{ - Folder folder; - - Session *session; -}; - -#if 0 -struct _MboxFolder -{ - LocalFolder lfolder; -}; - -struct _MaildirFolder -{ - LocalFolder lfolder; -}; -#endif - -struct _FolderItem -{ - SpecialFolderItemType stype; - - gchar *name; /* UTF-8 */ - gchar *path; /* UTF-8 */ - - time_t mtime; - - gint new; - gint unread; - gint total; - gint unmarked_num; - - gint last_num; - - /* special flags */ - guint no_sub : 1; /* no child allowed? */ - guint no_select : 1; /* not selectable? */ - guint collapsed : 1; /* collapsed item */ - guint threaded : 1; /* threaded folder view */ - - guint opened : 1; /* opened by summary view */ - guint updated : 1; /* folderview should be updated */ - - guint cache_dirty : 1; /* cache file needs to be updated */ - guint mark_dirty : 1; /* mark file needs to be updated */ - - FolderSortKey sort_key; - FolderSortType sort_type; - - GNode *node; - - FolderItem *parent; - - Folder *folder; - - PrefsAccount *account; - - gboolean ac_apply_sub; - - gchar *auto_to; - gboolean use_auto_to_on_reply; - gchar *auto_cc; - gchar *auto_bcc; - gchar *auto_replyto; - - gboolean trim_summary_subject; - gboolean trim_compose_subject; - - GSList *mark_queue; - - gpointer data; -}; - -Folder *folder_new (FolderType type, - const gchar *name, - const gchar *path); -void folder_local_folder_init (Folder *folder, - const gchar *name, - const gchar *path); -void folder_remote_folder_init (Folder *folder, - const gchar *name, - const gchar *path); - -void folder_destroy (Folder *folder); -void folder_local_folder_destroy (LocalFolder *lfolder); -void folder_remote_folder_destroy(RemoteFolder *rfolder); - -FolderItem *folder_item_new (const gchar *name, - const gchar *path); -void folder_item_append (FolderItem *parent, - FolderItem *item); -void folder_item_remove (FolderItem *item); -void folder_item_remove_children (FolderItem *item); -void folder_item_destroy (FolderItem *item); - -gint folder_item_compare (FolderItem *item_a, - FolderItem *item_b); - -void folder_set_ui_func (Folder *folder, - FolderUIFunc func, - gpointer data); -void folder_set_name (Folder *folder, - const gchar *name); -void folder_tree_destroy (Folder *folder); - -void folder_add (Folder *folder); - -GList *folder_get_list (void); -gint folder_read_list (void); -void folder_write_list (void); - -gchar *folder_get_status (GPtrArray *folders, - gboolean full); - -Folder *folder_find_from_path (const gchar *path); -Folder *folder_find_from_name (const gchar *name, - FolderType type); -FolderItem *folder_find_item_from_path (const gchar *path); -FolderItem *folder_find_child_item_by_name (FolderItem *item, - const gchar *name); -gchar *folder_get_identifier (Folder *folder); -gchar *folder_item_get_identifier (FolderItem *item); -FolderItem *folder_find_item_from_identifier (const gchar *identifier); - -Folder *folder_get_default_folder (void); -FolderItem *folder_get_default_inbox (void); -FolderItem *folder_get_default_outbox (void); -FolderItem *folder_get_default_draft (void); -FolderItem *folder_get_default_queue (void); -FolderItem *folder_get_default_trash (void); - -void folder_set_missing_folders (void); -void folder_unref_account_all (PrefsAccount *account); - -/* return value is locale encoded file name */ -gchar *folder_get_path (Folder *folder); -gchar *folder_item_get_path (FolderItem *item); - -gint folder_item_scan (FolderItem *item); -void folder_item_scan_foreach (GHashTable *table); -GSList *folder_item_get_msg_list (FolderItem *item, - gboolean use_cache); -/* return value is locale charset */ -gchar *folder_item_fetch_msg (FolderItem *item, - gint num); -gint folder_item_fetch_all_msg (FolderItem *item); -MsgInfo *folder_item_get_msginfo (FolderItem *item, - gint num); -gint folder_item_add_msg (FolderItem *dest, - const gchar *file, - MsgFlags *flags, - gboolean remove_source); -gint folder_item_add_msgs (FolderItem *dest, - GSList *file_list, - gboolean remove_source, - gint *first); -gint folder_item_move_msg (FolderItem *dest, - MsgInfo *msginfo); -gint folder_item_move_msgs (FolderItem *dest, - GSList *msglist); -gint folder_item_copy_msg (FolderItem *dest, - MsgInfo *msginfo); -gint folder_item_copy_msgs (FolderItem *dest, - GSList *msglist); -gint folder_item_remove_msg (FolderItem *item, - MsgInfo *msginfo); -gint folder_item_remove_msgs (FolderItem *item, - GSList *msglist); -gint folder_item_remove_all_msg (FolderItem *item); -gboolean folder_item_is_msg_changed (FolderItem *item, - MsgInfo *msginfo); -/* return value is locale chaset */ -gchar *folder_item_get_cache_file (FolderItem *item); -gchar *folder_item_get_mark_file (FolderItem *item); - -gint folder_item_close (FolderItem *item); - -#endif /* __FOLDER_H__ */ diff --git a/src/imap.c b/src/imap.c deleted file mode 100644 index a179c23c..00000000 --- a/src/imap.c +++ /dev/null @@ -1,4105 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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 <glib/gi18n.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <dirent.h> -#include <unistd.h> -#include <ctype.h> -#include <time.h> -#if HAVE_ICONV -# include <iconv.h> -#endif - -#include "imap.h" -#include "socket.h" -#include "ssl.h" -#include "recv.h" -#include "procmsg.h" -#include "procheader.h" -#include "folder.h" -#include "prefs_account.h" -#include "codeconv.h" -#include "md5.h" -#include "base64.h" -#include "utils.h" -#include "prefs_common.h" - -#define IMAP4_PORT 143 -#if USE_SSL -#define IMAPS_PORT 993 -#endif - -#define IMAP_CMD_LIMIT 1000 - -#define QUOTE_IF_REQUIRED(out, str) \ -{ \ - if (*str != '"' && strpbrk(str, " \t(){}%*") != NULL) { \ - gchar *__tmp; \ - gint len; \ - \ - len = strlen(str) + 3; \ - Xalloca(__tmp, len, return IMAP_ERROR); \ - g_snprintf(__tmp, len, "\"%s\"", str); \ - out = __tmp; \ - } else { \ - Xstrdup_a(out, str, return IMAP_ERROR); \ - } \ -} - -static GList *session_list = NULL; - -static void imap_folder_init (Folder *folder, - const gchar *name, - const gchar *path); - -static Folder *imap_folder_new (const gchar *name, - const gchar *path); -static void imap_folder_destroy (Folder *folder); - -static Session *imap_session_new (PrefsAccount *account); -static gint imap_session_connect (IMAPSession *session); -static gint imap_session_reconnect (IMAPSession *session); -static void imap_session_destroy (Session *session); -/* static void imap_session_destroy_all (void); */ - -static gint imap_search_flags (IMAPSession *session, - GArray **uids, - GHashTable **flags_table); -static gint imap_fetch_flags (IMAPSession *session, - GArray **uids, - GHashTable **flags_table); - -static GSList *imap_get_msg_list (Folder *folder, - FolderItem *item, - gboolean use_cache); -static gchar *imap_fetch_msg (Folder *folder, - FolderItem *item, - gint uid); -static MsgInfo *imap_get_msginfo (Folder *folder, - FolderItem *item, - gint uid); -static gint imap_add_msg (Folder *folder, - FolderItem *dest, - const gchar *file, - MsgFlags *flags, - gboolean remove_source); -static gint imap_add_msgs (Folder *folder, - FolderItem *dest, - GSList *file_list, - gboolean remove_source, - gint *first); - -static gint imap_move_msg (Folder *folder, - FolderItem *dest, - MsgInfo *msginfo); -static gint imap_move_msgs (Folder *folder, - FolderItem *dest, - GSList *msglist); -static gint imap_copy_msg (Folder *folder, - FolderItem *dest, - MsgInfo *msginfo); -static gint imap_copy_msgs (Folder *folder, - FolderItem *dest, - GSList *msglist); - -static gint imap_remove_msg (Folder *folder, - FolderItem *item, - MsgInfo *msginfo); -static gint imap_remove_msgs (Folder *folder, - FolderItem *item, - GSList *msglist); -static gint imap_remove_all_msg (Folder *folder, - FolderItem *item); - -static gboolean imap_is_msg_changed (Folder *folder, - FolderItem *item, - MsgInfo *msginfo); - -static gint imap_close (Folder *folder, - FolderItem *item); - -static gint imap_scan_folder (Folder *folder, - FolderItem *item); -static gint imap_scan_tree (Folder *folder); - -static gint imap_create_tree (Folder *folder); - -static FolderItem *imap_create_folder (Folder *folder, - FolderItem *parent, - const gchar *name); -static gint imap_rename_folder (Folder *folder, - FolderItem *item, - const gchar *name); -static gint imap_move_folder (Folder *folder, - FolderItem *item, - FolderItem *new_parent); -static gint imap_remove_folder (Folder *folder, - FolderItem *item); - -static IMAPSession *imap_session_get (Folder *folder); - -static gint imap_greeting (IMAPSession *session); -static gint imap_auth (IMAPSession *session, - const gchar *user, - const gchar *pass, - IMAPAuthType type); - -static gint imap_scan_tree_recursive (IMAPSession *session, - FolderItem *item); -static GSList *imap_parse_list (IMAPSession *session, - const gchar *real_path, - gchar *separator); - -static void imap_create_missing_folders (Folder *folder); -static FolderItem *imap_create_special_folder - (Folder *folder, - SpecialFolderItemType stype, - const gchar *name); - -static gint imap_do_copy_msgs (Folder *folder, - FolderItem *dest, - GSList *msglist, - gboolean remove_source); -static gint imap_remove_msgs_by_seq_set (Folder *folder, - FolderItem *item, - GSList *seq_list); - -static GSList *imap_get_uncached_messages (IMAPSession *session, - FolderItem *item, - guint32 first_uid, - guint32 last_uid, - gboolean update_count); -static void imap_delete_cached_message (FolderItem *item, - guint32 uid); -static GSList *imap_delete_cached_messages (GSList *mlist, - FolderItem *item, - guint32 first_uid, - guint32 last_uid); -static void imap_delete_all_cached_messages (FolderItem *item); - -#if USE_SSL -static SockInfo *imap_open (const gchar *server, - gushort port, - SSLType ssl_type); -#else -static SockInfo *imap_open (const gchar *server, - gushort port); -#endif - -static gint imap_msg_list_change_perm_flags (GSList *msglist, - MsgPermFlags flags, - gboolean is_set); -static gchar *imap_get_flag_str (IMAPFlags flags); -static gint imap_set_message_flags (IMAPSession *session, - const gchar *seq_set, - IMAPFlags flags, - gboolean is_set); -static gint imap_select (IMAPSession *session, - IMAPFolder *folder, - const gchar *path, - gint *exists, - gint *recent, - gint *unseen, - guint32 *uid_validity); -static gint imap_status (IMAPSession *session, - IMAPFolder *folder, - const gchar *path, - gint *messages, - gint *recent, - guint32 *uid_next, - guint32 *uid_validity, - gint *unseen); - -static void imap_parse_namespace (IMAPSession *session, - IMAPFolder *folder); -static void imap_get_namespace_by_list (IMAPSession *session, - IMAPFolder *folder); -static IMAPNameSpace *imap_find_namespace (IMAPFolder *folder, - const gchar *path); -static gchar imap_get_path_separator (IMAPFolder *folder, - const gchar *path); -static gchar *imap_get_real_path (IMAPFolder *folder, - const gchar *path); - -static gchar *imap_parse_atom (IMAPSession *session, - gchar *src, - gchar *dest, - gint dest_len, - GString *str); -static MsgFlags imap_parse_flags (const gchar *flag_str); -static IMAPFlags imap_parse_imap_flags (const gchar *flag_str); -static MsgInfo *imap_parse_envelope (IMAPSession *session, - FolderItem *item, - GString *line_str); - -static gboolean imap_has_capability (IMAPSession *session, - const gchar *capability); -static void imap_capability_free (IMAPSession *session); - -/* low-level IMAP4rev1 commands */ -static gint imap_cmd_capability (IMAPSession *session); -static gint imap_cmd_authenticate - (IMAPSession *session, - const gchar *user, - const gchar *pass, - IMAPAuthType type); -static gint imap_cmd_login (IMAPSession *session, - const gchar *user, - const gchar *pass); -static gint imap_cmd_logout (IMAPSession *session); -static gint imap_cmd_noop (IMAPSession *session); -#if USE_SSL -static gint imap_cmd_starttls (IMAPSession *session); -#endif -static gint imap_cmd_namespace (IMAPSession *session, - gchar **ns_str); -static gint imap_cmd_list (IMAPSession *session, - const gchar *ref, - const gchar *mailbox, - GPtrArray *argbuf); -static gint imap_cmd_do_select (IMAPSession *session, - const gchar *folder, - gboolean examine, - gint *exists, - gint *recent, - gint *unseen, - guint32 *uid_validity); -static gint imap_cmd_select (IMAPSession *session, - const gchar *folder, - gint *exists, - gint *recent, - gint *unseen, - guint32 *uid_validity); -static gint imap_cmd_examine (IMAPSession *session, - const gchar *folder, - gint *exists, - gint *recent, - gint *unseen, - guint32 *uid_validity); -static gint imap_cmd_create (IMAPSession *session, - const gchar *folder); -static gint imap_cmd_rename (IMAPSession *session, - const gchar *oldfolder, - const gchar *newfolder); -static gint imap_cmd_delete (IMAPSession *session, - const gchar *folder); -static gint imap_cmd_envelope (IMAPSession *session, - const gchar *seq_set); -static gint imap_cmd_search (IMAPSession *session, - const gchar *criteria, - GArray **result); -static gint imap_cmd_fetch (IMAPSession *session, - guint32 uid, - const gchar *filename); -static gint imap_cmd_append (IMAPSession *session, - const gchar *destfolder, - const gchar *file, - IMAPFlags flags, - guint32 *new_uid); -static gint imap_cmd_copy (IMAPSession *session, - const gchar *seq_set, - const gchar *destfolder); -static gint imap_cmd_store (IMAPSession *session, - const gchar *seq_set, - const gchar *sub_cmd); -static gint imap_cmd_expunge (IMAPSession *session); -static gint imap_cmd_close (IMAPSession *session); - -static gint imap_cmd_ok (IMAPSession *session, - GPtrArray *argbuf); -static void imap_cmd_gen_send (IMAPSession *session, - const gchar *format, ...); -static gint imap_cmd_gen_recv (IMAPSession *session, - gchar **ret); - -/* misc utility functions */ -static gchar *strchr_cpy (const gchar *src, - gchar ch, - gchar *dest, - gint len); -static gchar *get_quoted (const gchar *src, - gchar ch, - gchar *dest, - gint len); -static gchar *search_array_contain_str (GPtrArray *array, - gchar *str); -static gchar *search_array_str (GPtrArray *array, - gchar *str); -static void imap_path_separator_subst (gchar *str, - gchar separator); - -static gchar *imap_modified_utf7_to_utf8 (const gchar *mutf7_str); -static gchar *imap_utf8_to_modified_utf7 (const gchar *from); - -static GSList *imap_get_seq_set_from_msglist (GSList *msglist); -static void imap_seq_set_free (GSList *seq_list); - -static GHashTable *imap_get_uid_table (GArray *array); - -static gboolean imap_rename_folder_func (GNode *node, - gpointer data); - -static FolderClass imap_class = -{ - F_IMAP, - - imap_folder_new, - imap_folder_destroy, - - imap_scan_tree, - imap_create_tree, - - imap_get_msg_list, - imap_fetch_msg, - imap_get_msginfo, - imap_add_msg, - imap_add_msgs, - imap_move_msg, - imap_move_msgs, - imap_copy_msg, - imap_copy_msgs, - imap_remove_msg, - imap_remove_msgs, - imap_remove_all_msg, - imap_is_msg_changed, - imap_close, - imap_scan_folder, - - imap_create_folder, - imap_rename_folder, - imap_move_folder, - imap_remove_folder -}; - - -FolderClass *imap_get_class(void) -{ - return &imap_class; -} - -static Folder *imap_folder_new(const gchar *name, const gchar *path) -{ - Folder *folder; - - folder = (Folder *)g_new0(IMAPFolder, 1); - imap_folder_init(folder, name, path); - - return folder; -} - -static void imap_folder_destroy(Folder *folder) -{ - gchar *dir; - - dir = folder_get_path(folder); - if (is_dir_exist(dir)) - remove_dir_recursive(dir); - g_free(dir); - - folder_remote_folder_destroy(REMOTE_FOLDER(folder)); -} - -static void imap_folder_init(Folder *folder, const gchar *name, - const gchar *path) -{ - folder->klass = imap_get_class(); - folder_remote_folder_init(folder, name, path); -} - -static IMAPSession *imap_session_get(Folder *folder) -{ - RemoteFolder *rfolder = REMOTE_FOLDER(folder); - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, NULL); - g_return_val_if_fail(folder->account != NULL, NULL); - - if (!prefs_common.online_mode) - return NULL; - - if (!rfolder->session) { - rfolder->session = imap_session_new(folder->account); - if (rfolder->session) - imap_parse_namespace(IMAP_SESSION(rfolder->session), - IMAP_FOLDER(folder)); - return IMAP_SESSION(rfolder->session); - } - - if (time(NULL) - rfolder->session->last_access_time < - SESSION_TIMEOUT_INTERVAL) { - return IMAP_SESSION(rfolder->session); - } - - if (imap_cmd_noop(IMAP_SESSION(rfolder->session)) != IMAP_SUCCESS) { - log_warning(_("IMAP4 connection to %s has been" - " disconnected. Reconnecting...\n"), - folder->account->recv_server); - if (imap_session_reconnect(IMAP_SESSION(rfolder->session)) - == IMAP_SUCCESS) - imap_parse_namespace(IMAP_SESSION(rfolder->session), - IMAP_FOLDER(folder)); - else { - session_destroy(rfolder->session); - rfolder->session = NULL; - } - } - - return IMAP_SESSION(rfolder->session); -} - -static gint imap_greeting(IMAPSession *session) -{ - gchar *greeting; - gint ok; - - if ((ok = imap_cmd_gen_recv(session, &greeting)) != IMAP_SUCCESS) - return ok; - - if (greeting[0] != '*' || greeting[1] != ' ') - ok = IMAP_ERROR; - else if (!strncmp(greeting + 2, "OK", 2)) - ok = IMAP_SUCCESS; - else if (!strncmp(greeting + 2, "PREAUTH", 7)) { - session->authenticated = TRUE; - ok = IMAP_SUCCESS; - } else - ok = IMAP_ERROR; - - g_free(greeting); - return ok; -} - -static gint imap_auth(IMAPSession *session, const gchar *user, - const gchar *pass, IMAPAuthType type) -{ - gboolean nologin; - gint ok = IMAP_AUTHFAIL; - - nologin = imap_has_capability(session, "LOGINDISABLED"); - - switch (type) { - case 0: - if (imap_has_capability(session, "AUTH=CRAM-MD5")) - ok = imap_cmd_authenticate(session, user, pass, type); - else if (nologin) - log_print(_("IMAP4 server disables LOGIN.\n")); - else - ok = imap_cmd_login(session, user, pass); - break; - case IMAP_AUTH_LOGIN: - if (nologin) - log_warning(_("IMAP4 server disables LOGIN.\n")); - else - ok = imap_cmd_login(session, user, pass); - break; - case IMAP_AUTH_CRAM_MD5: - ok = imap_cmd_authenticate(session, user, pass, type); - break; - default: - break; - } - - if (ok == IMAP_SUCCESS) - session->authenticated = TRUE; - - return ok; -} - -static Session *imap_session_new(PrefsAccount *account) -{ - IMAPSession *session; - gushort port; - - g_return_val_if_fail(account != NULL, NULL); - g_return_val_if_fail(account->recv_server != NULL, NULL); - g_return_val_if_fail(account->userid != NULL, NULL); - -#if USE_SSL - port = account->set_imapport ? account->imapport - : account->ssl_imap == SSL_TUNNEL ? IMAPS_PORT : IMAP4_PORT; -#else - port = account->set_imapport ? account->imapport : IMAP4_PORT; -#endif - - session = g_new0(IMAPSession, 1); - - session_init(SESSION(session)); - - SESSION(session)->type = SESSION_IMAP; - SESSION(session)->sock = NULL; - SESSION(session)->server = g_strdup(account->recv_server); - SESSION(session)->port = port; -#if USE_SSL - SESSION(session)->ssl_type = account->ssl_imap; -#endif - SESSION(session)->last_access_time = time(NULL); - SESSION(session)->data = account; - - SESSION(session)->destroy = imap_session_destroy; - - session->authenticated = FALSE; - session->capability = NULL; - session->uidplus = FALSE; - session->mbox = NULL; - session->cmd_count = 0; - - session_list = g_list_append(session_list, session); - - if (imap_session_connect(session) != IMAP_SUCCESS) { - session_destroy(SESSION(session)); - return NULL; - } - - return SESSION(session); -} - -static gint imap_session_connect(IMAPSession *session) -{ - SockInfo *sock; - PrefsAccount *account; - gchar *pass; - - g_return_val_if_fail(session != NULL, IMAP_ERROR); - - account = (PrefsAccount *)(SESSION(session)->data); - - log_message(_("creating IMAP4 connection to %s:%d ...\n"), - SESSION(session)->server, SESSION(session)->port); - - pass = account->passwd; - if (!pass) { - gchar *tmp_pass; - tmp_pass = input_query_password(account->recv_server, - account->userid); - if (!tmp_pass) - return IMAP_ERROR; - Xstrdup_a(pass, tmp_pass, - {g_free(tmp_pass); return IMAP_ERROR;}); - g_free(tmp_pass); - } - -#if USE_SSL - if ((sock = imap_open(SESSION(session)->server, SESSION(session)->port, - SESSION(session)->ssl_type)) == NULL) -#else - if ((sock = imap_open(SESSION(session)->server, SESSION(session)->port)) - == NULL) -#endif - return IMAP_ERROR; - - SESSION(session)->sock = sock; - - if (imap_greeting(session) != IMAP_SUCCESS) - return IMAP_ERROR; - if (imap_cmd_capability(session) != IMAP_SUCCESS) - return IMAP_ERROR; - - if (imap_has_capability(session, "UIDPLUS")) - session->uidplus = TRUE; - -#if USE_SSL - if (account->ssl_imap == SSL_STARTTLS && - imap_has_capability(session, "STARTTLS")) { - gint ok; - - ok = imap_cmd_starttls(session); - if (ok != IMAP_SUCCESS) { - log_warning(_("Can't start TLS session.\n")); - return IMAP_ERROR; - } - if (!ssl_init_socket_with_method(sock, SSL_METHOD_TLSv1)) - return IMAP_SOCKET; - - /* capability can be changed after STARTTLS */ - if (imap_cmd_capability(session) != IMAP_SUCCESS) - return IMAP_ERROR; - } -#endif - - if (!session->authenticated && - imap_auth(session, account->userid, pass, account->imap_auth_type) - != IMAP_SUCCESS) { - imap_cmd_logout(session); - return IMAP_AUTHFAIL; - } - - return IMAP_SUCCESS; -} - -static gint imap_session_reconnect(IMAPSession *session) -{ - g_return_val_if_fail(session != NULL, IMAP_ERROR); - - session_disconnect(SESSION(session)); - - imap_capability_free(session); - session->uidplus = FALSE; - g_free(session->mbox); - session->mbox = NULL; - session->authenticated = FALSE; - SESSION(session)->state = SESSION_READY; - - return imap_session_connect(session); -} - -static void imap_session_destroy(Session *session) -{ - imap_capability_free(IMAP_SESSION(session)); - g_free(IMAP_SESSION(session)->mbox); - session_list = g_list_remove(session_list, session); -} - -#if 0 -static void imap_session_destroy_all(void) -{ - while (session_list != NULL) { - IMAPSession *session = (IMAPSession *)session_list->data; - - imap_cmd_logout(session); - session_destroy(SESSION(session)); - } -} -#endif - -#define THROW goto catch - -static gint imap_search_flags(IMAPSession *session, GArray **uids, - GHashTable **flags_table) -{ - gint ok; - gint i; - GArray *flag_uids; - GHashTable *unseen_table; - GHashTable *flagged_table; - GHashTable *answered_table; - guint32 uid; - IMAPFlags flags; - - ok = imap_cmd_search(session, "ALL", uids); - if (ok != IMAP_SUCCESS) return ok; - - ok = imap_cmd_search(session, "UNSEEN", &flag_uids); - if (ok != IMAP_SUCCESS) { - g_array_free(*uids, TRUE); - return ok; - } - unseen_table = imap_get_uid_table(flag_uids); - g_array_free(flag_uids, TRUE); - ok = imap_cmd_search(session, "FLAGGED", &flag_uids); - if (ok != IMAP_SUCCESS) { - g_hash_table_destroy(unseen_table); - g_array_free(*uids, TRUE); - return ok; - } - flagged_table = imap_get_uid_table(flag_uids); - g_array_free(flag_uids, TRUE); - ok = imap_cmd_search(session, "ANSWERED", &flag_uids); - if (ok != IMAP_SUCCESS) { - g_hash_table_destroy(flagged_table); - g_hash_table_destroy(unseen_table); - g_array_free(*uids, TRUE); - return ok; - } - answered_table = imap_get_uid_table(flag_uids); - g_array_free(flag_uids, TRUE); - - *flags_table = g_hash_table_new(NULL, g_direct_equal); - - for (i = 0; i < (*uids)->len; i++) { - uid = g_array_index(*uids, guint32, i); - flags = IMAP_FLAG_DRAFT; - if (!g_hash_table_lookup(unseen_table, GUINT_TO_POINTER(uid))) - flags |= IMAP_FLAG_SEEN; - if (g_hash_table_lookup(flagged_table, GUINT_TO_POINTER(uid))) - flags |= IMAP_FLAG_FLAGGED; - if (g_hash_table_lookup(answered_table, GUINT_TO_POINTER(uid))) - flags |= IMAP_FLAG_ANSWERED; - g_hash_table_insert(*flags_table, GUINT_TO_POINTER(uid), - GINT_TO_POINTER(flags)); - } - - g_hash_table_destroy(answered_table); - g_hash_table_destroy(flagged_table); - g_hash_table_destroy(unseen_table); - - return IMAP_SUCCESS; -} - -static gint imap_fetch_flags(IMAPSession *session, GArray **uids, - GHashTable **flags_table) -{ - gint ok; - gchar *tmp; - gchar *cur_pos; - gchar buf[IMAPBUFSIZE]; - guint32 uid; - IMAPFlags flags; - - imap_cmd_gen_send(session, "UID FETCH 1:* (UID FLAGS)"); - - *uids = g_array_new(FALSE, FALSE, sizeof(guint32)); - *flags_table = g_hash_table_new(NULL, g_direct_equal); - - while ((ok = imap_cmd_gen_recv(session, &tmp)) == IMAP_SUCCESS) { - if (tmp[0] != '*' || tmp[1] != ' ') { - g_free(tmp); - break; - } - cur_pos = tmp + 2; - -#define PARSE_ONE_ELEMENT(ch) \ -{ \ - cur_pos = strchr_cpy(cur_pos, ch, buf, sizeof(buf)); \ - if (cur_pos == NULL) { \ - g_warning("cur_pos == NULL\n"); \ - g_free(tmp); \ - g_hash_table_destroy(*flags_table); \ - g_array_free(*uids, TRUE); \ - return IMAP_ERROR; \ - } \ -} - - PARSE_ONE_ELEMENT(' '); - PARSE_ONE_ELEMENT(' '); - if (strcmp(buf, "FETCH") != 0) { - g_free(tmp); - continue; - } - if (*cur_pos != '(') { - g_free(tmp); - continue; - } - cur_pos++; - uid = 0; - flags = 0; - - while (*cur_pos != '\0' && *cur_pos != ')') { - while (*cur_pos == ' ') cur_pos++; - - if (!strncmp(cur_pos, "UID ", 4)) { - cur_pos += 4; - uid = strtoul(cur_pos, &cur_pos, 10); - } else if (!strncmp(cur_pos, "FLAGS ", 6)) { - cur_pos += 6; - if (*cur_pos != '(') { - g_warning("*cur_pos != '('\n"); - break; - } - cur_pos++; - PARSE_ONE_ELEMENT(')'); - flags = imap_parse_imap_flags(buf); - flags |= IMAP_FLAG_DRAFT; - } else { - g_warning("invalid FETCH response: %s\n", cur_pos); - break; - } - } - -#undef PARSE_ONE_ELEMENT - - if (uid > 0) { - g_array_append_val(*uids, uid); - g_hash_table_insert(*flags_table, GUINT_TO_POINTER(uid), - GINT_TO_POINTER(flags)); - } - - g_free(tmp); - } - - if (ok != IMAP_SUCCESS) { - g_hash_table_destroy(*flags_table); - g_array_free(*uids, TRUE); - } - - return ok; -} - -static GSList *imap_get_msg_list(Folder *folder, FolderItem *item, - gboolean use_cache) -{ - GSList *mlist = NULL; - IMAPSession *session; - gint ok, exists = 0, recent = 0, unseen = 0; - guint32 uid_validity = 0; - guint32 first_uid = 0, last_uid = 0; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(item != NULL, NULL); - g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, NULL); - g_return_val_if_fail(folder->account != NULL, NULL); - - item->new = item->unread = item->total = 0; - - session = imap_session_get(folder); - - if (!session) { - mlist = procmsg_read_cache(item, FALSE); - item->last_num = procmsg_get_last_num_in_msg_list(mlist); - procmsg_set_flags(mlist, item); - return mlist; - } - - ok = imap_select(session, IMAP_FOLDER(folder), item->path, - &exists, &recent, &unseen, &uid_validity); - if (ok != IMAP_SUCCESS) THROW; - - if (exists == 0) { - imap_delete_all_cached_messages(item); - return NULL; - } - - /* invalidate current cache if UIDVALIDITY has been changed */ - if (item->mtime != uid_validity) { - debug_print("imap_get_msg_list: " - "UIDVALIDITY has been changed.\n"); - use_cache = FALSE; - } - - if (use_cache) { - GArray *uids; - GHashTable *msg_table; - GHashTable *flags_table; - guint32 cache_last; - guint32 begin = 0; - GSList *cur, *next = NULL; - MsgInfo *msginfo; - IMAPFlags imap_flags; - - /* get cache data */ - mlist = procmsg_read_cache(item, FALSE); - procmsg_set_flags(mlist, item); - cache_last = procmsg_get_last_num_in_msg_list(mlist); - - /* get all UID list and flags */ - ok = imap_search_flags(session, &uids, &flags_table); - if (ok != IMAP_SUCCESS) { - if (ok == IMAP_SOCKET || ok == IMAP_IOERR) THROW; - ok = imap_fetch_flags(session, &uids, &flags_table); - if (ok != IMAP_SUCCESS) THROW; - } - - if (uids->len > 0) { - first_uid = g_array_index(uids, guint32, 0); - last_uid = g_array_index(uids, guint32, uids->len - 1); - } else { - g_array_free(uids, TRUE); - g_hash_table_destroy(flags_table); - THROW; - } - - /* sync message flags with server */ - for (cur = mlist; cur != NULL; cur = next) { - msginfo = (MsgInfo *)cur->data; - next = cur->next; - imap_flags = GPOINTER_TO_INT(g_hash_table_lookup - (flags_table, - GUINT_TO_POINTER(msginfo->msgnum))); - - if (imap_flags == 0) { - debug_print("imap_get_msg_list: " - "message %u has been deleted.\n", - msginfo->msgnum); - imap_delete_cached_message - (item, msginfo->msgnum); - if (MSG_IS_NEW(msginfo->flags)) - item->new--; - if (MSG_IS_UNREAD(msginfo->flags)) - item->unread--; - item->total--; - mlist = g_slist_remove(mlist, msginfo); - procmsg_msginfo_free(msginfo); - item->cache_dirty = TRUE; - item->mark_dirty = TRUE; - continue; - } - - if (!IMAP_IS_SEEN(imap_flags)) { - if (!MSG_IS_UNREAD(msginfo->flags)) { - item->unread++; - MSG_SET_PERM_FLAGS(msginfo->flags, - MSG_UNREAD); - item->mark_dirty = TRUE; - } - } else { - if (MSG_IS_NEW(msginfo->flags)) { - item->new--; - item->mark_dirty = TRUE; - } - if (MSG_IS_UNREAD(msginfo->flags)) { - item->unread--; - item->mark_dirty = TRUE; - } - MSG_UNSET_PERM_FLAGS(msginfo->flags, - MSG_NEW|MSG_UNREAD); - } - - if (IMAP_IS_FLAGGED(imap_flags)) { - if (!MSG_IS_MARKED(msginfo->flags)) { - MSG_SET_PERM_FLAGS(msginfo->flags, - MSG_MARKED); - item->mark_dirty = TRUE; - } - } else { - if (MSG_IS_MARKED(msginfo->flags)) { - MSG_UNSET_PERM_FLAGS(msginfo->flags, - MSG_MARKED); - item->mark_dirty = TRUE; - } - } - if (IMAP_IS_ANSWERED(imap_flags)) { - if (!MSG_IS_REPLIED(msginfo->flags)) { - MSG_SET_PERM_FLAGS(msginfo->flags, - MSG_REPLIED); - item->mark_dirty = TRUE; - } - } else { - if (MSG_IS_REPLIED(msginfo->flags)) { - MSG_UNSET_PERM_FLAGS(msginfo->flags, - MSG_REPLIED); - item->mark_dirty = TRUE; - } - } - } - - /* check for the first new message */ - msg_table = procmsg_msg_hash_table_create(mlist); - if (msg_table == NULL) - begin = first_uid; - else { - gint i; - - for (i = 0; i < uids->len; i++) { - guint32 uid; - - uid = g_array_index(uids, guint32, i); - if (g_hash_table_lookup - (msg_table, GUINT_TO_POINTER(uid)) - == NULL) { - debug_print("imap_get_msg_list: " - "first new UID: %u\n", uid); - begin = uid; - break; - } - } - g_hash_table_destroy(msg_table); - } - - g_array_free(uids, TRUE); - g_hash_table_destroy(flags_table); - - /* remove ununsed caches */ - if (first_uid > 0 && last_uid > 0) { - mlist = imap_delete_cached_messages - (mlist, item, 0, first_uid - 1); - mlist = imap_delete_cached_messages - (mlist, item, begin > 0 ? begin : last_uid + 1, - UINT_MAX); - } - - if (begin > 0 && begin <= last_uid) { - GSList *newlist; - newlist = imap_get_uncached_messages(session, item, - begin, last_uid, - TRUE); - if (newlist) - item->cache_dirty = TRUE; - mlist = g_slist_concat(mlist, newlist); - } - } else { - imap_delete_all_cached_messages(item); - mlist = imap_get_uncached_messages(session, item, 0, 0, TRUE); - last_uid = procmsg_get_last_num_in_msg_list(mlist); - item->cache_dirty = TRUE; - } - - item->mtime = uid_validity; - - mlist = procmsg_sort_msg_list(mlist, item->sort_key, item->sort_type); - - item->last_num = last_uid; - - debug_print("cache_dirty: %d, mark_dirty: %d\n", - item->cache_dirty, item->mark_dirty); - -catch: - return mlist; -} - -#undef THROW - -static gchar *imap_fetch_msg(Folder *folder, FolderItem *item, gint uid) -{ - gchar *path, *filename; - IMAPSession *session; - gint ok; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(item != NULL, NULL); - - path = folder_item_get_path(item); - if (!is_dir_exist(path)) - make_dir_hier(path); - filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(uid), NULL); - g_free(path); - - if (is_file_exist(filename)) { - debug_print("message %d has been already cached.\n", uid); - return filename; - } - - session = imap_session_get(folder); - if (!session) { - g_free(filename); - return NULL; - } - - ok = imap_select(session, IMAP_FOLDER(folder), item->path, - NULL, NULL, NULL, NULL); - if (ok != IMAP_SUCCESS) { - g_warning("can't select mailbox %s\n", item->path); - g_free(filename); - return NULL; - } - - debug_print("getting message %d...\n", uid); - ok = imap_cmd_fetch(session, (guint32)uid, filename); - - if (ok != IMAP_SUCCESS) { - g_warning("can't fetch message %d\n", uid); - g_free(filename); - return NULL; - } - - return filename; -} - -static MsgInfo *imap_get_msginfo(Folder *folder, FolderItem *item, gint uid) -{ - IMAPSession *session; - GSList *list; - MsgInfo *msginfo = NULL; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(item != NULL, NULL); - - session = imap_session_get(folder); - g_return_val_if_fail(session != NULL, NULL); - - list = imap_get_uncached_messages(session, item, uid, uid, FALSE); - if (list) { - msginfo = (MsgInfo *)list->data; - list->data = NULL; - } - procmsg_msg_list_free(list); - - return msginfo; -} - -static gint imap_add_msg(Folder *folder, FolderItem *dest, const gchar *file, - MsgFlags *flags, gboolean remove_source) -{ - GSList file_list; - MsgFileInfo fileinfo; - - g_return_val_if_fail(file != NULL, -1); - - fileinfo.file = (gchar *)file; - fileinfo.flags = flags; - file_list.data = &fileinfo; - file_list.next = NULL; - - return imap_add_msgs(folder, dest, &file_list, remove_source, NULL); -} - -static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list, - gboolean remove_source, gint *first) -{ - gchar *destdir; - IMAPSession *session; - gint messages, recent, unseen; - guint32 uid_next, uid_validity; - guint32 last_uid = 0; - GSList *cur; - MsgFileInfo *fileinfo; - gint ok; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(file_list != NULL, -1); - - session = imap_session_get(folder); - if (!session) return -1; - - ok = imap_status(session, IMAP_FOLDER(folder), dest->path, - &messages, &recent, &uid_next, &uid_validity, &unseen); - if (ok != IMAP_SUCCESS) { - g_warning("can't append messages\n"); - return -1; - } - - destdir = imap_get_real_path(IMAP_FOLDER(folder), dest->path); - - if (!session->uidplus) - last_uid = uid_next - 1; - if (first) - *first = uid_next; - - for (cur = file_list; cur != NULL; cur = cur->next) { - IMAPFlags iflags = 0; - guint32 new_uid = 0; - - fileinfo = (MsgFileInfo *)cur->data; - - if (fileinfo->flags) { - if (MSG_IS_MARKED(*fileinfo->flags)) - iflags |= IMAP_FLAG_FLAGGED; - if (MSG_IS_REPLIED(*fileinfo->flags)) - iflags |= IMAP_FLAG_ANSWERED; - if (!MSG_IS_UNREAD(*fileinfo->flags)) - iflags |= IMAP_FLAG_SEEN; - } - - if (dest->stype == F_OUTBOX || - dest->stype == F_QUEUE || - dest->stype == F_DRAFT || - dest->stype == F_TRASH) - iflags |= IMAP_FLAG_SEEN; - - ok = imap_cmd_append(session, destdir, fileinfo->file, iflags, - &new_uid); - - if (ok != IMAP_SUCCESS) { - g_warning("can't append message %s\n", fileinfo->file); - g_free(destdir); - return -1; - } - - if (!session->uidplus) - last_uid++; - else if (last_uid < new_uid) - last_uid = new_uid; - - dest->last_num = last_uid; - dest->total++; - dest->updated = TRUE; - - if (fileinfo->flags) { - if (MSG_IS_UNREAD(*fileinfo->flags)) - dest->unread++; - } else - dest->unread++; - } - - g_free(destdir); - - if (remove_source) { - for (cur = file_list; cur != NULL; cur = cur->next) { - fileinfo = (MsgFileInfo *)cur->data; - if (g_unlink(fileinfo->file) < 0) - FILE_OP_ERROR(fileinfo->file, "unlink"); - } - } - - return last_uid; -} - -static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest, GSList *msglist, - gboolean remove_source) -{ - FolderItem *src; - gchar *destdir; - GSList *seq_list, *cur; - MsgInfo *msginfo; - IMAPSession *session; - gint ok = IMAP_SUCCESS; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(msglist != NULL, -1); - - session = imap_session_get(folder); - if (!session) return -1; - - msginfo = (MsgInfo *)msglist->data; - - src = msginfo->folder; - if (src == dest) { - g_warning("the src folder is identical to the dest.\n"); - return -1; - } - - ok = imap_select(session, IMAP_FOLDER(folder), src->path, - NULL, NULL, NULL, NULL); - if (ok != IMAP_SUCCESS) - return ok; - - destdir = imap_get_real_path(IMAP_FOLDER(folder), dest->path); - - seq_list = imap_get_seq_set_from_msglist(msglist); - - for (cur = seq_list; cur != NULL; cur = cur->next) { - gchar *seq_set = (gchar *)cur->data; - - if (remove_source) - debug_print("Moving message %s%c[%s] to %s ...\n", - src->path, G_DIR_SEPARATOR, - seq_set, destdir); - else - debug_print("Copying message %s%c[%s] to %s ...\n", - src->path, G_DIR_SEPARATOR, - seq_set, destdir); - - ok = imap_cmd_copy(session, seq_set, destdir); - if (ok != IMAP_SUCCESS) { - imap_seq_set_free(seq_list); - return -1; - } - } - - dest->updated = TRUE; - - if (remove_source) { - imap_remove_msgs_by_seq_set(folder, src, seq_list); - if (ok != IMAP_SUCCESS) { - imap_seq_set_free(seq_list); - return ok; - } - } - - imap_seq_set_free(seq_list); - - for (cur = msglist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - dest->total++; - if (MSG_IS_NEW(msginfo->flags)) - dest->new++; - if (MSG_IS_UNREAD(msginfo->flags)) - dest->unread++; - - if (remove_source) { - src->total--; - if (MSG_IS_NEW(msginfo->flags)) - src->new--; - if (MSG_IS_UNREAD(msginfo->flags)) - src->unread--; - MSG_SET_TMP_FLAGS(msginfo->flags, MSG_INVALID); - } - } - - g_free(destdir); - - if (ok == IMAP_SUCCESS) - return 0; - else - return -1; -} - -static gint imap_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo) -{ - GSList msglist; - - g_return_val_if_fail(msginfo != NULL, -1); - - msglist.data = msginfo; - msglist.next = NULL; - - return imap_move_msgs(folder, dest, &msglist); -} - -static gint imap_move_msgs(Folder *folder, FolderItem *dest, GSList *msglist) -{ - MsgInfo *msginfo; - GSList *file_list; - gint ret = 0; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(msglist != NULL, -1); - - msginfo = (MsgInfo *)msglist->data; - g_return_val_if_fail(msginfo->folder != NULL, -1); - - if (folder == msginfo->folder->folder) - return imap_do_copy_msgs(folder, dest, msglist, TRUE); - - file_list = procmsg_get_message_file_list(msglist); - g_return_val_if_fail(file_list != NULL, -1); - - ret = imap_add_msgs(folder, dest, file_list, FALSE, NULL); - - procmsg_message_file_list_free(file_list); - - if (ret != -1) - ret = folder_item_remove_msgs(msginfo->folder, msglist); - - return ret; -} - -static gint imap_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo) -{ - GSList msglist; - - g_return_val_if_fail(msginfo != NULL, -1); - - msglist.data = msginfo; - msglist.next = NULL; - - return imap_copy_msgs(folder, dest, &msglist); -} - -static gint imap_copy_msgs(Folder *folder, FolderItem *dest, GSList *msglist) -{ - MsgInfo *msginfo; - GSList *file_list; - gint ret; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(msglist != NULL, -1); - - msginfo = (MsgInfo *)msglist->data; - g_return_val_if_fail(msginfo->folder != NULL, -1); - - if (folder == msginfo->folder->folder) - return imap_do_copy_msgs(folder, dest, msglist, FALSE); - - file_list = procmsg_get_message_file_list(msglist); - g_return_val_if_fail(file_list != NULL, -1); - - ret = imap_add_msgs(folder, dest, file_list, FALSE, NULL); - - procmsg_message_file_list_free(file_list); - - return ret; -} - -static gint imap_remove_msgs_by_seq_set(Folder *folder, FolderItem *item, - GSList *seq_list) -{ - gint ok; - IMAPSession *session; - GSList *cur; - - g_return_val_if_fail(seq_list != NULL, -1); - - session = imap_session_get(folder); - if (!session) return -1; - - for (cur = seq_list; cur != NULL; cur = cur->next) { - gchar *seq_set = (gchar *)cur->data; - - ok = imap_set_message_flags(session, seq_set, IMAP_FLAG_DELETED, - TRUE); - if (ok != IMAP_SUCCESS) { - log_warning(_("can't set deleted flags: %s\n"), - seq_set); - return ok; - } - } - - ok = imap_cmd_expunge(session); - if (ok != IMAP_SUCCESS) - log_warning(_("can't expunge\n")); - - item->updated = TRUE; - - return ok; -} - -static gint imap_remove_msg(Folder *folder, FolderItem *item, MsgInfo *msginfo) -{ - GSList msglist; - - g_return_val_if_fail(msginfo != NULL, -1); - - msglist.data = msginfo; - msglist.next = NULL; - - return imap_remove_msgs(folder, item, &msglist); -} - -static gint imap_remove_msgs(Folder *folder, FolderItem *item, GSList *msglist) -{ - gint ok; - IMAPSession *session; - GSList *seq_list, *cur; - gchar *dir; - gboolean dir_exist; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1); - g_return_val_if_fail(item != NULL, -1); - g_return_val_if_fail(msglist != NULL, -1); - - session = imap_session_get(folder); - if (!session) return -1; - - ok = imap_select(session, IMAP_FOLDER(folder), item->path, - NULL, NULL, NULL, NULL); - if (ok != IMAP_SUCCESS) - return ok; - - seq_list = imap_get_seq_set_from_msglist(msglist); - ok = imap_remove_msgs_by_seq_set(folder, item, seq_list); - imap_seq_set_free(seq_list); - if (ok != IMAP_SUCCESS) - return ok; - - dir = folder_item_get_path(item); - dir_exist = is_dir_exist(dir); - for (cur = msglist; cur != NULL; cur = cur->next) { - MsgInfo *msginfo = (MsgInfo *)cur->data; - guint32 uid = msginfo->msgnum; - - if (dir_exist) - remove_numbered_files(dir, uid, uid); - item->total--; - if (MSG_IS_NEW(msginfo->flags)) - item->new--; - if (MSG_IS_UNREAD(msginfo->flags)) - item->unread--; - MSG_SET_TMP_FLAGS(msginfo->flags, MSG_INVALID); - } - g_free(dir); - - return IMAP_SUCCESS; -} - -static gint imap_remove_all_msg(Folder *folder, FolderItem *item) -{ - gint ok; - IMAPSession *session; - gchar *dir; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(item != NULL, -1); - - session = imap_session_get(folder); - if (!session) return -1; - - ok = imap_select(session, IMAP_FOLDER(folder), item->path, - NULL, NULL, NULL, NULL); - if (ok != IMAP_SUCCESS) - return ok; - - imap_cmd_gen_send(session, "STORE 1:* +FLAGS.SILENT (\\Deleted)"); - ok = imap_cmd_ok(session, NULL); - if (ok != IMAP_SUCCESS) { - log_warning(_("can't set deleted flags: 1:*\n")); - return ok; - } - - ok = imap_cmd_expunge(session); - if (ok != IMAP_SUCCESS) { - log_warning(_("can't expunge\n")); - return ok; - } - - item->new = item->unread = item->total = 0; - item->updated = TRUE; - - dir = folder_item_get_path(item); - if (is_dir_exist(dir)) - remove_all_numbered_files(dir); - g_free(dir); - - return IMAP_SUCCESS; -} - -static gboolean imap_is_msg_changed(Folder *folder, FolderItem *item, - MsgInfo *msginfo) -{ - /* TODO: properly implement this method */ - return FALSE; -} - -static gint imap_close(Folder *folder, FolderItem *item) -{ - gint ok; - IMAPSession *session; - - g_return_val_if_fail(folder != NULL, -1); - - if (!item->path) return 0; - - session = imap_session_get(folder); - if (!session) return -1; - - if (session->mbox) { - if (strcmp2(session->mbox, item->path) != 0) return -1; - - ok = imap_cmd_close(session); - if (ok != IMAP_SUCCESS) - log_warning(_("can't close folder\n")); - - g_free(session->mbox); - session->mbox = NULL; - - return ok; - } else - return 0; -} - -static gint imap_scan_folder(Folder *folder, FolderItem *item) -{ - IMAPSession *session; - gint messages, recent, unseen; - guint32 uid_next, uid_validity; - gint ok; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(item != NULL, -1); - - session = imap_session_get(folder); - if (!session) return -1; - - ok = imap_status(session, IMAP_FOLDER(folder), item->path, - &messages, &recent, &uid_next, &uid_validity, &unseen); - if (ok != IMAP_SUCCESS) return -1; - - item->new = unseen > 0 ? recent : 0; - item->unread = unseen; - item->total = messages; - item->last_num = (messages > 0 && uid_next > 0) ? uid_next - 1 : 0; - /* item->mtime = uid_validity; */ - item->updated = TRUE; - - return 0; -} - -static gint imap_scan_tree(Folder *folder) -{ - FolderItem *item = NULL; - IMAPSession *session; - gchar *root_folder = NULL; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(folder->account != NULL, -1); - - session = imap_session_get(folder); - if (!session) { - if (!folder->node) { - folder_tree_destroy(folder); - item = folder_item_new(folder->name, NULL); - item->folder = folder; - folder->node = item->node = g_node_new(item); - } - return -1; - } - - if (folder->account->imap_dir && *folder->account->imap_dir) { - gchar *real_path; - GPtrArray *argbuf; - gint ok; - - Xstrdup_a(root_folder, folder->account->imap_dir, return -1); - extract_quote(root_folder, '"'); - subst_char(root_folder, - imap_get_path_separator(IMAP_FOLDER(folder), - root_folder), - '/'); - strtailchomp(root_folder, '/'); - real_path = imap_get_real_path - (IMAP_FOLDER(folder), root_folder); - debug_print("IMAP root directory: %s\n", real_path); - - /* check if root directory exist */ - argbuf = g_ptr_array_new(); - ok = imap_cmd_list(session, NULL, real_path, argbuf); - if (ok != IMAP_SUCCESS || - search_array_str(argbuf, "LIST ") == NULL) { - log_warning(_("root folder %s not exist\n"), real_path); - g_ptr_array_free(argbuf, TRUE); - g_free(real_path); - return -1; - } - g_ptr_array_free(argbuf, TRUE); - g_free(real_path); - } - - if (folder->node) - item = FOLDER_ITEM(folder->node->data); - if (!item || ((item->path || root_folder) && - strcmp2(item->path, root_folder) != 0)) { - folder_tree_destroy(folder); - item = folder_item_new(folder->name, root_folder); - item->folder = folder; - folder->node = item->node = g_node_new(item); - } - - imap_scan_tree_recursive(session, FOLDER_ITEM(folder->node->data)); - imap_create_missing_folders(folder); - - return 0; -} - -static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item) -{ - Folder *folder; - IMAPFolder *imapfolder; - FolderItem *new_item; - GSList *item_list, *cur; - GNode *node; - gchar *real_path; - gchar *wildcard_path; - gchar separator; - gchar wildcard[3]; - - g_return_val_if_fail(item != NULL, -1); - g_return_val_if_fail(item->folder != NULL, -1); - g_return_val_if_fail(item->no_sub == FALSE, -1); - - folder = item->folder; - imapfolder = IMAP_FOLDER(folder); - - separator = imap_get_path_separator(imapfolder, item->path); - - if (folder->ui_func) - folder->ui_func(folder, item, folder->ui_func_data); - - if (item->path) { - wildcard[0] = separator; - wildcard[1] = '%'; - wildcard[2] = '\0'; - real_path = imap_get_real_path(imapfolder, item->path); - } else { - wildcard[0] = '%'; - wildcard[1] = '\0'; - real_path = g_strdup(""); - } - - Xstrcat_a(wildcard_path, real_path, wildcard, - {g_free(real_path); return IMAP_ERROR;}); - QUOTE_IF_REQUIRED(wildcard_path, wildcard_path); - - imap_cmd_gen_send(session, "LIST \"\" %s", wildcard_path); - - strtailchomp(real_path, separator); - item_list = imap_parse_list(session, real_path, NULL); - g_free(real_path); - - node = item->node->children; - while (node != NULL) { - FolderItem *old_item = FOLDER_ITEM(node->data); - GNode *next = node->next; - - new_item = NULL; - - for (cur = item_list; cur != NULL; cur = cur->next) { - FolderItem *cur_item = FOLDER_ITEM(cur->data); - if (!strcmp2(old_item->path, cur_item->path)) { - new_item = cur_item; - break; - } - } - if (!new_item) { - debug_print("folder '%s' not found. removing...\n", - old_item->path); - folder_item_remove(old_item); - } else { - old_item->no_sub = new_item->no_sub; - old_item->no_select = new_item->no_select; - if (old_item->no_select == TRUE) - old_item->new = old_item->unread = - old_item->total = 0; - if (old_item->no_sub == TRUE && node->children) { - debug_print("folder '%s' doesn't have " - "subfolders. removing...\n", - old_item->path); - folder_item_remove_children(old_item); - } - } - - node = next; - } - - for (cur = item_list; cur != NULL; cur = cur->next) { - FolderItem *cur_item = FOLDER_ITEM(cur->data); - new_item = NULL; - for (node = item->node->children; node != NULL; - node = node->next) { - if (!strcmp2(FOLDER_ITEM(node->data)->path, - cur_item->path)) { - new_item = FOLDER_ITEM(node->data); - folder_item_destroy(cur_item); - cur_item = NULL; - break; - } - } - if (!new_item) { - new_item = cur_item; - debug_print("new folder '%s' found.\n", new_item->path); - folder_item_append(item, new_item); - } - - if (!strcmp(new_item->path, "INBOX")) { - new_item->stype = F_INBOX; - folder->inbox = new_item; - } else if (!item->parent || item->stype == F_INBOX) { - const gchar *base; - - base = g_basename(new_item->path); - - if (!folder->outbox && - !g_ascii_strcasecmp(base, "Sent")) { - new_item->stype = F_OUTBOX; - folder->outbox = new_item; - } else if (!folder->draft && - !g_ascii_strcasecmp(base, "Drafts")) { - new_item->stype = F_DRAFT; - folder->draft = new_item; - } else if (!folder->queue && - !g_ascii_strcasecmp(base, "Queue")) { - new_item->stype = F_QUEUE; - folder->queue = new_item; - } else if (!folder->trash && - !g_ascii_strcasecmp(base, "Trash")) { - new_item->stype = F_TRASH; - folder->trash = new_item; - } - } - -#if 0 - if (new_item->no_select == FALSE) - imap_scan_folder(folder, new_item); -#endif - if (new_item->no_sub == FALSE) - imap_scan_tree_recursive(session, new_item); - } - - g_slist_free(item_list); - - return IMAP_SUCCESS; -} - -static GSList *imap_parse_list(IMAPSession *session, const gchar *real_path, - gchar *separator) -{ - gchar buf[IMAPBUFSIZE]; - gchar flags[256]; - gchar separator_str[16]; - gchar *p; - const gchar *name; - gchar *loc_name, *loc_path; - GSList *item_list = NULL; - GString *str; - FolderItem *new_item; - - debug_print("getting list of %s ...\n", - *real_path ? real_path : "\"\""); - - str = g_string_new(NULL); - - for (;;) { - if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) <= 0) { - log_warning(_("error occurred while getting LIST.\n")); - break; - } - strretchomp(buf); - if (buf[0] != '*' || buf[1] != ' ') { - log_print("IMAP4< %s\n", buf); - if (sscanf(buf, "%*d %16s", buf) < 1 || - strcmp(buf, "OK") != 0) - log_warning(_("error occurred while getting LIST.\n")); - - break; - } - debug_print("IMAP4< %s\n", buf); - - g_string_assign(str, buf); - p = str->str + 2; - if (strncmp(p, "LIST ", 5) != 0) continue; - p += 5; - - if (*p != '(') continue; - p++; - p = strchr_cpy(p, ')', flags, sizeof(flags)); - if (!p) continue; - while (*p == ' ') p++; - - p = strchr_cpy(p, ' ', separator_str, sizeof(separator_str)); - if (!p) continue; - extract_quote(separator_str, '"'); - if (!strcmp(separator_str, "NIL")) - separator_str[0] = '\0'; - if (separator) - *separator = separator_str[0]; - - buf[0] = '\0'; - while (*p == ' ') p++; - if (*p == '{' || *p == '"') - p = imap_parse_atom(session, p, buf, sizeof(buf), str); - else - strncpy2(buf, p, sizeof(buf)); - strtailchomp(buf, separator_str[0]); - if (buf[0] == '\0') continue; - if (!strcmp(buf, real_path)) continue; - - if (separator_str[0] != '\0') - subst_char(buf, separator_str[0], '/'); - name = g_basename(buf); - if (name[0] == '.') continue; - - loc_name = imap_modified_utf7_to_utf8(name); - loc_path = imap_modified_utf7_to_utf8(buf); - new_item = folder_item_new(loc_name, loc_path); - if (strcasestr(flags, "\\Noinferiors") != NULL) - new_item->no_sub = TRUE; - if (strcmp(buf, "INBOX") != 0 && - strcasestr(flags, "\\Noselect") != NULL) - new_item->no_select = TRUE; - - item_list = g_slist_append(item_list, new_item); - - debug_print("folder '%s' found.\n", loc_path); - g_free(loc_path); - g_free(loc_name); - } - - g_string_free(str, TRUE); - - return item_list; -} - -static gint imap_create_tree(Folder *folder) -{ - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(folder->node != NULL, -1); - g_return_val_if_fail(folder->node->data != NULL, -1); - g_return_val_if_fail(folder->account != NULL, -1); - - imap_scan_tree(folder); - imap_create_missing_folders(folder); - - return 0; -} - -static void imap_create_missing_folders(Folder *folder) -{ - g_return_if_fail(folder != NULL); - - if (!folder->inbox) - folder->inbox = imap_create_special_folder - (folder, F_INBOX, "INBOX"); -#if 0 - if (!folder->outbox) - folder->outbox = imap_create_special_folder - (folder, F_OUTBOX, "Sent"); - if (!folder->draft) - folder->draft = imap_create_special_folder - (folder, F_DRAFT, "Drafts"); - if (!folder->queue) - folder->queue = imap_create_special_folder - (folder, F_QUEUE, "Queue"); -#endif - if (!folder->trash) - folder->trash = imap_create_special_folder - (folder, F_TRASH, "Trash"); -} - -static FolderItem *imap_create_special_folder(Folder *folder, - SpecialFolderItemType stype, - const gchar *name) -{ - FolderItem *item; - FolderItem *new_item; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(folder->node != NULL, NULL); - g_return_val_if_fail(folder->node->data != NULL, NULL); - g_return_val_if_fail(folder->account != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - - item = FOLDER_ITEM(folder->node->data); - new_item = imap_create_folder(folder, item, name); - - if (!new_item) { - g_warning(_("Can't create '%s'\n"), name); - if (!folder->inbox) return NULL; - - new_item = imap_create_folder(folder, folder->inbox, name); - if (!new_item) - g_warning(_("Can't create '%s' under INBOX\n"), name); - else - new_item->stype = stype; - } else - new_item->stype = stype; - - return new_item; -} - -static FolderItem *imap_create_folder(Folder *folder, FolderItem *parent, - const gchar *name) -{ - gchar *dirpath, *imap_path; - IMAPSession *session; - FolderItem *new_item; - gchar separator; - gchar *new_name; - const gchar *p; - gint ok; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(folder->account != NULL, NULL); - g_return_val_if_fail(parent != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - - session = imap_session_get(folder); - if (!session) return NULL; - - if (!parent->parent && strcmp(name, "INBOX") == 0) - dirpath = g_strdup(name); - else if (parent->path) - dirpath = g_strconcat(parent->path, "/", name, NULL); - else if ((p = strchr(name, '/')) != NULL && *(p + 1) != '\0') - dirpath = g_strdup(name); - else if (folder->account->imap_dir && *folder->account->imap_dir) { - gchar *imap_dir; - - Xstrdup_a(imap_dir, folder->account->imap_dir, return NULL); - strtailchomp(imap_dir, '/'); - dirpath = g_strconcat(imap_dir, "/", name, NULL); - } else - dirpath = g_strdup(name); - - /* keep trailing directory separator to create a folder that contains - sub folder */ - imap_path = imap_utf8_to_modified_utf7(dirpath); - strtailchomp(dirpath, '/'); - Xstrdup_a(new_name, name, {g_free(dirpath); return NULL;}); - strtailchomp(new_name, '/'); - separator = imap_get_path_separator(IMAP_FOLDER(folder), imap_path); - imap_path_separator_subst(imap_path, separator); - subst_char(new_name, '/', separator); - - if (strcmp(name, "INBOX") != 0) { - GPtrArray *argbuf; - gint i; - gboolean exist = FALSE; - - argbuf = g_ptr_array_new(); - ok = imap_cmd_list(session, NULL, imap_path, argbuf); - if (ok != IMAP_SUCCESS) { - log_warning(_("can't create mailbox: LIST failed\n")); - g_free(imap_path); - g_free(dirpath); - g_ptr_array_free(argbuf, TRUE); - return NULL; - } - - for (i = 0; i < argbuf->len; i++) { - gchar *str; - str = g_ptr_array_index(argbuf, i); - if (!strncmp(str, "LIST ", 5)) { - exist = TRUE; - break; - } - } - g_ptr_array_free(argbuf, TRUE); - - if (!exist) { - ok = imap_cmd_create(session, imap_path); - if (ok != IMAP_SUCCESS) { - log_warning(_("can't create mailbox\n")); - g_free(imap_path); - g_free(dirpath); - return NULL; - } - } - } - - new_item = folder_item_new(new_name, dirpath); - folder_item_append(parent, new_item); - g_free(imap_path); - g_free(dirpath); - - dirpath = folder_item_get_path(new_item); - if (!is_dir_exist(dirpath)) - make_dir_hier(dirpath); - g_free(dirpath); - - return new_item; -} - -static gint imap_rename_folder_real(Folder *folder, FolderItem *item, - FolderItem *new_parent, const gchar *name) -{ - gchar *newpath; - gchar *real_oldpath; - gchar *real_newpath; - gchar *paths[2]; - gchar *old_cache_dir; - gchar *new_cache_dir; - IMAPSession *session; - gchar separator; - gint ok; - gint exists, recent, unseen; - guint32 uid_validity; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(item != NULL, -1); - g_return_val_if_fail(folder == item->folder, -1); - g_return_val_if_fail(item->path != NULL, -1); - g_return_val_if_fail(new_parent != NULL || name != NULL, -1); - if (new_parent) { - g_return_val_if_fail(item != new_parent, -1); - g_return_val_if_fail(item->parent != new_parent, -1); - g_return_val_if_fail(item->folder == new_parent->folder, -1); - if (g_node_is_ancestor(item->node, new_parent->node)) { - g_warning("folder to be moved is ancestor of new parent\n"); - return -1; - } - } - - session = imap_session_get(folder); - if (!session) return -1; - - real_oldpath = imap_get_real_path(IMAP_FOLDER(folder), item->path); - - g_free(session->mbox); - session->mbox = NULL; - ok = imap_cmd_examine(session, "INBOX", - &exists, &recent, &unseen, &uid_validity); - if (ok != IMAP_SUCCESS) { - g_free(real_oldpath); - return -1; - } - - separator = imap_get_path_separator(IMAP_FOLDER(folder), item->path); - if (new_parent) { - if (name) { - newpath = g_strconcat(new_parent->path, - G_DIR_SEPARATOR_S, name, NULL); - } else { - gchar *name_; - - name_ = g_path_get_basename(item->path); - newpath = g_strconcat(new_parent->path, - G_DIR_SEPARATOR_S, name_, NULL); - AUTORELEASE_STR(name_, ); - name = name_; - } - } else { - if (strchr(item->path, G_DIR_SEPARATOR)) { - gchar *dirpath; - - dirpath = g_dirname(item->path); - newpath = g_strconcat(dirpath, G_DIR_SEPARATOR_S, name, - NULL); - g_free(dirpath); - } else - newpath = g_strdup(name); - } - - real_newpath = imap_utf8_to_modified_utf7(newpath); - imap_path_separator_subst(real_newpath, separator); - - ok = imap_cmd_rename(session, real_oldpath, real_newpath); - if (ok != IMAP_SUCCESS) { - log_warning(_("can't rename mailbox: %s to %s\n"), - real_oldpath, real_newpath); - g_free(real_oldpath); - g_free(newpath); - g_free(real_newpath); - return -1; - } - - if (new_parent) { - g_node_unlink(item->node); - g_node_append(new_parent->node, item->node); - item->parent = new_parent; - } - - g_free(item->name); - item->name = g_strdup(name); - - old_cache_dir = folder_item_get_path(item); - - paths[0] = g_strdup(item->path); - paths[1] = newpath; - g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, - imap_rename_folder_func, paths); - - if (is_dir_exist(old_cache_dir)) { - new_cache_dir = folder_item_get_path(item); - if (g_rename(old_cache_dir, new_cache_dir) < 0) { - FILE_OP_ERROR(old_cache_dir, "rename"); - } - g_free(new_cache_dir); - } - - g_free(old_cache_dir); - g_free(paths[0]); - g_free(newpath); - g_free(real_oldpath); - g_free(real_newpath); - - return 0; -} - -static gint imap_rename_folder(Folder *folder, FolderItem *item, - const gchar *name) -{ - return imap_rename_folder_real(folder, item, NULL, name); -} - -static gint imap_move_folder(Folder *folder, FolderItem *item, - FolderItem *new_parent) -{ - return imap_rename_folder_real(folder, item, new_parent, NULL); -} - -static gint imap_remove_folder(Folder *folder, FolderItem *item) -{ - gint ok; - IMAPSession *session; - gchar *path; - gchar *cache_dir; - gint exists, recent, unseen; - guint32 uid_validity; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(item != NULL, -1); - g_return_val_if_fail(item->path != NULL, -1); - - session = imap_session_get(folder); - if (!session) return -1; - - path = imap_get_real_path(IMAP_FOLDER(folder), item->path); - - ok = imap_cmd_examine(session, "INBOX", - &exists, &recent, &unseen, &uid_validity); - if (ok != IMAP_SUCCESS) { - g_free(path); - return -1; - } - - ok = imap_cmd_delete(session, path); - if (ok != IMAP_SUCCESS) { - log_warning(_("can't delete mailbox\n")); - g_free(path); - return -1; - } - - g_free(path); - cache_dir = folder_item_get_path(item); - if (is_dir_exist(cache_dir) && remove_dir_recursive(cache_dir) < 0) - g_warning("can't remove directory '%s'\n", cache_dir); - g_free(cache_dir); - folder_item_remove(item); - - return 0; -} - -static GSList *imap_get_uncached_messages(IMAPSession *session, - FolderItem *item, - guint32 first_uid, guint32 last_uid, - gboolean update_count) -{ - gchar *tmp; - GSList *newlist = NULL; - GSList *llast = NULL; - GString *str; - MsgInfo *msginfo; - gchar seq_set[22]; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(item != NULL, NULL); - g_return_val_if_fail(item->folder != NULL, NULL); - g_return_val_if_fail(FOLDER_TYPE(item->folder) == F_IMAP, NULL); - g_return_val_if_fail(first_uid <= last_uid, NULL); - - if (first_uid == 0 && last_uid == 0) - strcpy(seq_set, "1:*"); - else - g_snprintf(seq_set, sizeof(seq_set), "%u:%u", - first_uid, last_uid); - if (imap_cmd_envelope(session, seq_set) != IMAP_SUCCESS) { - log_warning(_("can't get envelope\n")); - return NULL; - } - - str = g_string_new(NULL); - - for (;;) { - if (sock_getline(SESSION(session)->sock, &tmp) < 0) { - log_warning(_("error occurred while getting envelope.\n")); - g_string_free(str, TRUE); - return newlist; - } - strretchomp(tmp); - if (tmp[0] != '*' || tmp[1] != ' ') { - log_print("IMAP4< %s\n", tmp); - g_free(tmp); - break; - } - if (strstr(tmp, "FETCH") == NULL) { - log_print("IMAP4< %s\n", tmp); - g_free(tmp); - continue; - } - log_print("IMAP4< %s\n", tmp); - g_string_assign(str, tmp); - g_free(tmp); - - msginfo = imap_parse_envelope(session, item, str); - if (!msginfo) { - log_warning(_("can't parse envelope: %s\n"), str->str); - continue; - } - if (update_count) { - if (MSG_IS_NEW(msginfo->flags)) - item->new++; - if (MSG_IS_UNREAD(msginfo->flags)) - item->unread++; - } - if (item->stype == F_QUEUE) { - MSG_SET_TMP_FLAGS(msginfo->flags, MSG_QUEUED); - } else if (item->stype == F_DRAFT) { - MSG_SET_TMP_FLAGS(msginfo->flags, MSG_DRAFT); - } - - msginfo->folder = item; - - if (!newlist) - llast = newlist = g_slist_append(newlist, msginfo); - else { - llast = g_slist_append(llast, msginfo); - llast = llast->next; - } - - if (update_count) - item->total++; - } - - g_string_free(str, TRUE); - - session_set_access_time(SESSION(session)); - - return newlist; -} - -static void imap_delete_cached_message(FolderItem *item, guint32 uid) -{ - gchar *dir; - gchar *file; - - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP); - - dir = folder_item_get_path(item); - file = g_strdup_printf("%s%c%u", dir, G_DIR_SEPARATOR, uid); - - debug_print("Deleting cached message: %s\n", file); - - g_unlink(file); - - g_free(file); - g_free(dir); -} - -static GSList *imap_delete_cached_messages(GSList *mlist, FolderItem *item, - guint32 first_uid, guint32 last_uid) -{ - GSList *cur, *next; - MsgInfo *msginfo; - gchar *dir; - - g_return_val_if_fail(item != NULL, mlist); - g_return_val_if_fail(item->folder != NULL, mlist); - g_return_val_if_fail(FOLDER_TYPE(item->folder) == F_IMAP, mlist); - - if (first_uid == 0 && last_uid == 0) - return mlist; - - debug_print("Deleting cached messages %u - %u ... ", - first_uid, last_uid); - - dir = folder_item_get_path(item); - if (is_dir_exist(dir)) - remove_numbered_files(dir, first_uid, last_uid); - g_free(dir); - - for (cur = mlist; cur != NULL; ) { - next = cur->next; - - msginfo = (MsgInfo *)cur->data; - if (msginfo != NULL && first_uid <= msginfo->msgnum && - msginfo->msgnum <= last_uid) { - procmsg_msginfo_free(msginfo); - mlist = g_slist_remove(mlist, msginfo); - } - - cur = next; - } - - debug_print("done.\n"); - - return mlist; -} - -static void imap_delete_all_cached_messages(FolderItem *item) -{ - gchar *dir; - - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP); - - debug_print("Deleting all cached messages... "); - - dir = folder_item_get_path(item); - if (is_dir_exist(dir)) - remove_all_numbered_files(dir); - g_free(dir); - - debug_print("done.\n"); -} - -#if USE_SSL -static SockInfo *imap_open(const gchar *server, gushort port, - SSLType ssl_type) -#else -static SockInfo *imap_open(const gchar *server, gushort port) -#endif -{ - SockInfo *sock; - - if ((sock = sock_connect(server, port)) == NULL) { - log_warning(_("Can't connect to IMAP4 server: %s:%d\n"), - server, port); - return NULL; - } - -#if USE_SSL - if (ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) { - log_warning(_("Can't establish IMAP4 session with: %s:%d\n"), - server, port); - sock_close(sock); - return NULL; - } -#endif - - return sock; -} - -static GList *imap_parse_namespace_str(gchar *str) -{ - guchar *p = str; - gchar *name; - gchar *separator; - IMAPNameSpace *namespace; - GList *ns_list = NULL; - - while (*p != '\0') { - /* parse ("#foo" "/") */ - - while (*p && *p != '(') p++; - if (*p == '\0') break; - p++; - - while (*p && *p != '"') p++; - if (*p == '\0') break; - p++; - name = p; - - while (*p && *p != '"') p++; - if (*p == '\0') break; - *p = '\0'; - p++; - - while (*p && g_ascii_isspace(*p)) p++; - if (*p == '\0') break; - if (strncmp(p, "NIL", 3) == 0) - separator = NULL; - else if (*p == '"') { - p++; - separator = p; - while (*p && *p != '"') p++; - if (*p == '\0') break; - *p = '\0'; - p++; - } else break; - - while (*p && *p != ')') p++; - if (*p == '\0') break; - p++; - - namespace = g_new(IMAPNameSpace, 1); - namespace->name = g_strdup(name); - namespace->separator = separator ? separator[0] : '\0'; - ns_list = g_list_append(ns_list, namespace); - } - - return ns_list; -} - -static void imap_parse_namespace(IMAPSession *session, IMAPFolder *folder) -{ - gchar *ns_str = NULL; - gchar **str_array; - - g_return_if_fail(session != NULL); - g_return_if_fail(folder != NULL); - - if (folder->ns_personal != NULL || - folder->ns_others != NULL || - folder->ns_shared != NULL) - return; - - if (imap_cmd_namespace(session, &ns_str) != IMAP_SUCCESS) { - log_warning(_("can't get namespace\n")); - imap_get_namespace_by_list(session, folder); - return; - } - - str_array = strsplit_parenthesis(ns_str, '(', ')', 3); - if (str_array[0]) - folder->ns_personal = imap_parse_namespace_str(str_array[0]); - if (str_array[0] && str_array[1]) - folder->ns_others = imap_parse_namespace_str(str_array[1]); - if (str_array[0] && str_array[1] && str_array[2]) - folder->ns_shared = imap_parse_namespace_str(str_array[2]); - g_strfreev(str_array); - g_free(ns_str); -} - -static void imap_get_namespace_by_list(IMAPSession *session, IMAPFolder *folder) -{ - GSList *item_list, *cur; - gchar separator = '\0'; - IMAPNameSpace *namespace; - - g_return_if_fail(session != NULL); - g_return_if_fail(folder != NULL); - - if (folder->ns_personal != NULL || - folder->ns_others != NULL || - folder->ns_shared != NULL) - return; - - imap_cmd_gen_send(session, "LIST \"\" \"\""); - item_list = imap_parse_list(session, "", &separator); - for (cur = item_list; cur != NULL; cur = cur->next) - folder_item_destroy(FOLDER_ITEM(cur->data)); - g_slist_free(item_list); - - namespace = g_new(IMAPNameSpace, 1); - namespace->name = g_strdup(""); - namespace->separator = separator; - folder->ns_personal = g_list_append(NULL, namespace); -} - -static IMAPNameSpace *imap_find_namespace_from_list(GList *ns_list, - const gchar *path) -{ - IMAPNameSpace *namespace = NULL; - gchar *tmp_path, *name; - - if (!path) path = ""; - - for (; ns_list != NULL; ns_list = ns_list->next) { - IMAPNameSpace *tmp_ns = ns_list->data; - - Xstrcat_a(tmp_path, path, "/", return namespace); - Xstrdup_a(name, tmp_ns->name, return namespace); - if (tmp_ns->separator && tmp_ns->separator != '/') { - subst_char(tmp_path, tmp_ns->separator, '/'); - subst_char(name, tmp_ns->separator, '/'); - } - if (strncmp(tmp_path, name, strlen(name)) == 0) - namespace = tmp_ns; - } - - return namespace; -} - -static IMAPNameSpace *imap_find_namespace(IMAPFolder *folder, - const gchar *path) -{ - IMAPNameSpace *namespace; - - g_return_val_if_fail(folder != NULL, NULL); - - namespace = imap_find_namespace_from_list(folder->ns_personal, path); - if (namespace) return namespace; - namespace = imap_find_namespace_from_list(folder->ns_others, path); - if (namespace) return namespace; - namespace = imap_find_namespace_from_list(folder->ns_shared, path); - if (namespace) return namespace; - - return NULL; -} - -static gchar imap_get_path_separator(IMAPFolder *folder, const gchar *path) -{ - IMAPNameSpace *namespace; - gchar separator = '/'; - - namespace = imap_find_namespace(folder, path); - if (namespace && namespace->separator) - separator = namespace->separator; - - return separator; -} - -static gchar *imap_get_real_path(IMAPFolder *folder, const gchar *path) -{ - gchar *real_path; - gchar separator; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(path != NULL, NULL); - - real_path = imap_utf8_to_modified_utf7(path); - separator = imap_get_path_separator(folder, path); - imap_path_separator_subst(real_path, separator); - - return real_path; -} - -static gchar *imap_parse_atom(IMAPSession *session, gchar *src, - gchar *dest, gint dest_len, GString *str) -{ - gchar *cur_pos = src; - gchar *nextline; - - g_return_val_if_fail(str != NULL, cur_pos); - - /* read the next line if the current response buffer is empty */ - while (g_ascii_isspace(*cur_pos)) cur_pos++; - while (*cur_pos == '\0') { - if (sock_getline(SESSION(session)->sock, &nextline) < 0) - return cur_pos; - g_string_assign(str, nextline); - cur_pos = str->str; - strretchomp(nextline); - /* log_print("IMAP4< %s\n", nextline); */ - debug_print("IMAP4< %s\n", nextline); - g_free(nextline); - - while (g_ascii_isspace(*cur_pos)) cur_pos++; - } - - if (!strncmp(cur_pos, "NIL", 3)) { - *dest = '\0'; - cur_pos += 3; - } else if (*cur_pos == '\"') { - gchar *p; - - p = get_quoted(cur_pos, '\"', dest, dest_len); - cur_pos = p ? p : cur_pos + 2; - } else if (*cur_pos == '{') { - gchar buf[32]; - gint len; - gint block_len = 0; - - cur_pos = strchr_cpy(cur_pos + 1, '}', buf, sizeof(buf)); - len = atoi(buf); - g_return_val_if_fail(len >= 0, cur_pos); - - g_string_truncate(str, 0); - cur_pos = str->str; - - do { - gint cur_len; - - cur_len = sock_getline(SESSION(session)->sock, - &nextline); - if (cur_len < 0) - return cur_pos; - block_len += cur_len; - subst_null(nextline, cur_len, ' '); - g_string_append(str, nextline); - cur_pos = str->str; - strretchomp(nextline); - /* log_print("IMAP4< %s\n", nextline); */ - debug_print("IMAP4< %s\n", nextline); - g_free(nextline); - } while (block_len < len); - - memcpy(dest, cur_pos, MIN(len, dest_len - 1)); - dest[MIN(len, dest_len - 1)] = '\0'; - cur_pos += len; - } - - return cur_pos; -} - -static gchar *imap_get_header(IMAPSession *session, gchar *cur_pos, - gchar **headers, GString *str) -{ - gchar *nextline; - gchar buf[32]; - gint len; - gint block_len = 0; - - *headers = NULL; - - g_return_val_if_fail(str != NULL, cur_pos); - - while (g_ascii_isspace(*cur_pos)) cur_pos++; - - g_return_val_if_fail(*cur_pos == '{', cur_pos); - - cur_pos = strchr_cpy(cur_pos + 1, '}', buf, sizeof(buf)); - len = atoi(buf); - g_return_val_if_fail(len >= 0, cur_pos); - - g_string_truncate(str, 0); - cur_pos = str->str; - - do { - gint cur_len; - - cur_len = sock_getline(SESSION(session)->sock, &nextline); - if (cur_len < 0) - return cur_pos; - block_len += cur_len; - subst_null(nextline, cur_len, ' '); - g_string_append(str, nextline); - cur_pos = str->str; - /* strretchomp(nextline); */ - /* debug_print("IMAP4< %s\n", nextline); */ - g_free(nextline); - } while (block_len < len); - - debug_print("IMAP4< [contents of RFC822.HEADER]\n"); - - *headers = g_strndup(cur_pos, len); - cur_pos += len; - - while (g_ascii_isspace(*cur_pos)) cur_pos++; - while (*cur_pos == '\0') { - if (sock_getline(SESSION(session)->sock, &nextline) < 0) - return cur_pos; - g_string_assign(str, nextline); - cur_pos = str->str; - strretchomp(nextline); - debug_print("IMAP4< %s\n", nextline); - g_free(nextline); - - while (g_ascii_isspace(*cur_pos)) cur_pos++; - } - - return cur_pos; -} - -static MsgFlags imap_parse_flags(const gchar *flag_str) -{ - const gchar *p = flag_str; - MsgFlags flags = {0, 0}; - - flags.perm_flags = MSG_UNREAD; - - while ((p = strchr(p, '\\')) != NULL) { - p++; - - if (g_ascii_strncasecmp(p, "Recent", 6) == 0 && - MSG_IS_UNREAD(flags)) { - MSG_SET_PERM_FLAGS(flags, MSG_NEW); - } else if (g_ascii_strncasecmp(p, "Seen", 4) == 0) { - MSG_UNSET_PERM_FLAGS(flags, MSG_NEW|MSG_UNREAD); - } else if (g_ascii_strncasecmp(p, "Deleted", 7) == 0) { - MSG_SET_PERM_FLAGS(flags, MSG_DELETED); - } else if (g_ascii_strncasecmp(p, "Flagged", 7) == 0) { - MSG_SET_PERM_FLAGS(flags, MSG_MARKED); - } else if (g_ascii_strncasecmp(p, "Answered", 8) == 0) { - MSG_SET_PERM_FLAGS(flags, MSG_REPLIED); - } - } - - return flags; -} - -static IMAPFlags imap_parse_imap_flags(const gchar *flag_str) -{ - const gchar *p = flag_str; - IMAPFlags flags = 0; - - while ((p = strchr(p, '\\')) != NULL) { - p++; - - if (g_ascii_strncasecmp(p, "Seen", 4) == 0) { - flags |= IMAP_FLAG_SEEN; - } else if (g_ascii_strncasecmp(p, "Deleted", 7) == 0) { - flags |= IMAP_FLAG_DELETED; - } else if (g_ascii_strncasecmp(p, "Flagged", 7) == 0) { - flags |= IMAP_FLAG_FLAGGED; - } else if (g_ascii_strncasecmp(p, "Answered", 8) == 0) { - flags |= IMAP_FLAG_ANSWERED; - } - } - - return flags; -} - -static MsgInfo *imap_parse_envelope(IMAPSession *session, FolderItem *item, - GString *line_str) -{ - gchar buf[IMAPBUFSIZE]; - MsgInfo *msginfo = NULL; - gchar *cur_pos; - gint msgnum; - guint32 uid = 0; - size_t size = 0; - MsgFlags flags = {0, 0}, imap_flags = {0, 0}; - - g_return_val_if_fail(line_str != NULL, NULL); - g_return_val_if_fail(line_str->str[0] == '*' && - line_str->str[1] == ' ', NULL); - - MSG_SET_TMP_FLAGS(flags, MSG_IMAP); - if (item->stype == F_QUEUE) { - MSG_SET_TMP_FLAGS(flags, MSG_QUEUED); - } else if (item->stype == F_DRAFT) { - MSG_SET_TMP_FLAGS(flags, MSG_DRAFT); - } - - cur_pos = line_str->str + 2; - -#define PARSE_ONE_ELEMENT(ch) \ -{ \ - cur_pos = strchr_cpy(cur_pos, ch, buf, sizeof(buf)); \ - if (cur_pos == NULL) { \ - g_warning("cur_pos == NULL\n"); \ - procmsg_msginfo_free(msginfo); \ - return NULL; \ - } \ -} - - PARSE_ONE_ELEMENT(' '); - msgnum = atoi(buf); - - PARSE_ONE_ELEMENT(' '); - g_return_val_if_fail(!strcmp(buf, "FETCH"), NULL); - - g_return_val_if_fail(*cur_pos == '(', NULL); - cur_pos++; - - while (*cur_pos != '\0' && *cur_pos != ')') { - while (*cur_pos == ' ') cur_pos++; - - if (!strncmp(cur_pos, "UID ", 4)) { - cur_pos += 4; - uid = strtoul(cur_pos, &cur_pos, 10); - } else if (!strncmp(cur_pos, "FLAGS ", 6)) { - cur_pos += 6; - if (*cur_pos != '(') { - g_warning("*cur_pos != '('\n"); - procmsg_msginfo_free(msginfo); - return NULL; - } - cur_pos++; - PARSE_ONE_ELEMENT(')'); - imap_flags = imap_parse_flags(buf); - } else if (!strncmp(cur_pos, "RFC822.SIZE ", 12)) { - cur_pos += 12; - size = strtol(cur_pos, &cur_pos, 10); - } else if (!strncmp(cur_pos, "RFC822.HEADER ", 14)) { - gchar *headers; - - cur_pos += 14; - cur_pos = imap_get_header(session, cur_pos, &headers, - line_str); - msginfo = procheader_parse_str(headers, flags, FALSE); - g_free(headers); - } else { - g_warning("invalid FETCH response: %s\n", cur_pos); - break; - } - } - -#undef PARSE_ONE_ELEMENT - - if (msginfo) { - msginfo->msgnum = uid; - msginfo->size = size; - msginfo->flags.tmp_flags |= imap_flags.tmp_flags; - msginfo->flags.perm_flags = imap_flags.perm_flags; - } - - return msginfo; -} - -static gint imap_msg_list_change_perm_flags(GSList *msglist, MsgPermFlags flags, - gboolean is_set) -{ - Folder *folder; - IMAPSession *session; - IMAPFlags iflags = 0; - MsgInfo *msginfo; - GSList *seq_list, *cur; - gint ok = IMAP_SUCCESS; - - if (msglist == NULL) return IMAP_SUCCESS; - - msginfo = (MsgInfo *)msglist->data; - g_return_val_if_fail(msginfo != NULL, -1); - - g_return_val_if_fail(MSG_IS_IMAP(msginfo->flags), -1); - g_return_val_if_fail(msginfo->folder != NULL, -1); - g_return_val_if_fail(msginfo->folder->folder != NULL, -1); - - folder = msginfo->folder->folder; - g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1); - - session = imap_session_get(folder); - if (!session) return -1; - - ok = imap_select(session, IMAP_FOLDER(folder), msginfo->folder->path, - NULL, NULL, NULL, NULL); - if (ok != IMAP_SUCCESS) - return ok; - - seq_list = imap_get_seq_set_from_msglist(msglist); - - if (flags & MSG_MARKED) iflags |= IMAP_FLAG_FLAGGED; - if (flags & MSG_REPLIED) iflags |= IMAP_FLAG_ANSWERED; - - for (cur = seq_list; cur != NULL; cur = cur->next) { - gchar *seq_set = (gchar *)cur->data; - - if (iflags) { - ok = imap_set_message_flags(session, seq_set, iflags, - is_set); - if (ok != IMAP_SUCCESS) break; - } - - if (flags & MSG_UNREAD) { - ok = imap_set_message_flags(session, seq_set, - IMAP_FLAG_SEEN, !is_set); - if (ok != IMAP_SUCCESS) break; - } - } - - imap_seq_set_free(seq_list); - - return ok; -} - -gint imap_msg_set_perm_flags(MsgInfo *msginfo, MsgPermFlags flags) -{ - GSList msglist; - - msglist.data = msginfo; - msglist.next = NULL; - - return imap_msg_list_change_perm_flags(&msglist, flags, TRUE); -} - -gint imap_msg_unset_perm_flags(MsgInfo *msginfo, MsgPermFlags flags) -{ - GSList msglist; - - msglist.data = msginfo; - msglist.next = NULL; - - return imap_msg_list_change_perm_flags(&msglist, flags, FALSE); -} - -gint imap_msg_list_set_perm_flags(GSList *msglist, MsgPermFlags flags) -{ - return imap_msg_list_change_perm_flags(msglist, flags, TRUE); -} - -gint imap_msg_list_unset_perm_flags(GSList *msglist, MsgPermFlags flags) -{ - return imap_msg_list_change_perm_flags(msglist, flags, FALSE); -} - -static gchar *imap_get_flag_str(IMAPFlags flags) -{ - GString *str; - gchar *ret; - - str = g_string_new(NULL); - - if (IMAP_IS_SEEN(flags)) g_string_append(str, "\\Seen "); - if (IMAP_IS_ANSWERED(flags)) g_string_append(str, "\\Answered "); - if (IMAP_IS_FLAGGED(flags)) g_string_append(str, "\\Flagged "); - if (IMAP_IS_DELETED(flags)) g_string_append(str, "\\Deleted "); - if (IMAP_IS_DRAFT(flags)) g_string_append(str, "\\Draft"); - - if (str->len > 0 && str->str[str->len - 1] == ' ') - g_string_truncate(str, str->len - 1); - - ret = str->str; - g_string_free(str, FALSE); - - return ret; -} - -static gint imap_set_message_flags(IMAPSession *session, - const gchar *seq_set, - IMAPFlags flags, - gboolean is_set) -{ - gchar *cmd; - gchar *flag_str; - gint ok; - - flag_str = imap_get_flag_str(flags); - cmd = g_strconcat(is_set ? "+FLAGS.SILENT (" : "-FLAGS.SILENT (", - flag_str, ")", NULL); - g_free(flag_str); - - ok = imap_cmd_store(session, seq_set, cmd); - g_free(cmd); - - return ok; -} - -static gint imap_select(IMAPSession *session, IMAPFolder *folder, - const gchar *path, - gint *exists, gint *recent, gint *unseen, - guint32 *uid_validity) -{ - gchar *real_path; - gint ok; - gint exists_, recent_, unseen_, uid_validity_; - - if (!exists || !recent || !unseen || !uid_validity) { - if (session->mbox && strcmp(session->mbox, path) == 0) - return IMAP_SUCCESS; - exists = &exists_; - recent = &recent_; - unseen = &unseen_; - uid_validity = &uid_validity_; - } - - g_free(session->mbox); - session->mbox = NULL; - - real_path = imap_get_real_path(folder, path); - ok = imap_cmd_select(session, real_path, - exists, recent, unseen, uid_validity); - if (ok != IMAP_SUCCESS) - log_warning(_("can't select folder: %s\n"), real_path); - else - session->mbox = g_strdup(path); - g_free(real_path); - - return ok; -} - -#define THROW(err) { ok = err; goto catch; } - -static gint imap_status(IMAPSession *session, IMAPFolder *folder, - const gchar *path, - gint *messages, gint *recent, - guint32 *uid_next, guint32 *uid_validity, - gint *unseen) -{ - gchar *real_path; - gchar *real_path_; - gint ok; - GPtrArray *argbuf = NULL; - gchar *str; - - if (messages && recent && uid_next && uid_validity && unseen) { - *messages = *recent = *uid_next = *uid_validity = *unseen = 0; - argbuf = g_ptr_array_new(); - } - - real_path = imap_get_real_path(folder, path); - QUOTE_IF_REQUIRED(real_path_, real_path); - imap_cmd_gen_send(session, "STATUS %s " - "(MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN)", - real_path_); - - ok = imap_cmd_ok(session, argbuf); - if (ok != IMAP_SUCCESS || !argbuf) THROW(ok); - - str = search_array_str(argbuf, "STATUS"); - if (!str) THROW(IMAP_ERROR); - - str = strchr(str, '('); - if (!str) THROW(IMAP_ERROR); - str++; - while (*str != '\0' && *str != ')') { - while (*str == ' ') str++; - - if (!strncmp(str, "MESSAGES ", 9)) { - str += 9; - *messages = strtol(str, &str, 10); - } else if (!strncmp(str, "RECENT ", 7)) { - str += 7; - *recent = strtol(str, &str, 10); - } else if (!strncmp(str, "UIDNEXT ", 8)) { - str += 8; - *uid_next = strtoul(str, &str, 10); - } else if (!strncmp(str, "UIDVALIDITY ", 12)) { - str += 12; - *uid_validity = strtoul(str, &str, 10); - } else if (!strncmp(str, "UNSEEN ", 7)) { - str += 7; - *unseen = strtol(str, &str, 10); - } else { - g_warning("invalid STATUS response: %s\n", str); - break; - } - } - -catch: - g_free(real_path); - if (argbuf) { - ptr_array_free_strings(argbuf); - g_ptr_array_free(argbuf, TRUE); - } - - return ok; -} - -#undef THROW - -static gboolean imap_has_capability(IMAPSession *session, - const gchar *capability) -{ - gchar **p; - - for (p = session->capability; *p != NULL; ++p) { - if (!g_ascii_strcasecmp(*p, capability)) - return TRUE; - } - - return FALSE; -} - -static void imap_capability_free(IMAPSession *session) -{ - if (session->capability) { - g_strfreev(session->capability); - session->capability = NULL; - } -} - - -/* low-level IMAP4rev1 commands */ - -#define THROW(err) { ok = err; goto catch; } - -static gint imap_cmd_capability(IMAPSession *session) -{ - gint ok; - GPtrArray *argbuf; - gchar *capability; - - argbuf = g_ptr_array_new(); - - imap_cmd_gen_send(session, "CAPABILITY"); - if ((ok = imap_cmd_ok(session, argbuf)) != IMAP_SUCCESS) THROW(ok); - - capability = search_array_str(argbuf, "CAPABILITY "); - if (!capability) THROW(IMAP_ERROR); - - capability += strlen("CAPABILITY "); - - imap_capability_free(session); - session->capability = g_strsplit(capability, " ", -1); - -catch: - ptr_array_free_strings(argbuf); - g_ptr_array_free(argbuf, TRUE); - - return ok; -} - -#undef THROW - -static gint imap_cmd_authenticate(IMAPSession *session, const gchar *user, - const gchar *pass, IMAPAuthType type) -{ - gchar *auth_type; - gint ok; - gchar *buf = NULL; - gchar *challenge; - gint challenge_len; - gchar hexdigest[33]; - gchar *response; - gchar *response64; - - g_return_val_if_fail((type == 0 || type == IMAP_AUTH_CRAM_MD5), - IMAP_ERROR); - - auth_type = "CRAM-MD5"; - - imap_cmd_gen_send(session, "AUTHENTICATE %s", auth_type); - ok = imap_cmd_gen_recv(session, &buf); - if (ok != IMAP_SUCCESS || buf[0] != '+' || buf[1] != ' ') { - g_free(buf); - return IMAP_ERROR; - } - - challenge = g_malloc(strlen(buf + 2) + 1); - challenge_len = base64_decode(challenge, buf + 2, -1); - challenge[challenge_len] = '\0'; - g_free(buf); - log_print("IMAP< [Decoded: %s]\n", challenge); - - md5_hex_hmac(hexdigest, challenge, challenge_len, pass, strlen(pass)); - g_free(challenge); - - response = g_strdup_printf("%s %s", user, hexdigest); - log_print("IMAP> [Encoded: %s]\n", response); - response64 = g_malloc((strlen(response) + 3) * 2 + 1); - base64_encode(response64, response, strlen(response)); - g_free(response); - - log_print("IMAP> %s\n", response64); - sock_puts(SESSION(session)->sock, response64); - ok = imap_cmd_ok(session, NULL); - if (ok != IMAP_SUCCESS) - log_warning(_("IMAP4 authentication failed.\n")); - - return ok; -} - -static gint imap_cmd_login(IMAPSession *session, - const gchar *user, const gchar *pass) -{ - gchar *user_, *pass_; - gint ok; - - QUOTE_IF_REQUIRED(user_, user); - QUOTE_IF_REQUIRED(pass_, pass); - imap_cmd_gen_send(session, "LOGIN %s %s", user_, pass_); - - ok = imap_cmd_ok(session, NULL); - if (ok != IMAP_SUCCESS) - log_warning(_("IMAP4 login failed.\n")); - - return ok; -} - -static gint imap_cmd_logout(IMAPSession *session) -{ - imap_cmd_gen_send(session, "LOGOUT"); - return imap_cmd_ok(session, NULL); -} - -static gint imap_cmd_noop(IMAPSession *session) -{ - imap_cmd_gen_send(session, "NOOP"); - return imap_cmd_ok(session, NULL); -} - -#if USE_SSL -static gint imap_cmd_starttls(IMAPSession *session) -{ - imap_cmd_gen_send(session, "STARTTLS"); - return imap_cmd_ok(session, NULL); -} -#endif - -#define THROW(err) { ok = err; goto catch; } - -static gint imap_cmd_namespace(IMAPSession *session, gchar **ns_str) -{ - gint ok; - GPtrArray *argbuf; - gchar *str; - - argbuf = g_ptr_array_new(); - - imap_cmd_gen_send(session, "NAMESPACE"); - if ((ok = imap_cmd_ok(session, argbuf)) != IMAP_SUCCESS) THROW(ok); - - str = search_array_str(argbuf, "NAMESPACE"); - if (!str) THROW(IMAP_ERROR); - - *ns_str = g_strdup(str); - -catch: - ptr_array_free_strings(argbuf); - g_ptr_array_free(argbuf, TRUE); - - return ok; -} - -#undef THROW - -static gint imap_cmd_list(IMAPSession *session, const gchar *ref, - const gchar *mailbox, GPtrArray *argbuf) -{ - gchar *ref_, *mailbox_; - - if (!ref) ref = "\"\""; - if (!mailbox) mailbox = "\"\""; - - QUOTE_IF_REQUIRED(ref_, ref); - QUOTE_IF_REQUIRED(mailbox_, mailbox); - imap_cmd_gen_send(session, "LIST %s %s", ref_, mailbox_); - - return imap_cmd_ok(session, argbuf); -} - -#define THROW goto catch - -static gint imap_cmd_do_select(IMAPSession *session, const gchar *folder, - gboolean examine, - gint *exists, gint *recent, gint *unseen, - guint32 *uid_validity) -{ - gint ok; - gchar *resp_str; - GPtrArray *argbuf; - gchar *select_cmd; - gchar *folder_; - guint uid_validity_; - - *exists = *recent = *unseen = *uid_validity = 0; - argbuf = g_ptr_array_new(); - - if (examine) - select_cmd = "EXAMINE"; - else - select_cmd = "SELECT"; - - QUOTE_IF_REQUIRED(folder_, folder); - imap_cmd_gen_send(session, "%s %s", select_cmd, folder_); - - if ((ok = imap_cmd_ok(session, argbuf)) != IMAP_SUCCESS) THROW; - - resp_str = search_array_contain_str(argbuf, "EXISTS"); - if (resp_str) { - if (sscanf(resp_str,"%d EXISTS", exists) != 1) { - g_warning("imap_cmd_select(): invalid EXISTS line.\n"); - THROW; - } - } - - resp_str = search_array_contain_str(argbuf, "RECENT"); - if (resp_str) { - if (sscanf(resp_str, "%d RECENT", recent) != 1) { - g_warning("imap_cmd_select(): invalid RECENT line.\n"); - THROW; - } - } - - resp_str = search_array_contain_str(argbuf, "UIDVALIDITY"); - if (resp_str) { - if (sscanf(resp_str, "OK [UIDVALIDITY %u] ", &uid_validity_) - != 1) { - g_warning("imap_cmd_select(): invalid UIDVALIDITY line.\n"); - THROW; - } - *uid_validity = uid_validity_; - } - - resp_str = search_array_contain_str(argbuf, "UNSEEN"); - if (resp_str) { - if (sscanf(resp_str, "OK [UNSEEN %d] ", unseen) != 1) { - g_warning("imap_cmd_select(): invalid UNSEEN line.\n"); - THROW; - } - } - -catch: - ptr_array_free_strings(argbuf); - g_ptr_array_free(argbuf, TRUE); - - return ok; -} - -static gint imap_cmd_select(IMAPSession *session, const gchar *folder, - gint *exists, gint *recent, gint *unseen, - guint32 *uid_validity) -{ - return imap_cmd_do_select(session, folder, FALSE, - exists, recent, unseen, uid_validity); -} - -static gint imap_cmd_examine(IMAPSession *session, const gchar *folder, - gint *exists, gint *recent, gint *unseen, - guint32 *uid_validity) -{ - return imap_cmd_do_select(session, folder, TRUE, - exists, recent, unseen, uid_validity); -} - -#undef THROW - -static gint imap_cmd_create(IMAPSession *session, const gchar *folder) -{ - gchar *folder_; - - QUOTE_IF_REQUIRED(folder_, folder); - imap_cmd_gen_send(session, "CREATE %s", folder_); - - return imap_cmd_ok(session, NULL); -} - -static gint imap_cmd_rename(IMAPSession *session, const gchar *old_folder, - const gchar *new_folder) -{ - gchar *old_folder_, *new_folder_; - - QUOTE_IF_REQUIRED(old_folder_, old_folder); - QUOTE_IF_REQUIRED(new_folder_, new_folder); - imap_cmd_gen_send(session, "RENAME %s %s", old_folder_, new_folder_); - - return imap_cmd_ok(session, NULL); -} - -static gint imap_cmd_delete(IMAPSession *session, const gchar *folder) -{ - gchar *folder_; - - QUOTE_IF_REQUIRED(folder_, folder); - imap_cmd_gen_send(session, "DELETE %s", folder_); - - return imap_cmd_ok(session, NULL); -} - -#define THROW(err) { ok = err; goto catch; } - -static gint imap_cmd_search(IMAPSession *session, const gchar *criteria, - GArray **result) -{ - gint ok; - GPtrArray *argbuf; - GArray *array; - gchar *str; - gchar *p, *ep; - gint i; - guint32 uid; - - g_return_val_if_fail(criteria != NULL, IMAP_ERROR); - g_return_val_if_fail(result != NULL, IMAP_ERROR); - - argbuf = g_ptr_array_new(); - - imap_cmd_gen_send(session, "UID SEARCH %s", criteria); - if ((ok = imap_cmd_ok(session, argbuf)) != IMAP_SUCCESS) THROW(ok); - - array = g_array_new(FALSE, FALSE, sizeof(guint32)); - - for (i = 0; i < argbuf->len; i++) { - str = g_ptr_array_index(argbuf, i); - if (strncmp(str, "SEARCH", 6) != 0) - continue; - - p = str + 6; - while (*p != '\0') { - uid = strtoul(p, &ep, 10); - if (p < ep && uid > 0) { - g_array_append_val(array, uid); - p = ep; - } else - break; - } - } - - *result = array; - -catch: - ptr_array_free_strings(argbuf); - g_ptr_array_free(argbuf, TRUE); - - return ok; -} - -static gint imap_cmd_fetch(IMAPSession *session, guint32 uid, - const gchar *filename) -{ - gint ok; - gchar *buf; - gchar *cur_pos; - gchar size_str[32]; - glong size_num; - gint ret; - - g_return_val_if_fail(filename != NULL, IMAP_ERROR); - - imap_cmd_gen_send(session, "UID FETCH %d BODY.PEEK[]", uid); - - while ((ok = imap_cmd_gen_recv(session, &buf)) == IMAP_SUCCESS) { - if (buf[0] != '*' || buf[1] != ' ') { - g_free(buf); - return IMAP_ERROR; - } - if (strstr(buf, "FETCH") != NULL) break; - g_free(buf); - } - if (ok != IMAP_SUCCESS) - return ok; - -#define RETURN_ERROR_IF_FAIL(cond) \ - if (!(cond)) { \ - g_free(buf); \ - return IMAP_ERROR; \ - } - - cur_pos = strchr(buf, '{'); - RETURN_ERROR_IF_FAIL(cur_pos != NULL); - cur_pos = strchr_cpy(cur_pos + 1, '}', size_str, sizeof(size_str)); - RETURN_ERROR_IF_FAIL(cur_pos != NULL); - size_num = atol(size_str); - RETURN_ERROR_IF_FAIL(size_num >= 0); - - RETURN_ERROR_IF_FAIL(*cur_pos == '\0'); - -#undef RETURN_ERROR_IF_FAIL - - g_free(buf); - - if ((ret = recv_bytes_write_to_file(SESSION(session)->sock, - size_num, filename)) != 0) { - if (ret == -2) - return IMAP_SOCKET; - } - - if (imap_cmd_gen_recv(session, &buf) != IMAP_SUCCESS) - return IMAP_ERROR; - - if (buf[0] == '\0' || buf[strlen(buf) - 1] != ')') { - g_free(buf); - return IMAP_ERROR; - } - g_free(buf); - - ok = imap_cmd_ok(session, NULL); - - if (ret != 0) - return IMAP_ERROR; - - return ok; -} - -static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder, - const gchar *file, IMAPFlags flags, - guint32 *new_uid) -{ - gint ok; - gint size; - gchar *destfolder_; - gchar *flag_str; - guint new_uid_; - gchar *ret = NULL; - gchar buf[BUFFSIZE]; - FILE *fp; - GPtrArray *argbuf; - gchar *resp_str; - - g_return_val_if_fail(file != NULL, IMAP_ERROR); - - size = get_file_size_as_crlf(file); - if ((fp = g_fopen(file, "rb")) == NULL) { - FILE_OP_ERROR(file, "fopen"); - return -1; - } - QUOTE_IF_REQUIRED(destfolder_, destfolder); - flag_str = imap_get_flag_str(flags); - imap_cmd_gen_send(session, "APPEND %s (%s) {%d}", - destfolder_, flag_str, size); - g_free(flag_str); - - ok = imap_cmd_gen_recv(session, &ret); - if (ok != IMAP_SUCCESS || ret[0] != '+' || ret[1] != ' ') { - log_warning(_("can't append %s to %s\n"), file, destfolder_); - g_free(ret); - fclose(fp); - return IMAP_ERROR; - } - g_free(ret); - - log_print("IMAP4> %s\n", _("(sending file...)")); - - while (fgets(buf, sizeof(buf), fp) != NULL) { - strretchomp(buf); - if (sock_puts(SESSION(session)->sock, buf) < 0) { - fclose(fp); - return -1; - } - } - - if (ferror(fp)) { - FILE_OP_ERROR(file, "fgets"); - fclose(fp); - return -1; - } - - sock_puts(SESSION(session)->sock, ""); - - fclose(fp); - - if (new_uid != NULL) - *new_uid = 0; - - if (new_uid != NULL && session->uidplus) { - argbuf = g_ptr_array_new(); - - ok = imap_cmd_ok(session, argbuf); - if (ok != IMAP_SUCCESS) - log_warning(_("can't append message to %s\n"), - destfolder_); - else if (argbuf->len > 0) { - resp_str = g_ptr_array_index(argbuf, argbuf->len - 1); - if (resp_str && - sscanf(resp_str, "%*u OK [APPENDUID %*u %u]", - &new_uid_) == 1) { - *new_uid = new_uid_; - } - } - - ptr_array_free_strings(argbuf); - g_ptr_array_free(argbuf, TRUE); - } else - ok = imap_cmd_ok(session, NULL); - - return ok; -} - -static gint imap_cmd_copy(IMAPSession *session, const gchar *seq_set, - const gchar *destfolder) -{ - gint ok; - gchar *destfolder_; - - g_return_val_if_fail(destfolder != NULL, IMAP_ERROR); - - QUOTE_IF_REQUIRED(destfolder_, destfolder); - imap_cmd_gen_send(session, "UID COPY %s %s", seq_set, destfolder_); - - ok = imap_cmd_ok(session, NULL); - if (ok != IMAP_SUCCESS) { - log_warning(_("can't copy %s to %s\n"), seq_set, destfolder_); - return -1; - } - - return ok; -} - -gint imap_cmd_envelope(IMAPSession *session, const gchar *seq_set) -{ - imap_cmd_gen_send - (session, "UID FETCH %s (UID FLAGS RFC822.SIZE RFC822.HEADER)", - seq_set); - - return IMAP_SUCCESS; -} - -static gint imap_cmd_store(IMAPSession *session, const gchar *seq_set, - const gchar *sub_cmd) -{ - gint ok; - - imap_cmd_gen_send(session, "UID STORE %s %s", seq_set, sub_cmd); - - if ((ok = imap_cmd_ok(session, NULL)) != IMAP_SUCCESS) { - log_warning(_("error while imap command: STORE %s %s\n"), - seq_set, sub_cmd); - return ok; - } - - return IMAP_SUCCESS; -} - -static gint imap_cmd_expunge(IMAPSession *session) -{ - gint ok; - - imap_cmd_gen_send(session, "EXPUNGE"); - if ((ok = imap_cmd_ok(session, NULL)) != IMAP_SUCCESS) { - log_warning(_("error while imap command: EXPUNGE\n")); - return ok; - } - - return IMAP_SUCCESS; -} - -static gint imap_cmd_close(IMAPSession *session) -{ - gint ok; - - imap_cmd_gen_send(session, "CLOSE"); - if ((ok = imap_cmd_ok(session, NULL)) != IMAP_SUCCESS) - log_warning(_("error while imap command: CLOSE\n")); - - return ok; -} - -static gint imap_cmd_ok(IMAPSession *session, GPtrArray *argbuf) -{ - gint ok; - gchar *buf; - gint cmd_num; - gchar cmd_status[IMAPBUFSIZE + 1]; - - while ((ok = imap_cmd_gen_recv(session, &buf)) == IMAP_SUCCESS) { - if (buf[0] == '*' && buf[1] == ' ') { - if (argbuf) { - g_memmove(buf, buf + 2, strlen(buf + 2) + 1); - g_ptr_array_add(argbuf, buf); - } else - g_free(buf); - continue; - } - - if (sscanf(buf, "%d %" Xstr(IMAPBUFSIZE) "s", - &cmd_num, cmd_status) < 2) { - g_free(buf); - return IMAP_ERROR; - } else if (cmd_num == session->cmd_count && - !strcmp(cmd_status, "OK")) { - if (argbuf) - g_ptr_array_add(argbuf, buf); - else - g_free(buf); - return IMAP_SUCCESS; - } else { - g_free(buf); - return IMAP_ERROR; - } - } - - return ok; -} - -static void imap_cmd_gen_send(IMAPSession *session, const gchar *format, ...) -{ - gchar buf[IMAPBUFSIZE]; - gchar tmp[IMAPBUFSIZE]; - gchar *p; - va_list args; - - va_start(args, format); - g_vsnprintf(tmp, sizeof(tmp), format, args); - va_end(args); - - session->cmd_count++; - - g_snprintf(buf, sizeof(buf), "%d %s\r\n", session->cmd_count, tmp); - if (!g_ascii_strncasecmp(tmp, "LOGIN ", 6) && - (p = strchr(tmp + 6, ' '))) { - *p = '\0'; - log_print("IMAP4> %d %s ********\n", session->cmd_count, tmp); - } else - log_print("IMAP4> %d %s\n", session->cmd_count, tmp); - - sock_write_all(SESSION(session)->sock, buf, strlen(buf)); -} - -static gint imap_cmd_gen_recv(IMAPSession *session, gchar **ret) -{ - if (sock_getline(SESSION(session)->sock, ret) < 0) - return IMAP_SOCKET; - - strretchomp(*ret); - - log_print("IMAP4< %s\n", *ret); - - session_set_access_time(SESSION(session)); - - return IMAP_SUCCESS; -} - - -/* misc utility functions */ - -static gchar *strchr_cpy(const gchar *src, gchar ch, gchar *dest, gint len) -{ - gchar *tmp; - - dest[0] = '\0'; - tmp = strchr(src, ch); - if (!tmp) - return NULL; - - memcpy(dest, src, MIN(tmp - src, len - 1)); - dest[MIN(tmp - src, len - 1)] = '\0'; - - return tmp + 1; -} - -static gchar *get_quoted(const gchar *src, gchar ch, gchar *dest, gint len) -{ - const gchar *p = src; - gint n = 0; - - g_return_val_if_fail(*p == ch, NULL); - - *dest = '\0'; - p++; - - while (*p != '\0' && *p != ch) { - if (n < len - 1) { - if (*p == '\\' && *(p + 1) != '\0') - p++; - *dest++ = *p++; - } else - p++; - n++; - } - - *dest = '\0'; - return (gchar *)(*p == ch ? p + 1 : p); -} - -static gchar *search_array_contain_str(GPtrArray *array, gchar *str) -{ - gint i; - - for (i = 0; i < array->len; i++) { - gchar *tmp; - - tmp = g_ptr_array_index(array, i); - if (strstr(tmp, str) != NULL) - return tmp; - } - - return NULL; -} - -static gchar *search_array_str(GPtrArray *array, gchar *str) -{ - gint i; - gint len; - - len = strlen(str); - - for (i = 0; i < array->len; i++) { - gchar *tmp; - - tmp = g_ptr_array_index(array, i); - if (!strncmp(tmp, str, len)) - return tmp; - } - - return NULL; -} - -static void imap_path_separator_subst(gchar *str, gchar separator) -{ - gchar *p; - gboolean in_escape = FALSE; - - if (!separator || separator == '/') return; - - for (p = str; *p != '\0'; p++) { - if (*p == '/' && !in_escape) - *p = separator; - else if (*p == '&' && *(p + 1) != '-' && !in_escape) - in_escape = TRUE; - else if (*p == '-' && in_escape) - in_escape = FALSE; - } -} - -static gchar *imap_modified_utf7_to_utf8(const gchar *mutf7_str) -{ - static iconv_t cd = (iconv_t)-1; - static gboolean iconv_ok = TRUE; - GString *norm_utf7; - gchar *norm_utf7_p; - size_t norm_utf7_len; - const gchar *p; - gchar *to_str, *to_p; - size_t to_len; - gboolean in_escape = FALSE; - - if (!iconv_ok) return g_strdup(mutf7_str); - - if (cd == (iconv_t)-1) { - cd = iconv_open(CS_INTERNAL, CS_UTF_7); - if (cd == (iconv_t)-1) { - g_warning("iconv cannot convert UTF-7 to %s\n", - CS_INTERNAL); - iconv_ok = FALSE; - return g_strdup(mutf7_str); - } - } - - /* modified UTF-7 to normal UTF-7 conversion */ - norm_utf7 = g_string_new(NULL); - - for (p = mutf7_str; *p != '\0'; p++) { - /* replace: '&' -> '+', - "&-" -> '&', - "+" -> "+-", - escaped ',' -> '/' */ - if (!in_escape && *p == '&') { - if (*(p + 1) != '-') { - g_string_append_c(norm_utf7, '+'); - in_escape = TRUE; - } else { - g_string_append_c(norm_utf7, '&'); - p++; - } - } else if (!in_escape && *p == '+') { - g_string_append(norm_utf7, "+-"); - } else if (in_escape && *p == ',') { - g_string_append_c(norm_utf7, '/'); - } else if (in_escape && *p == '-') { - g_string_append_c(norm_utf7, '-'); - in_escape = FALSE; - } else { - g_string_append_c(norm_utf7, *p); - } - } - - /* somehow iconv() returns error when the last of the string is "+-" */ - g_string_append_c(norm_utf7, '\n'); - norm_utf7_p = norm_utf7->str; - norm_utf7_len = norm_utf7->len; - to_len = strlen(mutf7_str) * 5; - to_p = to_str = g_malloc(to_len + 1); - - if (iconv(cd, (ICONV_CONST gchar **)&norm_utf7_p, &norm_utf7_len, - &to_p, &to_len) == -1) { - g_warning(_("iconv cannot convert UTF-7 to %s\n"), CS_INTERNAL); - g_string_free(norm_utf7, TRUE); - g_free(to_str); - return g_strdup(mutf7_str); - } - - /* second iconv() call for flushing */ - iconv(cd, NULL, NULL, &to_p, &to_len); - g_string_free(norm_utf7, TRUE); - *to_p = '\0'; - strretchomp(to_str); - - return to_str; -} - -static gchar *imap_utf8_to_modified_utf7(const gchar *from) -{ - static iconv_t cd = (iconv_t)-1; - static gboolean iconv_ok = TRUE; - gchar *norm_utf7, *norm_utf7_p; - size_t from_len, norm_utf7_len; - GString *to_str; - gchar *from_tmp, *to, *p; - gboolean in_escape = FALSE; - - if (!iconv_ok) return g_strdup(from); - - if (cd == (iconv_t)-1) { - cd = iconv_open(CS_UTF_7, CS_INTERNAL); - if (cd == (iconv_t)-1) { - g_warning(_("iconv cannot convert %s to UTF-7\n"), - CS_INTERNAL); - iconv_ok = FALSE; - return g_strdup(from); - } - } - - /* UTF-8 to normal UTF-7 conversion */ - Xstrdup_a(from_tmp, from, return g_strdup(from)); - from_len = strlen(from); - norm_utf7_len = from_len * 5; - Xalloca(norm_utf7, norm_utf7_len + 1, return g_strdup(from)); - norm_utf7_p = norm_utf7; - - while (from_len > 0) { - if (*from_tmp == '+') { - *norm_utf7_p++ = '+'; - *norm_utf7_p++ = '-'; - norm_utf7_len -= 2; - from_tmp++; - from_len--; - } else if (g_ascii_isprint(*from_tmp)) { - /* printable ascii char */ - *norm_utf7_p = *from_tmp; - norm_utf7_p++; - norm_utf7_len--; - from_tmp++; - from_len--; - } else { - size_t conv_len = 0; - - /* unprintable char: convert to UTF-7 */ - p = from_tmp; - while (!g_ascii_isprint(*p) && conv_len < from_len) { - conv_len += g_utf8_skip[*(guchar *)p]; - p += g_utf8_skip[*(guchar *)p]; - } - - from_len -= conv_len; - if (iconv(cd, (ICONV_CONST gchar **)&from_tmp, - &conv_len, - &norm_utf7_p, &norm_utf7_len) == -1) { - g_warning("iconv cannot convert %s to UTF-7\n", - CS_INTERNAL); - return g_strdup(from); - } - - /* second iconv() call for flushing */ - iconv(cd, NULL, NULL, &norm_utf7_p, &norm_utf7_len); - } - } - - *norm_utf7_p = '\0'; - to_str = g_string_new(NULL); - for (p = norm_utf7; p < norm_utf7_p; p++) { - /* replace: '&' -> "&-", - '+' -> '&', - "+-" -> '+', - BASE64 '/' -> ',' */ - if (!in_escape && *p == '&') { - g_string_append(to_str, "&-"); - } else if (!in_escape && *p == '+') { - if (*(p + 1) == '-') { - g_string_append_c(to_str, '+'); - p++; - } else { - g_string_append_c(to_str, '&'); - in_escape = TRUE; - } - } else if (in_escape && *p == '/') { - g_string_append_c(to_str, ','); - } else if (in_escape && *p == '-') { - g_string_append_c(to_str, '-'); - in_escape = FALSE; - } else { - g_string_append_c(to_str, *p); - } - } - - if (in_escape) { - in_escape = FALSE; - g_string_append_c(to_str, '-'); - } - - to = to_str->str; - g_string_free(to_str, FALSE); - - return to; -} - -static GSList *imap_get_seq_set_from_msglist(GSList *msglist) -{ - GString *str; - GSList *sorted_list, *cur; - guint first, last, next; - gchar *ret_str; - GSList *ret_list = NULL; - - if (msglist == NULL) - return NULL; - - str = g_string_sized_new(256); - - sorted_list = g_slist_copy(msglist); - sorted_list = procmsg_sort_msg_list(sorted_list, SORT_BY_NUMBER, - SORT_ASCENDING); - - first = ((MsgInfo *)sorted_list->data)->msgnum; - - for (cur = sorted_list; cur != NULL; cur = cur->next) { - last = ((MsgInfo *)cur->data)->msgnum; - if (cur->next) - next = ((MsgInfo *)cur->next->data)->msgnum; - else - next = 0; - - if (last + 1 != next || next == 0) { - if (str->len > 0) - g_string_append_c(str, ','); - if (first == last) - g_string_sprintfa(str, "%u", first); - else - g_string_sprintfa(str, "%u:%u", first, last); - - first = next; - - if (str->len > IMAP_CMD_LIMIT) { - ret_str = g_strdup(str->str); - ret_list = g_slist_append(ret_list, ret_str); - g_string_truncate(str, 0); - } - } - } - - if (str->len > 0) { - ret_str = g_strdup(str->str); - ret_list = g_slist_append(ret_list, ret_str); - } - - g_slist_free(sorted_list); - g_string_free(str, TRUE); - - return ret_list; -} - -static void imap_seq_set_free(GSList *seq_list) -{ - slist_free_strings(seq_list); - g_slist_free(seq_list); -} - -static GHashTable *imap_get_uid_table(GArray *array) -{ - GHashTable *table; - gint i; - guint32 uid; - - g_return_val_if_fail(array != NULL, NULL); - - table = g_hash_table_new(NULL, g_direct_equal); - - for (i = 0; i < array->len; i++) { - uid = g_array_index(array, guint32, i); - g_hash_table_insert(table, GUINT_TO_POINTER(uid), - GINT_TO_POINTER(i + 1)); - } - - return table; -} - -static gboolean imap_rename_folder_func(GNode *node, gpointer data) -{ - FolderItem *item = node->data; - gchar **paths = data; - const gchar *oldpath = paths[0]; - const gchar *newpath = paths[1]; - gchar *base; - gchar *new_itempath; - gint oldpathlen; - - oldpathlen = strlen(oldpath); - if (strncmp(oldpath, item->path, oldpathlen) != 0) { - g_warning("path doesn't match: %s, %s\n", oldpath, item->path); - return TRUE; - } - - base = item->path + oldpathlen; - while (*base == G_DIR_SEPARATOR) base++; - if (*base == '\0') - new_itempath = g_strdup(newpath); - else - new_itempath = g_strconcat(newpath, G_DIR_SEPARATOR_S, base, - NULL); - g_free(item->path); - item->path = new_itempath; - - return FALSE; -} diff --git a/src/imap.h b/src/imap.h deleted file mode 100644 index c726c875..00000000 --- a/src/imap.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 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. - */ - -#ifndef __IMAP_H__ -#define __IMAP_H__ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <glib.h> -#include <time.h> - -#include "folder.h" -#include "session.h" -#include "procmsg.h" - -typedef struct _IMAPFolder IMAPFolder; -typedef struct _IMAPSession IMAPSession; -typedef struct _IMAPNameSpace IMAPNameSpace; - -#define IMAP_FOLDER(obj) ((IMAPFolder *)obj) -#define IMAP_SESSION(obj) ((IMAPSession *)obj) - -#include "prefs_account.h" - -typedef enum -{ - IMAP_AUTH_LOGIN = 1 << 0, - IMAP_AUTH_CRAM_MD5 = 1 << 1 -} IMAPAuthType; - -struct _IMAPFolder -{ - RemoteFolder rfolder; - - /* list of IMAPNameSpace */ - GList *ns_personal; - GList *ns_others; - GList *ns_shared; -}; - -struct _IMAPSession -{ - Session session; - - gboolean authenticated; - - gchar **capability; - gboolean uidplus; - - gchar *mbox; - guint cmd_count; -}; - -struct _IMAPNameSpace -{ - gchar *name; - gchar separator; -}; - -#define IMAP_SUCCESS 0 -#define IMAP_SOCKET 2 -#define IMAP_AUTHFAIL 3 -#define IMAP_PROTOCOL 4 -#define IMAP_SYNTAX 5 -#define IMAP_IOERR 6 -#define IMAP_ERROR 7 - -#define IMAPBUFSIZE 8192 - -typedef enum -{ - IMAP_FLAG_SEEN = 1 << 0, - IMAP_FLAG_ANSWERED = 1 << 1, - IMAP_FLAG_FLAGGED = 1 << 2, - IMAP_FLAG_DELETED = 1 << 3, - IMAP_FLAG_DRAFT = 1 << 4 -} IMAPFlags; - -#define IMAP_IS_SEEN(flags) ((flags & IMAP_FLAG_SEEN) != 0) -#define IMAP_IS_ANSWERED(flags) ((flags & IMAP_FLAG_ANSWERED) != 0) -#define IMAP_IS_FLAGGED(flags) ((flags & IMAP_FLAG_FLAGGED) != 0) -#define IMAP_IS_DELETED(flags) ((flags & IMAP_FLAG_DELETED) != 0) -#define IMAP_IS_DRAFT(flags) ((flags & IMAP_FLAG_DRAFT) != 0) - -FolderClass *imap_get_class (void); - -gint imap_msg_set_perm_flags (MsgInfo *msginfo, - MsgPermFlags flags); -gint imap_msg_unset_perm_flags (MsgInfo *msginfo, - MsgPermFlags flags); -gint imap_msg_list_set_perm_flags (GSList *msglist, - MsgPermFlags flags); -gint imap_msg_list_unset_perm_flags (GSList *msglist, - MsgPermFlags flags); - -#endif /* __IMAP_H__ */ @@ -561,6 +561,9 @@ static void check_gpg(void) engineInfo = engineInfo->next; } } + + procmsg_set_decrypt_message_func + (rfc2015_open_message_decrypted); } else { if (prefs_common.gpg_warning) { AlertValue val; diff --git a/src/md5.c b/src/md5.c deleted file mode 100644 index 54585971..00000000 --- a/src/md5.c +++ /dev/null @@ -1,433 +0,0 @@ -/* md5.c - MD5 Message-Digest Algorithm - * Copyright (C) 1995, 1996, 1998, 1999 Free Software Foundation, Inc. - * - * according to the definition of MD5 in RFC 1321 from April 1992. - * NOTE: This is *not* the same file as the one from glibc. - * - * 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, 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. - */ -/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */ -/* heavily modified for GnuPG by <werner.koch@guug.de> */ -/* modified again for Sylpheed by <wk@gnupg.org> 2001-02-11 */ - - -/* Test values: - * "" D4 1D 8C D9 8F 00 B2 04 E9 80 09 98 EC F8 42 7E - * "a" 0C C1 75 B9 C0 F1 B6 A8 31 C3 99 E2 69 77 26 61 - * "abc 90 01 50 98 3C D2 4F B0 D6 96 3F 7D 28 E1 7F 72 - * "message digest" F9 6B 69 7D 7C B7 93 8D 52 5A 2F 31 AA F1 61 D0 - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#include "utils.h" -#include "md5.h" - - -/**************** - * Rotate a 32 bit integer by n bytes - */ -#if defined(__GNUC__) && defined(__i386__) -static inline u32 -rol( u32 x, int n) -{ - __asm__("roll %%cl,%0" - :"=r" (x) - :"0" (x),"c" (n)); - return x; -} -#else -#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) -#endif - - -void -md5_init(MD5_CONTEXT *ctx) -{ - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; - - ctx->nblocks = 0; - ctx->count = 0; - ctx->finalized = 0; -} - -/* These are the four functions used in the four steps of the MD5 algorithm - and defined in the RFC 1321. The first function is a little bit optimized - (as found in Colin Plumbs public domain implementation). */ -/* #define FF(b, c, d) ((b & c) | (~b & d)) */ -#define FF(b, c, d) (d ^ (b & (c ^ d))) -#define FG(b, c, d) FF (d, b, c) -#define FH(b, c, d) (b ^ c ^ d) -#define FI(b, c, d) (c ^ (b | ~d)) - - -/**************** - * transform n*64 bytes - */ -static void -transform(MD5_CONTEXT *ctx, const unsigned char *data) -{ - u32 correct_words[16]; - u32 A = ctx->A; - u32 B = ctx->B; - u32 C = ctx->C; - u32 D = ctx->D; - u32 *cwp = correct_words; - -#ifdef BIG_ENDIAN_HOST - { - int i; - unsigned char *p2, *p1; - - for (i = 0, p1 = data, p2 = (unsigned char*)correct_words; - i < 16; i++, p2 += 4) { - p2[3] = *p1++; - p2[2] = *p1++; - p2[1] = *p1++; - p2[0] = *p1++; - } - } -#else - memcpy(correct_words, data, 64); -#endif - - -#define OP(a, b, c, d, s, T) \ - do { \ - a += FF (b, c, d) + (*cwp++) + T; \ - a = rol(a, s); \ - a += b; \ - } while (0) - - /* Before we start, one word about the strange constants. - They are defined in RFC 1321 as - - T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 - */ - - /* Round 1. */ - OP (A, B, C, D, 7, 0xd76aa478); - OP (D, A, B, C, 12, 0xe8c7b756); - OP (C, D, A, B, 17, 0x242070db); - OP (B, C, D, A, 22, 0xc1bdceee); - OP (A, B, C, D, 7, 0xf57c0faf); - OP (D, A, B, C, 12, 0x4787c62a); - OP (C, D, A, B, 17, 0xa8304613); - OP (B, C, D, A, 22, 0xfd469501); - OP (A, B, C, D, 7, 0x698098d8); - OP (D, A, B, C, 12, 0x8b44f7af); - OP (C, D, A, B, 17, 0xffff5bb1); - OP (B, C, D, A, 22, 0x895cd7be); - OP (A, B, C, D, 7, 0x6b901122); - OP (D, A, B, C, 12, 0xfd987193); - OP (C, D, A, B, 17, 0xa679438e); - OP (B, C, D, A, 22, 0x49b40821); - -#undef OP -#define OP(f, a, b, c, d, k, s, T) \ - do { \ - a += f (b, c, d) + correct_words[k] + T; \ - a = rol(a, s); \ - a += b; \ - } while (0) - - /* Round 2. */ - OP (FG, A, B, C, D, 1, 5, 0xf61e2562); - OP (FG, D, A, B, C, 6, 9, 0xc040b340); - OP (FG, C, D, A, B, 11, 14, 0x265e5a51); - OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); - OP (FG, A, B, C, D, 5, 5, 0xd62f105d); - OP (FG, D, A, B, C, 10, 9, 0x02441453); - OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); - OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); - OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); - OP (FG, D, A, B, C, 14, 9, 0xc33707d6); - OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); - OP (FG, B, C, D, A, 8, 20, 0x455a14ed); - OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); - OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); - OP (FG, C, D, A, B, 7, 14, 0x676f02d9); - OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); - - /* Round 3. */ - OP (FH, A, B, C, D, 5, 4, 0xfffa3942); - OP (FH, D, A, B, C, 8, 11, 0x8771f681); - OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); - OP (FH, B, C, D, A, 14, 23, 0xfde5380c); - OP (FH, A, B, C, D, 1, 4, 0xa4beea44); - OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); - OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); - OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); - OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); - OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); - OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); - OP (FH, B, C, D, A, 6, 23, 0x04881d05); - OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); - OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); - OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); - OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); - - /* Round 4. */ - OP (FI, A, B, C, D, 0, 6, 0xf4292244); - OP (FI, D, A, B, C, 7, 10, 0x432aff97); - OP (FI, C, D, A, B, 14, 15, 0xab9423a7); - OP (FI, B, C, D, A, 5, 21, 0xfc93a039); - OP (FI, A, B, C, D, 12, 6, 0x655b59c3); - OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); - OP (FI, C, D, A, B, 10, 15, 0xffeff47d); - OP (FI, B, C, D, A, 1, 21, 0x85845dd1); - OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); - OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); - OP (FI, C, D, A, B, 6, 15, 0xa3014314); - OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); - OP (FI, A, B, C, D, 4, 6, 0xf7537e82); - OP (FI, D, A, B, C, 11, 10, 0xbd3af235); - OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); - OP (FI, B, C, D, A, 9, 21, 0xeb86d391); - - /* Put checksum in context given as argument. */ - ctx->A += A; - ctx->B += B; - ctx->C += C; - ctx->D += D; -} - - - -/* The routine updates the message-digest context to - * account for the presence of each of the characters inBuf[0..inLen-1] - * in the message whose digest is being computed. - */ -void -md5_update(MD5_CONTEXT *hd, const unsigned char *inbuf, size_t inlen) -{ - if (hd->count == 64) { /* flush the buffer */ - transform( hd, hd->buf ); - hd->count = 0; - hd->nblocks++; - } - if (!inbuf) - return; - if (hd->count) { - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; - md5_update(hd, NULL, 0); - if (!inlen) - return; - } - - while (inlen >= 64) { - transform(hd, inbuf); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; -} - - - -/* The routine final terminates the message-digest computation and - * ends with the desired message digest in mdContext->digest[0...15]. - * The handle is prepared for a new MD5 cycle. - * Returns 16 bytes representing the digest. - */ - -static void -do_final(MD5_CONTEXT *hd) -{ - u32 t, msb, lsb; - unsigned char *p; - - md5_update(hd, NULL, 0); /* flush */ - - msb = 0; - t = hd->nblocks; - if ((lsb = t << 6) < t) /* multiply by 64 to make a byte count */ - msb++; - msb += t >> 26; - t = lsb; - if ((lsb = t + hd->count) < t) /* add the count */ - msb++; - t = lsb; - if ((lsb = t << 3) < t) /* multiply by 8 to make a bit count */ - msb++; - msb += t >> 29; - - if (hd->count < 56) { /* enough room */ - hd->buf[hd->count++] = 0x80; /* pad */ - while(hd->count < 56) - hd->buf[hd->count++] = 0; /* pad */ - } else { /* need one extra block */ - hd->buf[hd->count++] = 0x80; /* pad character */ - while (hd->count < 64) - hd->buf[hd->count++] = 0; - md5_update(hd, NULL, 0); /* flush */ - memset(hd->buf, 0, 56); /* fill next block with zeroes */ - } - - /* append the 64 bit count */ - hd->buf[56] = lsb ; - hd->buf[57] = lsb >> 8; - hd->buf[58] = lsb >> 16; - hd->buf[59] = lsb >> 24; - hd->buf[60] = msb ; - hd->buf[61] = msb >> 8; - hd->buf[62] = msb >> 16; - hd->buf[63] = msb >> 24; - transform(hd, hd->buf); - - p = hd->buf; -#ifdef BIG_ENDIAN_HOST -#define X(a) do { *p++ = hd->a ; *p++ = hd->a >> 8; \ - *p++ = hd->a >> 16; *p++ = hd->a >> 24; } while(0) -#else /* little endian */ - /*#define X(a) do { *(u32*)p = hd->##a ; p += 4; } while(0)*/ - /* Unixware's cpp doesn't like the above construct so we do it his way: - * (reported by Allan Clark) */ -#define X(a) do { *(u32*)p = (*hd).a ; p += 4; } while(0) -#endif - X(A); - X(B); - X(C); - X(D); -#undef X - hd->finalized = 1; -} - -void -md5_final(unsigned char *digest, MD5_CONTEXT *ctx) -{ - if (!ctx->finalized) - do_final(ctx); - memcpy(digest, ctx->buf, 16); -} - -/* - * Creates a MD5 digest in hex fomrat (lowercase letters) from the - * string S. hextdigest but be buffer of at lease 33 bytes! - */ -void -md5_hex_digest(char *hexdigest, const unsigned char *s) -{ - int i; - MD5_CONTEXT context; - unsigned char digest[16]; - - md5_init(&context); - md5_update(&context, s, strlen(s)); - md5_final(digest, &context); - - for (i = 0; i < 16; i++) - sprintf(hexdigest + 2 * i, "%02x", digest[i]); -} - - -/* -** Function: md5_hmac -** taken from the file rfc2104.txt -** written by Martin Schaaf <mascha@ma-scha.de> -*/ -void -md5_hmac(unsigned char *digest, - const unsigned char* text, int text_len, - const unsigned char* key, int key_len) -{ - MD5_CONTEXT context; - unsigned char k_ipad[64]; /* inner padding - - * key XORd with ipad - */ - unsigned char k_opad[64]; /* outer padding - - * key XORd with opad - */ - /* unsigned char tk[16]; */ - int i; - - /* start out by storing key in pads */ - memset(k_ipad, 0, sizeof k_ipad); - memset(k_opad, 0, sizeof k_opad); - if (key_len > 64) { - /* if key is longer than 64 bytes reset it to key=MD5(key) */ - MD5_CONTEXT tctx; - - md5_init(&tctx); - md5_update(&tctx, key, key_len); - md5_final(k_ipad, &tctx); - md5_final(k_opad, &tctx); - } else { - memcpy(k_ipad, key, key_len); - memcpy(k_opad, key, key_len); - } - - /* - * the HMAC_MD5 transform looks like: - * - * MD5(K XOR opad, MD5(K XOR ipad, text)) - * - * where K is an n byte key - * ipad is the byte 0x36 repeated 64 times - * opad is the byte 0x5c repeated 64 times - * and text is the data being protected - */ - - - /* XOR key with ipad and opad values */ - for (i = 0; i < 64; i++) { - k_ipad[i] ^= 0x36; - k_opad[i] ^= 0x5c; - } - - /* - * perform inner MD5 - */ - md5_init(&context); /* init context for 1st - * pass */ - md5_update(&context, k_ipad, 64); /* start with inner pad */ - md5_update(&context, text, text_len); /* then text of datagram */ - md5_final(digest, &context); /* finish up 1st pass */ - /* - * perform outer MD5 - */ - md5_init(&context); /* init context for 2nd - * pass */ - md5_update(&context, k_opad, 64); /* start with outer pad */ - md5_update(&context, digest, 16); /* then results of 1st - * hash */ - md5_final(digest, &context); /* finish up 2nd pass */ -} - - -void -md5_hex_hmac(char *hexdigest, - const unsigned char* text, int text_len, - const unsigned char* key, int key_len) -{ - unsigned char digest[16]; - int i; - - md5_hmac(digest, text, text_len, key, key_len); - for (i = 0; i < 16; i++) - sprintf(hexdigest + 2 * i, "%02x", digest[i]); -} diff --git a/src/md5.h b/src/md5.h deleted file mode 100644 index 84894b2c..00000000 --- a/src/md5.h +++ /dev/null @@ -1,49 +0,0 @@ -/* md5.h - MD5 Message-Digest Algorithm - * Copyright (C) 1995, 1996, 1998, 1999 Free Software Foundation, Inc. - * - * according to the definition of MD5 in RFC 1321 from April 1992. - * NOTE: This is *not* the same file as the one from glibc - * - * 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, 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. - */ - -#ifndef _MD5_HDR_ -#define _MD5_HDR_ - -#include "utils.h" - -typedef struct { /* Hmm, should be private */ - u32 A,B,C,D; - u32 nblocks; - unsigned char buf[64]; - int count; - int finalized; -} MD5_CONTEXT; - -void md5_init(MD5_CONTEXT *ctx); -void md5_update(MD5_CONTEXT *hd, const unsigned char *inbuf, size_t inlen); -void md5_final(unsigned char *digest, MD5_CONTEXT *ctx); - -void md5_hex_digest(char *hexdigest, const unsigned char *s); - -void md5_hmac(unsigned char *digest, - const unsigned char* text, int text_len, - const unsigned char* key, int key_len); -void md5_hex_hmac(char *hexdigest, - const unsigned char* text, int text_len, - const unsigned char* key, int key_len); - -#endif /* _MD5_HDR_ */ - diff --git a/src/mh.c b/src/mh.c deleted file mode 100644 index 40554867..00000000 --- a/src/mh.c +++ /dev/null @@ -1,1431 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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 <glib/gi18n.h> -#include <dirent.h> -#include <sys/stat.h> -#include <time.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> - -#undef MEASURE_TIME - -#include "folder.h" -#include "mh.h" -#include "procmsg.h" -#include "procheader.h" -#include "utils.h" -#include "prefs_common.h" - -static void mh_folder_init (Folder *folder, - const gchar *name, - const gchar *path); - -static Folder *mh_folder_new (const gchar *name, - const gchar *path); -static void mh_folder_destroy (Folder *folder); - -static GSList *mh_get_msg_list (Folder *folder, - FolderItem *item, - gboolean use_cache); -static gchar *mh_fetch_msg (Folder *folder, - FolderItem *item, - gint num); -static MsgInfo *mh_get_msginfo (Folder *folder, - FolderItem *item, - gint num); -static gint mh_add_msg (Folder *folder, - FolderItem *dest, - const gchar *file, - MsgFlags *flags, - gboolean remove_source); -static gint mh_add_msgs (Folder *folder, - FolderItem *dest, - GSList *file_list, - gboolean remove_source, - gint *first); -static gint mh_move_msg (Folder *folder, - FolderItem *dest, - MsgInfo *msginfo); -static gint mh_move_msgs (Folder *folder, - FolderItem *dest, - GSList *msglist); -static gint mh_copy_msg (Folder *folder, - FolderItem *dest, - MsgInfo *msginfo); -static gint mh_copy_msgs (Folder *folder, - FolderItem *dest, - GSList *msglist); -static gint mh_remove_msg (Folder *folder, - FolderItem *item, - MsgInfo *msginfo); -static gint mh_remove_all_msg (Folder *folder, - FolderItem *item); -static gboolean mh_is_msg_changed (Folder *folder, - FolderItem *item, - MsgInfo *msginfo); -static gint mh_close (Folder *folder, - FolderItem *item); - -static gint mh_scan_folder_full (Folder *folder, - FolderItem *item, - gboolean count_sum); -static gint mh_scan_folder (Folder *folder, - FolderItem *item); -static gint mh_scan_tree (Folder *folder); - -static gint mh_create_tree (Folder *folder); -static FolderItem *mh_create_folder (Folder *folder, - FolderItem *parent, - const gchar *name); -static gint mh_rename_folder (Folder *folder, - FolderItem *item, - const gchar *name); -static gint mh_move_folder (Folder *folder, - FolderItem *item, - FolderItem *new_parent); -static gint mh_remove_folder (Folder *folder, - FolderItem *item); - -static gchar *mh_get_new_msg_filename (FolderItem *dest); - -static gint mh_do_move_msgs (Folder *folder, - FolderItem *dest, - GSList *msglist); - -static time_t mh_get_mtime (FolderItem *item); -static GSList *mh_get_uncached_msgs (GHashTable *msg_table, - FolderItem *item); -static MsgInfo *mh_parse_msg (const gchar *file, - FolderItem *item); -static void mh_remove_missing_folder_items (Folder *folder); -static void mh_scan_tree_recursive (FolderItem *item); - -static gboolean mh_rename_folder_func (GNode *node, - gpointer data); - -static FolderClass mh_class = -{ - F_MH, - - mh_folder_new, - mh_folder_destroy, - - mh_scan_tree, - mh_create_tree, - - mh_get_msg_list, - mh_fetch_msg, - mh_get_msginfo, - mh_add_msg, - mh_add_msgs, - mh_move_msg, - mh_move_msgs, - mh_copy_msg, - mh_copy_msgs, - mh_remove_msg, - NULL, - mh_remove_all_msg, - mh_is_msg_changed, - mh_close, - mh_scan_folder, - - mh_create_folder, - mh_rename_folder, - mh_move_folder, - mh_remove_folder, -}; - - -FolderClass *mh_get_class(void) -{ - return &mh_class; -} - -static Folder *mh_folder_new(const gchar *name, const gchar *path) -{ - Folder *folder; - - folder = (Folder *)g_new0(MHFolder, 1); - mh_folder_init(folder, name, path); - - return folder; -} - -static void mh_folder_destroy(Folder *folder) -{ - folder_local_folder_destroy(LOCAL_FOLDER(folder)); -} - -static void mh_folder_init(Folder *folder, const gchar *name, const gchar *path) -{ - folder->klass = mh_get_class(); - folder_local_folder_init(folder, name, path); -} - -static GSList *mh_get_msg_list(Folder *folder, FolderItem *item, - gboolean use_cache) -{ - GSList *mlist; - GHashTable *msg_table; - time_t cur_mtime; -#ifdef MEASURE_TIME - GTimer *timer; -#endif - - g_return_val_if_fail(item != NULL, NULL); - -#ifdef MEASURE_TIME - timer = g_timer_new(); -#endif - - cur_mtime = mh_get_mtime(item); - - if (use_cache && item->mtime == cur_mtime) { - debug_print("Folder is not modified.\n"); - mlist = procmsg_read_cache(item, FALSE); - if (!mlist) { - mlist = mh_get_uncached_msgs(NULL, item); - if (mlist) - item->cache_dirty = TRUE; - } - } else if (use_cache) { - GSList *newlist, *cur, *next; - gboolean strict_cache_check = prefs_common.strict_cache_check; - - if (item->stype == F_QUEUE || item->stype == F_DRAFT) - strict_cache_check = TRUE; - - mlist = procmsg_read_cache(item, strict_cache_check); - msg_table = procmsg_msg_hash_table_create(mlist); - newlist = mh_get_uncached_msgs(msg_table, item); - if (newlist) - item->cache_dirty = TRUE; - if (msg_table) - g_hash_table_destroy(msg_table); - - if (!strict_cache_check) { - /* remove nonexistent messages */ - for (cur = mlist; cur != NULL; cur = next) { - MsgInfo *msginfo = (MsgInfo *)cur->data; - next = cur->next; - if (!MSG_IS_CACHED(msginfo->flags)) { - debug_print("removing nonexistent message %d from cache\n", msginfo->msgnum); - mlist = g_slist_remove(mlist, msginfo); - procmsg_msginfo_free(msginfo); - item->cache_dirty = TRUE; - item->mark_dirty = TRUE; - } - } - } - - mlist = g_slist_concat(mlist, newlist); - } else { - mlist = mh_get_uncached_msgs(NULL, item); - item->cache_dirty = TRUE; - } - - item->mtime = cur_mtime; - - procmsg_set_flags(mlist, item); - - mlist = procmsg_sort_msg_list(mlist, item->sort_key, item->sort_type); - -#ifdef MEASURE_TIME - g_timer_stop(timer); - g_print("%s: %s: elapsed time: %f sec\n", - G_STRFUNC, item->path, g_timer_elapsed(timer, NULL)); - g_timer_destroy(timer); -#endif - debug_print("cache_dirty: %d, mark_dirty: %d\n", - item->cache_dirty, item->mark_dirty); - - return mlist; -} - -static gchar *mh_fetch_msg(Folder *folder, FolderItem *item, gint num) -{ - gchar *path; - gchar *file; - - g_return_val_if_fail(item != NULL, NULL); - g_return_val_if_fail(num > 0, NULL); - - if (item->last_num < 0 || num > item->last_num) { - mh_scan_folder(folder, item); - if (item->last_num < 0) return NULL; - } - - g_return_val_if_fail(num <= item->last_num, NULL); - - path = folder_item_get_path(item); - file = g_strconcat(path, G_DIR_SEPARATOR_S, itos(num), NULL); - g_free(path); - if (!is_file_exist(file)) { - g_free(file); - return NULL; - } - - return file; -} - -static MsgInfo *mh_get_msginfo(Folder *folder, FolderItem *item, gint num) -{ - MsgInfo *msginfo; - gchar *file; - - g_return_val_if_fail(item != NULL, NULL); - g_return_val_if_fail(num > 0, NULL); - - file = mh_fetch_msg(folder, item, num); - if (!file) return NULL; - - msginfo = mh_parse_msg(file, item); - if (msginfo) - msginfo->msgnum = num; - - g_free(file); - - return msginfo; -} - -static gchar *mh_get_new_msg_filename(FolderItem *dest) -{ - gchar *destfile; - gchar *destpath; - - destpath = folder_item_get_path(dest); - g_return_val_if_fail(destpath != NULL, NULL); - - if (!is_dir_exist(destpath)) - make_dir_hier(destpath); - - for (;;) { - destfile = g_strdup_printf("%s%c%d", destpath, G_DIR_SEPARATOR, - dest->last_num + 1); - if (is_file_entry_exist(destfile)) { - dest->last_num++; - g_free(destfile); - } else - break; - } - - g_free(destpath); - - return destfile; -} - -#define SET_DEST_MSG_FLAGS(fp, dest, n, fl) \ -{ \ - MsgInfo newmsginfo; \ - \ - newmsginfo.msgnum = n; \ - newmsginfo.flags = fl; \ - if (dest->stype == F_OUTBOX || \ - dest->stype == F_QUEUE || \ - dest->stype == F_DRAFT || \ - dest->stype == F_TRASH) \ - MSG_UNSET_PERM_FLAGS(newmsginfo.flags, \ - MSG_NEW|MSG_UNREAD|MSG_DELETED); \ - \ - if (fp) \ - procmsg_write_flags(&newmsginfo, fp); \ - else if (dest->opened) \ - procmsg_add_flags(dest, n, newmsginfo.flags); \ -} - -static gint mh_add_msg(Folder *folder, FolderItem *dest, const gchar *file, - MsgFlags *flags, gboolean remove_source) -{ - GSList file_list; - MsgFileInfo fileinfo; - - g_return_val_if_fail(file != NULL, -1); - - fileinfo.file = (gchar *)file; - fileinfo.flags = flags; - file_list.data = &fileinfo; - file_list.next = NULL; - - return mh_add_msgs(folder, dest, &file_list, remove_source, NULL); -} - -static gint mh_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list, - gboolean remove_source, gint *first) -{ - gchar *destfile; - GSList *cur; - MsgFileInfo *fileinfo; - gint first_ = 0; - FILE *fp; - - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(file_list != NULL, -1); - - if (dest->last_num < 0) { - mh_scan_folder(folder, dest); - if (dest->last_num < 0) return -1; - } - - if ((((MsgFileInfo *)file_list->data)->flags == NULL && - file_list->next == NULL) || dest->opened) - fp = NULL; - else if ((fp = procmsg_open_mark_file(dest, DATA_APPEND)) == NULL) - g_warning("Can't open mark file.\n"); - - for (cur = file_list; cur != NULL; cur = cur->next) { - fileinfo = (MsgFileInfo *)cur->data; - - destfile = mh_get_new_msg_filename(dest); - if (destfile == NULL) return -1; - if (first_ == 0 || first_ > dest->last_num + 1) - first_ = dest->last_num + 1; - -#ifdef G_OS_UNIX - if (link(fileinfo->file, destfile) < 0) { -#endif - if (copy_file(fileinfo->file, destfile, TRUE) < 0) { - g_warning(_("can't copy message %s to %s\n"), - fileinfo->file, destfile); - g_free(destfile); - return -1; - } -#ifdef G_OS_UNIX - } -#endif - - g_free(destfile); - dest->last_num++; - dest->total++; - dest->updated = TRUE; - - if (fileinfo->flags) { - if (MSG_IS_RECEIVED(*fileinfo->flags)) { - if (dest->unmarked_num == 0) - dest->new = 0; - dest->unmarked_num++; - procmsg_add_mark_queue(dest, dest->last_num, - *fileinfo->flags); - } else { - SET_DEST_MSG_FLAGS(fp, dest, dest->last_num, - *fileinfo->flags); - } - if (MSG_IS_NEW(*fileinfo->flags)) - dest->new++; - if (MSG_IS_UNREAD(*fileinfo->flags)) - dest->unread++; - } else { - if (dest->unmarked_num == 0) - dest->new = 0; - dest->unmarked_num++; - dest->new++; - dest->unread++; - } - } - - if (fp) fclose(fp); - - if (first) - *first = first_; - - if (remove_source) { - for (cur = file_list; cur != NULL; cur = cur->next) { - fileinfo = (MsgFileInfo *)cur->data; - if (g_unlink(fileinfo->file) < 0) - FILE_OP_ERROR(fileinfo->file, "unlink"); - } - } - - return dest->last_num; -} - -static gint mh_do_move_msgs(Folder *folder, FolderItem *dest, GSList *msglist) -{ - FolderItem *src; - gchar *srcfile; - gchar *destfile; - FILE *fp; - GSList *cur; - MsgInfo *msginfo; - - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(msglist != NULL, -1); - - if (dest->last_num < 0) { - mh_scan_folder(folder, dest); - if (dest->last_num < 0) return -1; - } - - if (dest->opened) - fp = NULL; - else if ((fp = procmsg_open_mark_file(dest, DATA_APPEND)) == NULL) - g_warning(_("Can't open mark file.\n")); - - for (cur = msglist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - src = msginfo->folder; - - if (src == dest) { - g_warning(_("the src folder is identical to the dest.\n")); - continue; - } - debug_print("Moving message %s%c%d to %s ...\n", - src->path, G_DIR_SEPARATOR, msginfo->msgnum, - dest->path); - - destfile = mh_get_new_msg_filename(dest); - if (!destfile) break; - srcfile = procmsg_get_message_file(msginfo); - - if (move_file(srcfile, destfile, FALSE) < 0) { - g_free(srcfile); - g_free(destfile); - break; - } - - g_free(srcfile); - g_free(destfile); - src->total--; - src->updated = TRUE; - dest->last_num++; - dest->total++; - dest->updated = TRUE; - - if (fp) { - SET_DEST_MSG_FLAGS(fp, dest, dest->last_num, - msginfo->flags); - } - - if (MSG_IS_NEW(msginfo->flags)) { - src->new--; - dest->new++; - } - if (MSG_IS_UNREAD(msginfo->flags)) { - src->unread--; - dest->unread++; - } - - MSG_SET_TMP_FLAGS(msginfo->flags, MSG_INVALID); - } - - if (fp) fclose(fp); - - return dest->last_num; -} - -static gint mh_move_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo) -{ - GSList msglist; - - g_return_val_if_fail(msginfo != NULL, -1); - - msglist.data = msginfo; - msglist.next = NULL; - - return mh_move_msgs(folder, dest, &msglist); -} - -static gint mh_move_msgs(Folder *folder, FolderItem *dest, GSList *msglist) -{ - MsgInfo *msginfo; - GSList *file_list; - gint ret = 0; - gint first; - - msginfo = (MsgInfo *)msglist->data; - if (folder == msginfo->folder->folder) - return mh_do_move_msgs(folder, dest, msglist); - - file_list = procmsg_get_message_file_list(msglist); - g_return_val_if_fail(file_list != NULL, -1); - - ret = mh_add_msgs(folder, dest, file_list, FALSE, &first); - - procmsg_message_file_list_free(file_list); - - if (ret != -1) - ret = folder_item_remove_msgs(msginfo->folder, msglist); - - return ret; -} - -static gint mh_copy_msg(Folder *folder, FolderItem *dest, MsgInfo *msginfo) -{ - GSList msglist; - - g_return_val_if_fail(msginfo != NULL, -1); - - msglist.data = msginfo; - msglist.next = NULL; - - return mh_copy_msgs(folder, dest, &msglist); -} - -static gint mh_copy_msgs(Folder *folder, FolderItem *dest, GSList *msglist) -{ - gchar *srcfile; - gchar *destfile; - FILE *fp; - GSList *cur; - MsgInfo *msginfo; - - g_return_val_if_fail(dest != NULL, -1); - g_return_val_if_fail(msglist != NULL, -1); - - if (dest->last_num < 0) { - mh_scan_folder(folder, dest); - if (dest->last_num < 0) return -1; - } - - if (dest->opened) - fp = NULL; - else if ((fp = procmsg_open_mark_file(dest, DATA_APPEND)) == NULL) - g_warning(_("Can't open mark file.\n")); - - for (cur = msglist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - - if (msginfo->folder == dest) { - g_warning(_("the src folder is identical to the dest.\n")); - continue; - } - debug_print(_("Copying message %s%c%d to %s ...\n"), - msginfo->folder->path, G_DIR_SEPARATOR, - msginfo->msgnum, dest->path); - - destfile = mh_get_new_msg_filename(dest); - if (!destfile) break; - srcfile = procmsg_get_message_file(msginfo); - - if (copy_file(srcfile, destfile, TRUE) < 0) { - FILE_OP_ERROR(srcfile, "copy"); - g_free(srcfile); - g_free(destfile); - break; - } - - g_free(srcfile); - g_free(destfile); - dest->last_num++; - dest->total++; - dest->updated = TRUE; - - if (fp) { - SET_DEST_MSG_FLAGS(fp, dest, dest->last_num, - msginfo->flags); - } - - if (MSG_IS_NEW(msginfo->flags)) - dest->new++; - if (MSG_IS_UNREAD(msginfo->flags)) - dest->unread++; - } - - if (fp) fclose(fp); - - return dest->last_num; -} - -static gint mh_remove_msg(Folder *folder, FolderItem *item, MsgInfo *msginfo) -{ - gchar *file; - - g_return_val_if_fail(item != NULL, -1); - - file = mh_fetch_msg(folder, item, msginfo->msgnum); - g_return_val_if_fail(file != NULL, -1); - - if (g_unlink(file) < 0) { - FILE_OP_ERROR(file, "unlink"); - g_free(file); - return -1; - } - g_free(file); - - item->total--; - item->updated = TRUE; - if (MSG_IS_NEW(msginfo->flags)) - item->new--; - if (MSG_IS_UNREAD(msginfo->flags)) - item->unread--; - MSG_SET_TMP_FLAGS(msginfo->flags, MSG_INVALID); - - if (msginfo->msgnum == item->last_num) - mh_scan_folder_full(folder, item, FALSE); - - return 0; -} - -static gint mh_remove_all_msg(Folder *folder, FolderItem *item) -{ - gchar *path; - gint val; - - g_return_val_if_fail(item != NULL, -1); - - path = folder_item_get_path(item); - g_return_val_if_fail(path != NULL, -1); - val = remove_all_numbered_files(path); - g_free(path); - if (val == 0) { - item->new = item->unread = item->total = 0; - item->last_num = 0; - item->updated = TRUE; - } - - return val; -} - -static gboolean mh_is_msg_changed(Folder *folder, FolderItem *item, - MsgInfo *msginfo) -{ - struct stat s; - - if (g_stat(itos(msginfo->msgnum), &s) < 0 || - msginfo->size != s.st_size || - msginfo->mtime != s.st_mtime) - return TRUE; - - return FALSE; -} - -static gint mh_close(Folder *folder, FolderItem *item) -{ - return 0; -} - -static gint mh_scan_folder_full(Folder *folder, FolderItem *item, - gboolean count_sum) -{ - gchar *path; - DIR *dp; - struct dirent *d; - gint max = 0; - gint num; - gint n_msg = 0; - - g_return_val_if_fail(item != NULL, -1); - - debug_print("mh_scan_folder(): Scanning %s ...\n", item->path); - - path = folder_item_get_path(item); - g_return_val_if_fail(path != NULL, -1); - if (change_dir(path) < 0) { - g_free(path); - return -1; - } - g_free(path); - - if ((dp = opendir(".")) == NULL) { - FILE_OP_ERROR(item->path, "opendir"); - return -1; - } - - if (folder->ui_func) - folder->ui_func(folder, item, folder->ui_func_data); - - while ((d = readdir(dp)) != NULL) { - if ((num = to_number(d->d_name)) > 0 && - dirent_is_regular_file(d)) { - n_msg++; - if (max < num) - max = num; - } - } - - closedir(dp); - - if (n_msg == 0) - item->new = item->unread = item->total = 0; - else if (count_sum) { - gint new, unread, total, min, max_; - - procmsg_get_mark_sum - (item, &new, &unread, &total, &min, &max_, 0); - - if (n_msg > total) { - item->unmarked_num = new = n_msg - total; - unread += n_msg - total; - } else - item->unmarked_num = 0; - - item->new = new; - item->unread = unread; - item->total = n_msg; - } - - item->updated = TRUE; - - debug_print(_("Last number in dir %s = %d\n"), item->path, max); - item->last_num = max; - - return 0; -} - -static gint mh_scan_folder(Folder *folder, FolderItem *item) -{ - return mh_scan_folder_full(folder, item, TRUE); -} - -static gint mh_scan_tree(Folder *folder) -{ - FolderItem *item; - gchar *rootpath; - - g_return_val_if_fail(folder != NULL, -1); - - if (!folder->node) { - item = folder_item_new(folder->name, NULL); - item->folder = folder; - folder->node = item->node = g_node_new(item); - } else - item = FOLDER_ITEM(folder->node->data); - - rootpath = folder_item_get_path(item); - if (change_dir(rootpath) < 0) { - g_free(rootpath); - return -1; - } - g_free(rootpath); - - mh_create_tree(folder); - mh_remove_missing_folder_items(folder); - mh_scan_tree_recursive(item); - - return 0; -} - -#define MAKE_DIR_IF_NOT_EXIST(dir) \ -{ \ - if (!is_dir_exist(dir)) { \ - if (is_file_exist(dir)) { \ - g_warning(_("File `%s' already exists.\n" \ - "Can't create folder."), dir); \ - return -1; \ - } \ - if (make_dir(dir) < 0) \ - return -1; \ - } \ -} - -static gint mh_create_tree(Folder *folder) -{ - gchar *rootpath; - - g_return_val_if_fail(folder != NULL, -1); - - CHDIR_RETURN_VAL_IF_FAIL(get_mail_base_dir(), -1); - rootpath = LOCAL_FOLDER(folder)->rootpath; - MAKE_DIR_IF_NOT_EXIST(rootpath); - CHDIR_RETURN_VAL_IF_FAIL(rootpath, -1); - MAKE_DIR_IF_NOT_EXIST(INBOX_DIR); - MAKE_DIR_IF_NOT_EXIST(OUTBOX_DIR); - MAKE_DIR_IF_NOT_EXIST(QUEUE_DIR); - MAKE_DIR_IF_NOT_EXIST(DRAFT_DIR); - MAKE_DIR_IF_NOT_EXIST(TRASH_DIR); - - return 0; -} - -#undef MAKE_DIR_IF_NOT_EXIST - -static FolderItem *mh_create_folder(Folder *folder, FolderItem *parent, - const gchar *name) -{ - gchar *path; - gchar *fs_name; - gchar *fullpath; - FolderItem *new_item; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(parent != NULL, NULL); - g_return_val_if_fail(name != NULL, NULL); - - path = folder_item_get_path(parent); - fs_name = g_filename_from_utf8(name, -1, NULL, NULL, NULL); - fullpath = g_strconcat(path, G_DIR_SEPARATOR_S, - fs_name ? fs_name : name, NULL); - g_free(fs_name); - g_free(path); - - if (make_dir(fullpath) < 0) { - g_free(fullpath); - return NULL; - } - - g_free(fullpath); - - if (parent->path) - path = g_strconcat(parent->path, G_DIR_SEPARATOR_S, name, - NULL); - else - path = g_strdup(name); - new_item = folder_item_new(name, path); - folder_item_append(parent, new_item); - g_free(path); - - return new_item; -} - -static gint mh_move_folder_real(Folder *folder, FolderItem *item, - FolderItem *new_parent, const gchar *name) -{ - gchar *oldpath; - gchar *newpath; - gchar *dirname; - gchar *new_dir; - gchar *name_; - gchar *utf8_name; - gchar *paths[2]; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(item != NULL, -1); - g_return_val_if_fail(folder == item->folder, -1); - g_return_val_if_fail(item->path != NULL, -1); - g_return_val_if_fail(new_parent != NULL || name != NULL, -1); - if (new_parent) { - g_return_val_if_fail(item != new_parent, -1); - g_return_val_if_fail(item->parent != new_parent, -1); - g_return_val_if_fail(item->folder == new_parent->folder, -1); - if (g_node_is_ancestor(item->node, new_parent->node)) { - g_warning("folder to be moved is ancestor of new parent\n"); - return -1; - } - } - - oldpath = folder_item_get_path(item); - if (new_parent) { - if (name) { - name_ = g_filename_from_utf8(name, -1, NULL, NULL, - NULL); - if (!name_) - name_ = g_strdup(name); - utf8_name = g_strdup(name); - } else { - name_ = g_path_get_basename(oldpath); - utf8_name = g_filename_to_utf8(name_, -1, NULL, NULL, - NULL); - if (!utf8_name) - utf8_name = g_strdup(name_); - } - new_dir = folder_item_get_path(new_parent); - newpath = g_strconcat(new_dir, G_DIR_SEPARATOR_S, name_, NULL); - g_free(new_dir); - } else { - name_ = g_filename_from_utf8(name, -1, NULL, NULL, NULL); - utf8_name = g_strdup(name); - dirname = g_dirname(oldpath); - newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S, - name_ ? name_ : name, NULL); - g_free(dirname); - } - g_free(name_); - - if (is_file_entry_exist(newpath)) { - g_warning("%s already exists\n", newpath); - g_free(oldpath); - g_free(newpath); - g_free(utf8_name); - return -1; - } - - debug_print("mh_move_folder: rename(%s, %s)\n", oldpath, newpath); - - if (g_rename(oldpath, newpath) < 0) { - FILE_OP_ERROR(oldpath, "rename"); - g_free(oldpath); - g_free(newpath); - g_free(utf8_name); - return -1; - } - - g_free(oldpath); - g_free(newpath); - - if (new_parent) { - g_node_unlink(item->node); - g_node_append(new_parent->node, item->node); - item->parent = new_parent; - if (new_parent->path != NULL) { - newpath = g_strconcat(new_parent->path, - G_DIR_SEPARATOR_S, utf8_name, - NULL); - g_free(utf8_name); - } else - newpath = utf8_name; - } else { - if (strchr(item->path, G_DIR_SEPARATOR) != NULL) { - dirname = g_dirname(item->path); - newpath = g_strconcat(dirname, G_DIR_SEPARATOR_S, - utf8_name, NULL); - g_free(dirname); - g_free(utf8_name); - } else - newpath = utf8_name; - } - - if (name) { - g_free(item->name); - item->name = g_strdup(name); - } - - paths[0] = g_strdup(item->path); - paths[1] = newpath; - g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, - mh_rename_folder_func, paths); - - g_free(paths[0]); - g_free(paths[1]); - - return 0; -} - -static gint mh_move_folder(Folder *folder, FolderItem *item, - FolderItem *new_parent) -{ - return mh_move_folder_real(folder, item, new_parent, NULL); -} - -static gint mh_rename_folder(Folder *folder, FolderItem *item, - const gchar *name) -{ - return mh_move_folder_real(folder, item, NULL, name); -} - -static gint mh_remove_folder(Folder *folder, FolderItem *item) -{ - gchar *path; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(item != NULL, -1); - g_return_val_if_fail(item->path != NULL, -1); - - path = folder_item_get_path(item); - if (remove_dir_recursive(path) < 0) { - g_warning("can't remove directory `%s'\n", path); - g_free(path); - return -1; - } - - g_free(path); - folder_item_remove(item); - return 0; -} - - -static time_t mh_get_mtime(FolderItem *item) -{ - gchar *path; - struct stat s; - - path = folder_item_get_path(item); - if (g_stat(path, &s) < 0) { - FILE_OP_ERROR(path, "stat"); - return -1; - } else { - return MAX(s.st_mtime, s.st_ctime); - } -} - -static GSList *mh_get_uncached_msgs(GHashTable *msg_table, FolderItem *item) -{ - gchar *path; - DIR *dp; - struct dirent *d; - GSList *newlist = NULL; - GSList *last = NULL; - MsgInfo *msginfo; - gint n_newmsg = 0; - gint num; - - g_return_val_if_fail(item != NULL, NULL); - - path = folder_item_get_path(item); - g_return_val_if_fail(path != NULL, NULL); - if (change_dir(path) < 0) { - g_free(path); - return NULL; - } - g_free(path); - - if ((dp = opendir(".")) == NULL) { - FILE_OP_ERROR(item->path, "opendir"); - return NULL; - } - - debug_print("Searching uncached messages...\n"); - - if (msg_table) { - while ((d = readdir(dp)) != NULL) { - if ((num = to_number(d->d_name)) <= 0) continue; - - msginfo = g_hash_table_lookup - (msg_table, GUINT_TO_POINTER(num)); - - if (msginfo) { - MSG_SET_TMP_FLAGS(msginfo->flags, MSG_CACHED); - } else { - /* not found in the cache (uncached message) */ - msginfo = mh_parse_msg(d->d_name, item); - if (!msginfo) continue; - - if (!newlist) - last = newlist = - g_slist_append(NULL, msginfo); - else { - last = g_slist_append(last, msginfo); - last = last->next; - } - n_newmsg++; - } - } - } else { - /* discard all previous cache */ - while ((d = readdir(dp)) != NULL) { - if (to_number(d->d_name) <= 0) continue; - - msginfo = mh_parse_msg(d->d_name, item); - if (!msginfo) continue; - - if (!newlist) - last = newlist = g_slist_append(NULL, msginfo); - else { - last = g_slist_append(last, msginfo); - last = last->next; - } - n_newmsg++; - } - } - - closedir(dp); - - if (n_newmsg) - debug_print("%d uncached message(s) found.\n", n_newmsg); - else - debug_print("done.\n"); - - /* sort new messages in numerical order */ - if (newlist && item->sort_key == SORT_BY_NONE) { - debug_print("Sorting uncached messages in numerical order...\n"); - newlist = g_slist_sort - (newlist, (GCompareFunc)procmsg_cmp_msgnum_for_sort); - debug_print("done.\n"); - } - - return newlist; -} - -static MsgInfo *mh_parse_msg(const gchar *file, FolderItem *item) -{ - MsgInfo *msginfo; - MsgFlags flags; - - g_return_val_if_fail(item != NULL, NULL); - g_return_val_if_fail(file != NULL, NULL); - - flags.perm_flags = MSG_NEW|MSG_UNREAD; - flags.tmp_flags = 0; - - if (item->stype == F_QUEUE) { - MSG_SET_TMP_FLAGS(flags, MSG_QUEUED); - } else if (item->stype == F_DRAFT) { - MSG_SET_TMP_FLAGS(flags, MSG_DRAFT); - } - - msginfo = procheader_parse_file(file, flags, FALSE); - if (!msginfo) return NULL; - - msginfo->msgnum = atoi(file); - msginfo->folder = item; - - return msginfo; -} - -#if 0 -static gboolean mh_is_maildir_one(const gchar *path, const gchar *dir) -{ - gchar *entry; - gboolean result; - - entry = g_strconcat(path, G_DIR_SEPARATOR_S, dir, NULL); - result = is_dir_exist(entry); - g_free(entry); - - return result; -} - -/* - * check whether PATH is a Maildir style mailbox. - * This is the case if the 3 subdir: new, cur, tmp are existing. - * This functon assumes that entry is an directory - */ -static gboolean mh_is_maildir(const gchar *path) -{ - return mh_is_maildir_one(path, "new") && - mh_is_maildir_one(path, "cur") && - mh_is_maildir_one(path, "tmp"); -} -#endif - -static gboolean mh_remove_missing_folder_items_func(GNode *node, gpointer data) -{ - FolderItem *item; - gchar *path; - - g_return_val_if_fail(node->data != NULL, FALSE); - - if (G_NODE_IS_ROOT(node)) - return FALSE; - - item = FOLDER_ITEM(node->data); - - path = folder_item_get_path(item); - if (!is_dir_exist(path)) { - debug_print("folder '%s' not found. removing...\n", path); - folder_item_remove(item); - } - g_free(path); - - return FALSE; -} - -static void mh_remove_missing_folder_items(Folder *folder) -{ - g_return_if_fail(folder != NULL); - - debug_print("searching missing folders...\n"); - - g_node_traverse(folder->node, G_POST_ORDER, G_TRAVERSE_ALL, -1, - mh_remove_missing_folder_items_func, folder); -} - -static void mh_scan_tree_recursive(FolderItem *item) -{ - Folder *folder; -#ifdef G_OS_WIN32 - GDir *dir; -#else - DIR *dp; - struct dirent *d; -#endif - const gchar *dir_name; - struct stat s; - gchar *fs_path; - gchar *entry; - gchar *utf8entry; - gchar *utf8name; - gint n_msg = 0; - - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - - folder = item->folder; - - fs_path = item->path ? - g_filename_from_utf8(item->path, -1, NULL, NULL, NULL) - : g_strdup("."); - if (!fs_path) - fs_path = g_strdup(item->path); -#ifdef G_OS_WIN32 - dir = g_dir_open(fs_path, 0, NULL); - if (!dir) { - g_warning("failed to open directory: %s\n", fs_path); - g_free(fs_path); - return; - } -#else - dp = opendir(fs_path); - if (!dp) { - FILE_OP_ERROR(fs_path, "opendir"); - g_free(fs_path); - return; - } -#endif - g_free(fs_path); - - debug_print("scanning %s ...\n", - item->path ? item->path - : LOCAL_FOLDER(item->folder)->rootpath); - if (folder->ui_func) - folder->ui_func(folder, item, folder->ui_func_data); - -#ifdef G_OS_WIN32 - while ((dir_name = g_dir_read_name(dir)) != NULL) { -#else - while ((d = readdir(dp)) != NULL) { - dir_name = d->d_name; -#endif - if (dir_name[0] == '.') continue; - - utf8name = g_filename_to_utf8(dir_name, -1, NULL, NULL, NULL); - if (!utf8name) - utf8name = g_strdup(dir_name); - - if (item->path) - utf8entry = g_strconcat(item->path, G_DIR_SEPARATOR_S, - utf8name, NULL); - else - utf8entry = g_strdup(utf8name); - entry = g_filename_from_utf8(utf8entry, -1, NULL, NULL, NULL); - if (!entry) - entry = g_strdup(utf8entry); - - if ( -#if !defined(G_OS_WIN32) && defined(HAVE_DIRENT_D_TYPE) - d->d_type == DT_DIR || - (d->d_type == DT_UNKNOWN && -#endif - g_stat(entry, &s) == 0 && S_ISDIR(s.st_mode) -#if !defined(G_OS_WIN32) && defined(HAVE_DIRENT_D_TYPE) - ) -#endif - ) { - FolderItem *new_item = NULL; - GNode *node; - -#if 0 - if (mh_is_maildir(entry)) { - g_free(entry); - g_free(utf8entry); - g_free(utf8name); - continue; - } -#endif - -#ifndef G_OS_WIN32 - if (g_utf8_validate(utf8name, -1, NULL) == FALSE) { - g_warning(_("Directory name\n" - "'%s' is not a valid UTF-8 string.\n" - "Maybe the locale encoding is used for filename.\n" - "If that is the case, you must set the following environmental variable\n" - "(see README for detail):\n" - "\n" - "\tG_FILENAME_ENCODING=@locale\n"), - utf8name); - g_free(entry); - g_free(utf8entry); - g_free(utf8name); - continue; - } -#endif /* G_OS_WIN32 */ - - node = item->node; - for (node = node->children; node != NULL; node = node->next) { - FolderItem *cur_item = FOLDER_ITEM(node->data); - if (!strcmp2(cur_item->path, utf8entry)) { - new_item = cur_item; - break; - } - } - if (!new_item) { - debug_print("new folder '%s' found.\n", entry); - new_item = folder_item_new(utf8name, utf8entry); - folder_item_append(item, new_item); - } - - if (!item->path) { - if (!folder->inbox && - !strcmp(dir_name, INBOX_DIR)) { - new_item->stype = F_INBOX; - folder->inbox = new_item; - } else if (!folder->outbox && - !strcmp(dir_name, OUTBOX_DIR)) { - new_item->stype = F_OUTBOX; - folder->outbox = new_item; - } else if (!folder->draft && - !strcmp(dir_name, DRAFT_DIR)) { - new_item->stype = F_DRAFT; - folder->draft = new_item; - } else if (!folder->queue && - !strcmp(dir_name, QUEUE_DIR)) { - new_item->stype = F_QUEUE; - folder->queue = new_item; - } else if (!folder->trash && - !strcmp(dir_name, TRASH_DIR)) { - new_item->stype = F_TRASH; - folder->trash = new_item; - } - } - - mh_scan_tree_recursive(new_item); - } else if (to_number(dir_name) > 0) n_msg++; - - g_free(entry); - g_free(utf8entry); - g_free(utf8name); - } - -#ifdef G_OS_WIN32 - g_dir_close(dir); -#else - closedir(dp); -#endif - - if (item->path) { - gint new, unread, total, min, max; - - procmsg_get_mark_sum - (item, &new, &unread, &total, &min, &max, 0); - if (n_msg > total) { - new += n_msg - total; - unread += n_msg - total; - } - item->new = new; - item->unread = unread; - item->total = n_msg; - item->updated = TRUE; - } -} - -static gboolean mh_rename_folder_func(GNode *node, gpointer data) -{ - FolderItem *item = node->data; - gchar **paths = data; - const gchar *oldpath = paths[0]; - const gchar *newpath = paths[1]; - gchar *base; - gchar *new_itempath; - gint oldpathlen; - - oldpathlen = strlen(oldpath); - if (strncmp(oldpath, item->path, oldpathlen) != 0) { - g_warning("path doesn't match: %s, %s\n", oldpath, item->path); - return TRUE; - } - - base = item->path + oldpathlen; - while (*base == G_DIR_SEPARATOR) base++; - if (*base == '\0') - new_itempath = g_strdup(newpath); - else - new_itempath = g_strconcat(newpath, G_DIR_SEPARATOR_S, base, - NULL); - g_free(item->path); - item->path = new_itempath; - - return FALSE; -} diff --git a/src/mh.h b/src/mh.h deleted file mode 100644 index 160259c1..00000000 --- a/src/mh.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 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. - */ - -#ifndef __MH_H__ -#define __MH_H__ - -#include <glib.h> - -#include "folder.h" - -typedef struct _MHFolder MHFolder; - -#define MH_FOLDER(obj) ((MHFolder *)obj) - -struct _MHFolder -{ - LocalFolder lfolder; -}; - -FolderClass *mh_get_class (void); - -#endif /* __MH_H__ */ diff --git a/src/news.c b/src/news.c deleted file mode 100644 index 28181b32..00000000 --- a/src/news.c +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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 <glib/gi18n.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <dirent.h> -#include <unistd.h> -#include <time.h> - -#include "news.h" -#include "nntp.h" -#include "socket.h" -#include "recv.h" -#include "procmsg.h" -#include "procheader.h" -#include "folder.h" -#include "session.h" -#include "codeconv.h" -#include "utils.h" -#include "prefs_common.h" -#include "prefs_account.h" -#if USE_SSL -# include "ssl.h" -#endif - -#define NNTP_PORT 119 -#if USE_SSL -#define NNTPS_PORT 563 -#endif - -static void news_folder_init (Folder *folder, - const gchar *name, - const gchar *path); - -static Folder *news_folder_new (const gchar *name, - const gchar *folder); -static void news_folder_destroy (Folder *folder); - -static GSList *news_get_article_list (Folder *folder, - FolderItem *item, - gboolean use_cache); -static gchar *news_fetch_msg (Folder *folder, - FolderItem *item, - gint num); -static MsgInfo *news_get_msginfo (Folder *folder, - FolderItem *item, - gint num); - -static gint news_close (Folder *folder, - FolderItem *item); - -static gint news_scan_group (Folder *folder, - FolderItem *item); - -#if USE_SSL -static Session *news_session_new (const gchar *server, - gushort port, - const gchar *userid, - const gchar *passwd, - SSLType ssl_type); -#else -static Session *news_session_new (const gchar *server, - gushort port, - const gchar *userid, - const gchar *passwd); -#endif - -static gint news_get_article_cmd (NNTPSession *session, - const gchar *cmd, - gint num, - gchar *filename); -static gint news_get_article (NNTPSession *session, - gint num, - gchar *filename); -#if 0 -static gint news_get_header (NNTPSession *session, - gint num, - gchar *filename); -#endif - -static gint news_select_group (NNTPSession *session, - const gchar *group, - gint *num, - gint *first, - gint *last); -static GSList *news_get_uncached_articles(NNTPSession *session, - FolderItem *item, - gint cache_last, - gint *rfirst, - gint *rlast); -static MsgInfo *news_parse_xover (const gchar *xover_str); -static gchar *news_parse_xhdr (const gchar *xhdr_str, - MsgInfo *msginfo); -static GSList *news_delete_old_articles (GSList *alist, - FolderItem *item, - gint first); -static void news_delete_all_articles (FolderItem *item); -static void news_delete_expired_caches (GSList *alist, - FolderItem *item); - -static FolderClass news_class = -{ - F_NEWS, - - news_folder_new, - news_folder_destroy, - - NULL, - NULL, - - news_get_article_list, - news_fetch_msg, - news_get_msginfo, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - news_close, - news_scan_group, - - NULL, - NULL, - NULL, - NULL -}; - - -FolderClass *news_get_class(void) -{ - return &news_class; -} - -static Folder *news_folder_new(const gchar *name, const gchar *path) -{ - Folder *folder; - - folder = (Folder *)g_new0(NewsFolder, 1); - news_folder_init(folder, name, path); - - return folder; -} - -static void news_folder_destroy(Folder *folder) -{ - gchar *dir; - - dir = folder_get_path(folder); - if (is_dir_exist(dir)) - remove_dir_recursive(dir); - g_free(dir); - - folder_remote_folder_destroy(REMOTE_FOLDER(folder)); -} - -static void news_folder_init(Folder *folder, const gchar *name, - const gchar *path) -{ - folder->klass = news_get_class(); - folder_remote_folder_init(folder, name, path); -} - -#if USE_SSL -static Session *news_session_new(const gchar *server, gushort port, - const gchar *userid, const gchar *passwd, - SSLType ssl_type) -#else -static Session *news_session_new(const gchar *server, gushort port, - const gchar *userid, const gchar *passwd) -#endif -{ - gchar buf[NNTPBUFSIZE]; - Session *session; - - g_return_val_if_fail(server != NULL, NULL); - - log_message(_("creating NNTP connection to %s:%d ...\n"), server, port); - -#if USE_SSL - session = nntp_session_new(server, port, buf, userid, passwd, ssl_type); -#else - session = nntp_session_new(server, port, buf, userid, passwd); -#endif - - return session; -} - -static Session *news_session_new_for_folder(Folder *folder) -{ - Session *session; - PrefsAccount *ac; - const gchar *userid = NULL; - gchar *passwd = NULL; - gushort port; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(folder->account != NULL, NULL); - - ac = folder->account; - if (ac->use_nntp_auth && ac->userid && ac->userid[0]) { - userid = ac->userid; - if (ac->passwd && ac->passwd[0]) - passwd = g_strdup(ac->passwd); - else - passwd = input_query_password(ac->nntp_server, userid); - } - -#if USE_SSL - port = ac->set_nntpport ? ac->nntpport - : ac->ssl_nntp ? NNTPS_PORT : NNTP_PORT; - session = news_session_new(ac->nntp_server, port, userid, passwd, - ac->ssl_nntp); -#else - port = ac->set_nntpport ? ac->nntpport : NNTP_PORT; - session = news_session_new(ac->nntp_server, port, userid, passwd); -#endif - - g_free(passwd); - - return session; -} - -static NNTPSession *news_session_get(Folder *folder) -{ - RemoteFolder *rfolder = REMOTE_FOLDER(folder); - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(FOLDER_TYPE(folder) == F_NEWS, NULL); - g_return_val_if_fail(folder->account != NULL, NULL); - - if (!prefs_common.online_mode) - return NULL; - - if (!rfolder->session) { - rfolder->session = news_session_new_for_folder(folder); - return NNTP_SESSION(rfolder->session); - } - - if (time(NULL) - rfolder->session->last_access_time < - SESSION_TIMEOUT_INTERVAL) { - return NNTP_SESSION(rfolder->session); - } - - if (nntp_mode(NNTP_SESSION(rfolder->session), FALSE) - != NN_SUCCESS) { - log_warning(_("NNTP connection to %s:%d has been" - " disconnected. Reconnecting...\n"), - folder->account->nntp_server, - folder->account->set_nntpport ? - folder->account->nntpport : NNTP_PORT); - session_destroy(rfolder->session); - rfolder->session = news_session_new_for_folder(folder); - } - - if (rfolder->session) - session_set_access_time(rfolder->session); - - return NNTP_SESSION(rfolder->session); -} - -static GSList *news_get_article_list(Folder *folder, FolderItem *item, - gboolean use_cache) -{ - GSList *alist; - NNTPSession *session; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(item != NULL, NULL); - g_return_val_if_fail(FOLDER_TYPE(folder) == F_NEWS, NULL); - - session = news_session_get(folder); - - if (!session) { - alist = procmsg_read_cache(item, FALSE); - item->last_num = procmsg_get_last_num_in_msg_list(alist); - } else if (use_cache) { - GSList *newlist; - gint cache_last; - gint first, last; - - alist = procmsg_read_cache(item, FALSE); - - cache_last = procmsg_get_last_num_in_msg_list(alist); - newlist = news_get_uncached_articles - (session, item, cache_last, &first, &last); - if (newlist) - item->cache_dirty = TRUE; - if (first == 0 && last == 0) { - news_delete_all_articles(item); - procmsg_msg_list_free(alist); - alist = NULL; - item->cache_dirty = TRUE; - } else { - alist = news_delete_old_articles(alist, item, first); - news_delete_expired_caches(alist, item); - } - - alist = g_slist_concat(alist, newlist); - - item->last_num = last; - } else { - gint last; - - alist = news_get_uncached_articles - (session, item, 0, NULL, &last); - news_delete_all_articles(item); - item->last_num = last; - item->cache_dirty = TRUE; - } - - procmsg_set_flags(alist, item); - - alist = procmsg_sort_msg_list(alist, item->sort_key, item->sort_type); - - debug_print("cache_dirty: %d, mark_dirty: %d\n", - item->cache_dirty, item->mark_dirty); - - return alist; -} - -static gchar *news_fetch_msg(Folder *folder, FolderItem *item, gint num) -{ - gchar *path, *filename; - NNTPSession *session; - gint ok; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(item != NULL, NULL); - - path = folder_item_get_path(item); - if (!is_dir_exist(path)) - make_dir_hier(path); - filename = g_strconcat(path, G_DIR_SEPARATOR_S, itos(num), NULL); - g_free(path); - - if (is_file_exist(filename)) { - debug_print(_("article %d has been already cached.\n"), num); - return filename; - } - - session = news_session_get(folder); - if (!session) { - g_free(filename); - return NULL; - } - - ok = news_select_group(session, item->path, NULL, NULL, NULL); - if (ok != NN_SUCCESS) { - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(folder)->session = NULL; - } - g_free(filename); - return NULL; - } - - debug_print(_("getting article %d...\n"), num); - ok = news_get_article(NNTP_SESSION(REMOTE_FOLDER(folder)->session), - num, filename); - if (ok != NN_SUCCESS) { - g_warning(_("can't read article %d\n"), num); - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(folder)->session = NULL; - } - g_free(filename); - return NULL; - } - - return filename; -} - -static MsgInfo *news_get_msginfo(Folder *folder, FolderItem *item, gint num) -{ - MsgInfo *msginfo; - MsgFlags flags = {0, 0}; - gchar *file; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(item != NULL, NULL); - - file = news_fetch_msg(folder, item, num); - if (!file) return NULL; - - msginfo = procheader_parse_file(file, flags, FALSE); - - g_free(file); - - return msginfo; -} - -static gint news_close(Folder *folder, FolderItem *item) -{ - return 0; -} - -static gint news_scan_group(Folder *folder, FolderItem *item) -{ - NNTPSession *session; - gint num = 0, first = 0, last = 0; - gint new = 0, unread = 0, total = 0; - gint min = 0, max = 0; - gint ok; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(item != NULL, -1); - - session = news_session_get(folder); - if (!session) return -1; - - ok = news_select_group(session, item->path, &num, &first, &last); - if (ok != NN_SUCCESS) { - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(folder)->session = NULL; - } - return -1; - } - - if (num == 0) { - item->new = item->unread = item->total = item->last_num = 0; - return 0; - } - - procmsg_get_mark_sum(item, &new, &unread, &total, &min, &max, first); - - if (max < first || last < min) - new = unread = total = num; - else { - if (min < first) - min = first; - - if (last < max) - max = last; - else if (max < last) { - new += last - max; - unread += last - max; - } - - if (new > num) new = num; - if (unread > num) unread = num; - } - - item->new = new; - item->unread = unread; - item->total = num; - item->last_num = last; - - return 0; -} - -static NewsGroupInfo *news_group_info_new(const gchar *name, - gint first, gint last, gchar type) -{ - NewsGroupInfo *ginfo; - - ginfo = g_new(NewsGroupInfo, 1); - ginfo->name = g_strdup(name); - ginfo->first = first; - ginfo->last = last; - ginfo->type = type; - - return ginfo; -} - -static void news_group_info_free(NewsGroupInfo *ginfo) -{ - g_free(ginfo->name); - g_free(ginfo); -} - -static gint news_group_info_compare(NewsGroupInfo *ginfo1, - NewsGroupInfo *ginfo2) -{ - return g_ascii_strcasecmp(ginfo1->name, ginfo2->name); -} - -GSList *news_get_group_list(Folder *folder) -{ - gchar *path, *filename; - FILE *fp; - GSList *list = NULL; - GSList *last = NULL; - gchar buf[NNTPBUFSIZE]; - - g_return_val_if_fail(folder != NULL, NULL); - g_return_val_if_fail(FOLDER_TYPE(folder) == F_NEWS, NULL); - - path = folder_item_get_path(FOLDER_ITEM(folder->node->data)); - if (!is_dir_exist(path)) - make_dir_hier(path); - filename = g_strconcat(path, G_DIR_SEPARATOR_S, NEWSGROUP_LIST, NULL); - g_free(path); - - if ((fp = g_fopen(filename, "rb")) == NULL) { - NNTPSession *session; - gint ok; - - session = news_session_get(folder); - if (!session) { - g_free(filename); - return NULL; - } - - ok = nntp_list(session); - if (ok != NN_SUCCESS) { - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(folder)->session = NULL; - } - g_free(filename); - return NULL; - } - if (recv_write_to_file(SESSION(session)->sock, filename) < 0) { - log_warning(_("can't retrieve newsgroup list\n")); - session_destroy(SESSION(session)); - REMOTE_FOLDER(folder)->session = NULL; - g_free(filename); - return NULL; - } - - if ((fp = g_fopen(filename, "rb")) == NULL) { - FILE_OP_ERROR(filename, "fopen"); - g_free(filename); - return NULL; - } - } - - while (fgets(buf, sizeof(buf), fp) != NULL) { - gchar *p = buf; - gchar *name; - gint last_num; - gint first_num; - gchar type; - NewsGroupInfo *ginfo; - - p = strchr(p, ' '); - if (!p) continue; - *p = '\0'; - p++; - name = buf; - - if (sscanf(p, "%d %d %c", &last_num, &first_num, &type) < 3) - continue; - - ginfo = news_group_info_new(name, first_num, last_num, type); - - if (!last) - last = list = g_slist_append(NULL, ginfo); - else { - last = g_slist_append(last, ginfo); - last = last->next; - } - } - - fclose(fp); - g_free(filename); - - list = g_slist_sort(list, (GCompareFunc)news_group_info_compare); - - return list; -} - -void news_group_list_free(GSList *group_list) -{ - GSList *cur; - - if (!group_list) return; - - for (cur = group_list; cur != NULL; cur = cur->next) - news_group_info_free((NewsGroupInfo *)cur->data); - g_slist_free(group_list); -} - -void news_remove_group_list_cache(Folder *folder) -{ - gchar *path, *filename; - - g_return_if_fail(folder != NULL); - g_return_if_fail(FOLDER_TYPE(folder) == F_NEWS); - - path = folder_item_get_path(FOLDER_ITEM(folder->node->data)); - filename = g_strconcat(path, G_DIR_SEPARATOR_S, NEWSGROUP_LIST, NULL); - g_free(path); - - if (is_file_exist(filename)) { - if (remove(filename) < 0) - FILE_OP_ERROR(filename, "remove"); - } - g_free(filename); -} - -gint news_post(Folder *folder, const gchar *file) -{ - FILE *fp; - gint ok; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(FOLDER_TYPE(folder) == F_NEWS, -1); - g_return_val_if_fail(file != NULL, -1); - - if ((fp = g_fopen(file, "rb")) == NULL) { - FILE_OP_ERROR(file, "fopen"); - return -1; - } - - ok = news_post_stream(folder, fp); - - fclose(fp); - - return ok; -} - -gint news_post_stream(Folder *folder, FILE *fp) -{ - NNTPSession *session; - gint ok; - - g_return_val_if_fail(folder != NULL, -1); - g_return_val_if_fail(FOLDER_TYPE(folder) == F_NEWS, -1); - g_return_val_if_fail(fp != NULL, -1); - - session = news_session_get(folder); - if (!session) return -1; - - ok = nntp_post(session, fp); - if (ok != NN_SUCCESS) { - log_warning(_("can't post article.\n")); - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(folder)->session = NULL; - } - return -1; - } - - return 0; -} - -static gint news_get_article_cmd(NNTPSession *session, const gchar *cmd, - gint num, gchar *filename) -{ - gchar *msgid; - gint ok; - - ok = nntp_get_article(session, cmd, num, &msgid); - if (ok != NN_SUCCESS) - return ok; - - debug_print("Message-Id = %s, num = %d\n", msgid, num); - g_free(msgid); - - ok = recv_write_to_file(SESSION(session)->sock, filename); - if (ok < 0) { - log_warning(_("can't retrieve article %d\n"), num); - if (ok == -2) - return NN_SOCKET; - else - return NN_IOERR; - } - - return NN_SUCCESS; -} - -static gint news_get_article(NNTPSession *session, gint num, gchar *filename) -{ - return news_get_article_cmd(session, "ARTICLE", num, filename); -} - -#if 0 -static gint news_get_header(NNTPSession *session, gint num, gchar *filename) -{ - return news_get_article_cmd(session, "HEAD", num, filename); -} -#endif - -/** - * news_select_group: - * @session: Active NNTP session. - * @group: Newsgroup name. - * @num: Estimated number of articles. - * @first: First article number. - * @last: Last article number. - * - * Select newsgroup @group with the GROUP command if it is not already - * selected in @session, or article numbers need to be returned. - * - * Return value: NNTP result code. - **/ -static gint news_select_group(NNTPSession *session, const gchar *group, - gint *num, gint *first, gint *last) -{ - gint ok; - gint num_, first_, last_; - - if (!num || !first || !last) { - if (session->group && - g_ascii_strcasecmp(session->group, group) == 0) - return NN_SUCCESS; - num = &num_; - first = &first_; - last = &last_; - } - - g_free(session->group); - session->group = NULL; - - ok = nntp_group(session, group, num, first, last); - if (ok == NN_SUCCESS) - session->group = g_strdup(group); - else - log_warning(_("can't select group: %s\n"), group); - - return ok; -} - -static GSList *news_get_uncached_articles(NNTPSession *session, - FolderItem *item, gint cache_last, - gint *rfirst, gint *rlast) -{ - gint ok; - gint num = 0, first = 0, last = 0, begin = 0, end = 0; - gchar buf[NNTPBUFSIZE]; - GSList *newlist = NULL; - GSList *llast = NULL; - MsgInfo *msginfo; - gint max_articles; - - if (rfirst) *rfirst = -1; - if (rlast) *rlast = -1; - - g_return_val_if_fail(session != NULL, NULL); - g_return_val_if_fail(item != NULL, NULL); - g_return_val_if_fail(item->folder != NULL, NULL); - g_return_val_if_fail(item->folder->account != NULL, NULL); - g_return_val_if_fail(FOLDER_TYPE(item->folder) == F_NEWS, NULL); - - ok = news_select_group(session, item->path, &num, &first, &last); - if (ok != NN_SUCCESS) { - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(item->folder)->session = NULL; - } - return NULL; - } - - /* calculate getting overview range */ - if (first > last) { - log_warning(_("invalid article range: %d - %d\n"), - first, last); - return NULL; - } - - if (rfirst) *rfirst = first; - if (rlast) *rlast = last; - - if (cache_last < first) - begin = first; - else if (last < cache_last) - begin = first; - else if (last == cache_last) { - debug_print(_("no new articles.\n")); - return NULL; - } else - begin = cache_last + 1; - end = last; - - max_articles = item->folder->account->max_nntp_articles; - if (max_articles > 0 && end - begin + 1 > max_articles) - begin = end - max_articles + 1; - - log_message(_("getting xover %d - %d in %s...\n"), - begin, end, item->path); - ok = nntp_xover(session, begin, end); - if (ok != NN_SUCCESS) { - log_warning(_("can't get xover\n")); - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(item->folder)->session = NULL; - } - return NULL; - } - - for (;;) { - if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) < 0) { - log_warning(_("error occurred while getting xover.\n")); - session_destroy(SESSION(session)); - REMOTE_FOLDER(item->folder)->session = NULL; - return newlist; - } - - if (buf[0] == '.' && buf[1] == '\r') break; - - msginfo = news_parse_xover(buf); - if (!msginfo) { - log_warning(_("invalid xover line: %s\n"), buf); - continue; - } - - msginfo->folder = item; - msginfo->flags.perm_flags = MSG_NEW|MSG_UNREAD; - msginfo->flags.tmp_flags = MSG_NEWS; - msginfo->newsgroups = g_strdup(item->path); - - if (!newlist) - llast = newlist = g_slist_append(newlist, msginfo); - else { - llast = g_slist_append(llast, msginfo); - llast = llast->next; - } - } - - ok = nntp_xhdr(session, "to", begin, end); - if (ok != NN_SUCCESS) { - log_warning(_("can't get xhdr\n")); - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(item->folder)->session = NULL; - } - return newlist; - } - - llast = newlist; - - for (;;) { - if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) < 0) { - log_warning(_("error occurred while getting xhdr.\n")); - session_destroy(SESSION(session)); - REMOTE_FOLDER(item->folder)->session = NULL; - return newlist; - } - - if (buf[0] == '.' && buf[1] == '\r') break; - if (!llast) { - g_warning("llast == NULL\n"); - continue; - } - - msginfo = (MsgInfo *)llast->data; - msginfo->to = news_parse_xhdr(buf, msginfo); - - llast = llast->next; - } - - ok = nntp_xhdr(session, "cc", begin, end); - if (ok != NN_SUCCESS) { - log_warning(_("can't get xhdr\n")); - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - REMOTE_FOLDER(item->folder)->session = NULL; - } - return newlist; - } - - llast = newlist; - - for (;;) { - if (sock_gets(SESSION(session)->sock, buf, sizeof(buf)) < 0) { - log_warning(_("error occurred while getting xhdr.\n")); - session_destroy(SESSION(session)); - REMOTE_FOLDER(item->folder)->session = NULL; - return newlist; - } - - if (buf[0] == '.' && buf[1] == '\r') break; - if (!llast) { - g_warning("llast == NULL\n"); - continue; - } - - msginfo = (MsgInfo *)llast->data; - msginfo->cc = news_parse_xhdr(buf, msginfo); - - llast = llast->next; - } - - session_set_access_time(SESSION(session)); - - return newlist; -} - -#define PARSE_ONE_PARAM(p, srcp) \ -{ \ - p = strchr(srcp, '\t'); \ - if (!p) return NULL; \ - else \ - *p++ = '\0'; \ -} - -static MsgInfo *news_parse_xover(const gchar *xover_str) -{ - MsgInfo *msginfo; - gchar *subject, *sender, *size, *line, *date, *msgid, *ref, *tmp; - gchar *p; - gint num, size_int, line_int; - gchar *xover_buf; - - Xstrdup_a(xover_buf, xover_str, return NULL); - - PARSE_ONE_PARAM(subject, xover_buf); - PARSE_ONE_PARAM(sender, subject); - PARSE_ONE_PARAM(date, sender); - PARSE_ONE_PARAM(msgid, date); - PARSE_ONE_PARAM(ref, msgid); - PARSE_ONE_PARAM(size, ref); - PARSE_ONE_PARAM(line, size); - - tmp = strchr(line, '\t'); - if (!tmp) tmp = strchr(line, '\r'); - if (!tmp) tmp = strchr(line, '\n'); - if (tmp) *tmp = '\0'; - - num = atoi(xover_str); - size_int = atoi(size); - line_int = atoi(line); - - /* set MsgInfo */ - msginfo = g_new0(MsgInfo, 1); - msginfo->msgnum = num; - msginfo->size = size_int; - - msginfo->date = g_strdup(date); - msginfo->date_t = procheader_date_parse(NULL, date, 0); - - msginfo->from = conv_unmime_header(sender, NULL); - msginfo->fromname = procheader_get_fromname(msginfo->from); - - msginfo->subject = conv_unmime_header(subject, NULL); - - extract_parenthesis(msgid, '<', '>'); - remove_space(msgid); - if (*msgid != '\0') - msginfo->msgid = g_strdup(msgid); - - eliminate_parenthesis(ref, '(', ')'); - if ((p = strrchr(ref, '<')) != NULL) { - extract_parenthesis(p, '<', '>'); - remove_space(p); - if (*p != '\0') - msginfo->inreplyto = g_strdup(p); - } - - return msginfo; -} - -static gchar *news_parse_xhdr(const gchar *xhdr_str, MsgInfo *msginfo) -{ - gchar *p; - gchar *tmp; - gint num; - - p = strchr(xhdr_str, ' '); - if (!p) - return NULL; - else - p++; - - num = atoi(xhdr_str); - if (msginfo->msgnum != num) return NULL; - - tmp = strchr(p, '\r'); - if (!tmp) tmp = strchr(p, '\n'); - - if (tmp) - return g_strndup(p, tmp - p); - else - return g_strdup(p); -} - -static GSList *news_delete_old_articles(GSList *alist, FolderItem *item, - gint first) -{ - GSList *cur, *next; - MsgInfo *msginfo; - gchar *dir; - - g_return_val_if_fail(item != NULL, alist); - g_return_val_if_fail(item->folder != NULL, alist); - g_return_val_if_fail(FOLDER_TYPE(item->folder) == F_NEWS, alist); - - if (first < 2) return alist; - - debug_print("Deleting cached articles 1 - %d ...\n", first - 1); - - dir = folder_item_get_path(item); - remove_numbered_files(dir, 1, first - 1); - g_free(dir); - - for (cur = alist; cur != NULL; ) { - next = cur->next; - - msginfo = (MsgInfo *)cur->data; - if (msginfo && msginfo->msgnum < first) { - procmsg_msginfo_free(msginfo); - alist = g_slist_remove(alist, msginfo); - item->cache_dirty = TRUE; - } - - cur = next; - } - - return alist; -} - -static void news_delete_all_articles(FolderItem *item) -{ - gchar *dir; - - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS); - - debug_print("Deleting all cached articles...\n"); - - dir = folder_item_get_path(item); - remove_all_numbered_files(dir); - g_free(dir); -} - -static void news_delete_expired_caches(GSList *alist, FolderItem *item) -{ - gchar *dir; - - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - g_return_if_fail(FOLDER_TYPE(item->folder) == F_NEWS); - - debug_print("Deleting expired cached articles...\n"); - - dir = folder_item_get_path(item); - remove_expired_files(dir, 24 * 7); - g_free(dir); -} diff --git a/src/news.h b/src/news.h deleted file mode 100644 index 31628113..00000000 --- a/src/news.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 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. - */ - -#ifndef __NEWS_H__ -#define __NEWS_H__ - -#include <glib.h> -#include <stdio.h> - -#include "folder.h" - -typedef struct _NewsFolder NewsFolder; -typedef struct _NewsGroupInfo NewsGroupInfo; - -#define NEWS_FOLDER(obj) ((NewsFolder *)obj) - -struct _NewsFolder -{ - RemoteFolder rfolder; - - gboolean use_auth; -}; - -struct _NewsGroupInfo -{ - gchar *name; - guint first; - guint last; - gchar type; -}; - -FolderClass *news_get_class (void); - -GSList *news_get_group_list (Folder *folder); -void news_group_list_free (GSList *group_list); -void news_remove_group_list_cache (Folder *folder); - -gint news_post (Folder *folder, - const gchar *file); -gint news_post_stream (Folder *folder, - FILE *fp); - -#endif /* __NEWS_H__ */ diff --git a/src/nntp.c b/src/nntp.c deleted file mode 100644 index 7e36baaa..00000000 --- a/src/nntp.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * 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 <glib.h> -#include <glib/gi18n.h> -#include <stdio.h> -#include <string.h> - -#include "nntp.h" -#include "socket.h" -#include "utils.h" -#if USE_SSL -# include "ssl.h" -#endif - -static gint verbose = 1; - -static void nntp_session_destroy(Session *session); - -static gint nntp_ok (SockInfo *sock, - gchar *argbuf); - -static gint nntp_gen_send (SockInfo *sock, - const gchar *format, - ...); -static gint nntp_gen_recv (SockInfo *sock, - gchar *buf, - gint size); -static gint nntp_gen_command (NNTPSession *session, - gchar *argbuf, - const gchar *format, - ...); - - -#if USE_SSL -Session *nntp_session_new(const gchar *server, gushort port, gchar *buf, - const gchar *userid, const gchar *passwd, - SSLType ssl_type) -#else -Session *nntp_session_new(const gchar *server, gushort port, gchar *buf, - const gchar *userid, const gchar *passwd) -#endif -{ - NNTPSession *session; - SockInfo *sock; - - if ((sock = sock_connect(server, port)) == NULL) { - log_warning(_("Can't connect to NNTP server: %s:%d\n"), - server, port); - return NULL; - } - -#if USE_SSL - if (ssl_type == SSL_TUNNEL && !ssl_init_socket(sock)) { - sock_close(sock); - return NULL; - } -#endif - - if (nntp_ok(sock, buf) != NN_SUCCESS) { - sock_close(sock); - return NULL; - } - - session = g_new0(NNTPSession, 1); - - session_init(SESSION(session)); - - SESSION(session)->type = SESSION_NEWS; - SESSION(session)->server = g_strdup(server); - SESSION(session)->sock = sock; - SESSION(session)->last_access_time = time(NULL); - SESSION(session)->data = NULL; - - SESSION(session)->destroy = nntp_session_destroy; - - session->group = NULL; - - if (userid && passwd) { - gint ok; - - session->userid = g_strdup(userid); - session->passwd = g_strdup(passwd); - - ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid); - if (ok != NN_SUCCESS) { - session_destroy(SESSION(session)); - return NULL; - } - ok = nntp_ok(sock, NULL); - if (ok == NN_AUTHCONT) { - ok = nntp_gen_send(sock, "AUTHINFO PASS %s", - session->passwd); - if (ok != NN_SUCCESS) { - session_destroy(SESSION(session)); - return NULL; - } - ok = nntp_ok(sock, NULL); - if (ok != NN_SUCCESS) - session->auth_failed = TRUE; - } - if (ok == NN_SOCKET) { - session_destroy(SESSION(session)); - return NULL; - } - } - - session_set_access_time(SESSION(session)); - - return SESSION(session); -} - -static void nntp_session_destroy(Session *session) -{ - NNTPSession *nntp_session = NNTP_SESSION(session); - - g_return_if_fail(session != NULL); - - g_free(nntp_session->group); - g_free(nntp_session->userid); - g_free(nntp_session->passwd); -} - -gint nntp_group(NNTPSession *session, const gchar *group, - gint *num, gint *first, gint *last) -{ - gint ok; - gint resp; - gchar buf[NNTPBUFSIZE]; - - ok = nntp_gen_command(session, buf, "GROUP %s", group); - - if (ok != NN_SUCCESS && ok != NN_SOCKET && ok != NN_AUTHREQ) { - ok = nntp_mode(session, FALSE); - if (ok == NN_SUCCESS) - ok = nntp_gen_command(session, buf, "GROUP %s", group); - } - - if (ok != NN_SUCCESS) - return ok; - - if (sscanf(buf, "%d %d %d %d", &resp, num, first, last) - != 4) { - log_warning(_("protocol error: %s\n"), buf); - return NN_PROTOCOL; - } - - return NN_SUCCESS; -} - -gint nntp_get_article(NNTPSession *session, const gchar *cmd, gint num, - gchar **msgid) -{ - gint ok; - gchar buf[NNTPBUFSIZE]; - - if (num > 0) - ok = nntp_gen_command(session, buf, "%s %d", cmd, num); - else - ok = nntp_gen_command(session, buf, cmd); - - if (ok != NN_SUCCESS) - return ok; - - extract_parenthesis(buf, '<', '>'); - if (buf[0] == '\0') { - log_warning(_("protocol error\n")); - *msgid = g_strdup("0"); - } else - *msgid = g_strdup(buf); - - return NN_SUCCESS; -} - -gint nntp_article(NNTPSession *session, gint num, gchar **msgid) -{ - return nntp_get_article(session, "ARTICLE", num, msgid); -} - -gint nntp_body(NNTPSession *session, gint num, gchar **msgid) -{ - return nntp_get_article(session, "BODY", num, msgid); -} - -gint nntp_head(NNTPSession *session, gint num, gchar **msgid) -{ - return nntp_get_article(session, "HEAD", num, msgid); -} - -gint nntp_stat(NNTPSession *session, gint num, gchar **msgid) -{ - return nntp_get_article(session, "STAT", num, msgid); -} - -gint nntp_next(NNTPSession *session, gint *num, gchar **msgid) -{ - gint ok; - gint resp; - gchar buf[NNTPBUFSIZE]; - - ok = nntp_gen_command(session, buf, "NEXT"); - - if (ok != NN_SUCCESS) - return ok; - - if (sscanf(buf, "%d %d", &resp, num) != 2) { - log_warning(_("protocol error: %s\n"), buf); - return NN_PROTOCOL; - } - - extract_parenthesis(buf, '<', '>'); - if (buf[0] == '\0') { - log_warning(_("protocol error\n")); - return NN_PROTOCOL; - } - *msgid = g_strdup(buf); - - return NN_SUCCESS; -} - -gint nntp_xover(NNTPSession *session, gint first, gint last) -{ - gint ok; - gchar buf[NNTPBUFSIZE]; - - ok = nntp_gen_command(session, buf, "XOVER %d-%d", first, last); - if (ok != NN_SUCCESS) - return ok; - - return NN_SUCCESS; -} - -gint nntp_xhdr(NNTPSession *session, const gchar *header, gint first, gint last) -{ - gint ok; - gchar buf[NNTPBUFSIZE]; - - ok = nntp_gen_command(session, buf, "XHDR %s %d-%d", - header, first, last); - if (ok != NN_SUCCESS) - return ok; - - return NN_SUCCESS; -} - -gint nntp_list(NNTPSession *session) -{ - return nntp_gen_command(session, NULL, "LIST"); -} - -gint nntp_post(NNTPSession *session, FILE *fp) -{ - gint ok; - gchar buf[NNTPBUFSIZE]; - gchar *msg; - - ok = nntp_gen_command(session, buf, "POST"); - if (ok != NN_SUCCESS) - return ok; - - msg = get_outgoing_rfc2822_str(fp); - if (sock_write_all(SESSION(session)->sock, msg, strlen(msg)) < 0) { - log_warning(_("Error occurred while posting\n")); - g_free(msg); - return NN_SOCKET; - } - g_free(msg); - - sock_write_all(SESSION(session)->sock, ".\r\n", 3); - if ((ok = nntp_ok(SESSION(session)->sock, buf)) != NN_SUCCESS) - return ok; - - session_set_access_time(SESSION(session)); - - return NN_SUCCESS; -} - -gint nntp_newgroups(NNTPSession *session) -{ - return NN_SUCCESS; -} - -gint nntp_newnews(NNTPSession *session) -{ - return NN_SUCCESS; -} - -gint nntp_mode(NNTPSession *session, gboolean stream) -{ - gint ok; - - ok = nntp_gen_command(session, NULL, "MODE %s", - stream ? "STREAM" : "READER"); - - return ok; -} - -static gint nntp_ok(SockInfo *sock, gchar *argbuf) -{ - gint ok; - gchar buf[NNTPBUFSIZE]; - - if ((ok = nntp_gen_recv(sock, buf, sizeof(buf))) == NN_SUCCESS) { - if (strlen(buf) < 3) - return NN_ERROR; - - if ((buf[0] == '1' || buf[0] == '2' || buf[0] == '3') && - (buf[3] == ' ' || buf[3] == '\0')) { - if (argbuf) - strcpy(argbuf, buf); - - if (!strncmp(buf, "381", 3)) - return NN_AUTHCONT; - - return NN_SUCCESS; - } else if (!strncmp(buf, "480", 3)) - return NN_AUTHREQ; - else - return NN_ERROR; - } - - return ok; -} - -static gint nntp_gen_send(SockInfo *sock, const gchar *format, ...) -{ - gchar buf[NNTPBUFSIZE]; - va_list args; - - va_start(args, format); - g_vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - - if (verbose) { - if (!g_ascii_strncasecmp(buf, "AUTHINFO PASS", 13)) - log_print("NNTP> AUTHINFO PASS ********\n"); - else - log_print("NNTP> %s\n", buf); - } - - strcat(buf, "\r\n"); - if (sock_write_all(sock, buf, strlen(buf)) < 0) { - log_warning(_("Error occurred while sending command\n")); - return NN_SOCKET; - } - - return NN_SUCCESS; -} - -static gint nntp_gen_recv(SockInfo *sock, gchar *buf, gint size) -{ - if (sock_gets(sock, buf, size) == -1) - return NN_SOCKET; - - strretchomp(buf); - - if (verbose) - log_print("NNTP< %s\n", buf); - - return NN_SUCCESS; -} - -static gint nntp_gen_command(NNTPSession *session, gchar *argbuf, - const gchar *format, ...) -{ - gchar buf[NNTPBUFSIZE]; - va_list args; - gint ok; - SockInfo *sock; - - va_start(args, format); - g_vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - - sock = SESSION(session)->sock; - ok = nntp_gen_send(sock, "%s", buf); - if (ok != NN_SUCCESS) - return ok; - ok = nntp_ok(sock, argbuf); - if (ok == NN_AUTHREQ) { - if (!session->userid || !session->passwd) { - session->auth_failed = TRUE; - return ok; - } - - ok = nntp_gen_send(sock, "AUTHINFO USER %s", session->userid); - if (ok != NN_SUCCESS) - return ok; - ok = nntp_ok(sock, NULL); - if (ok == NN_AUTHCONT) { - ok = nntp_gen_send(sock, "AUTHINFO PASS %s", - session->passwd); - if (ok != NN_SUCCESS) - return ok; - ok = nntp_ok(sock, NULL); - } - if (ok != NN_SUCCESS) { - session->auth_failed = TRUE; - return ok; - } - - ok = nntp_gen_send(sock, "%s", buf); - if (ok != NN_SUCCESS) - return ok; - ok = nntp_ok(sock, argbuf); - } - - session_set_access_time(SESSION(session)); - - return ok; -} diff --git a/src/nntp.h b/src/nntp.h deleted file mode 100644 index 46992e42..00000000 --- a/src/nntp.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2003 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. - */ - -#ifndef __NNTP_H__ -#define __NNTP_H__ - -#include "session.h" -#if USE_SSL -# include "ssl.h" -#endif - -typedef struct _NNTPSession NNTPSession; - -#define NNTP_SESSION(obj) ((NNTPSession *)obj) - -struct _NNTPSession -{ - Session session; - - gchar *group; - - gchar *userid; - gchar *passwd; - gboolean auth_failed; -}; - -#define NN_SUCCESS 0 -#define NN_SOCKET 2 -#define NN_AUTHFAIL 3 -#define NN_PROTOCOL 4 -#define NN_SYNTAX 5 -#define NN_IOERR 6 -#define NN_ERROR 7 -#define NN_AUTHREQ 8 -#define NN_AUTHCONT 9 - -#define NNTPBUFSIZE 8192 - -#if USE_SSL -Session *nntp_session_new (const gchar *server, - gushort port, - gchar *buf, - const gchar *userid, - const gchar *passwd, - SSLType ssl_type); -#else -Session *nntp_session_new (const gchar *server, - gushort port, - gchar *buf, - const gchar *userid, - const gchar *passwd); -#endif - -gint nntp_group (NNTPSession *session, - const gchar *group, - gint *num, - gint *first, - gint *last); -gint nntp_get_article (NNTPSession *session, - const gchar *cmd, - gint num, - gchar **msgid); -gint nntp_article (NNTPSession *session, - gint num, - gchar **msgid); -gint nntp_body (NNTPSession *session, - gint num, - gchar **msgid); -gint nntp_head (NNTPSession *session, - gint num, - gchar **msgid); -gint nntp_stat (NNTPSession *session, - gint num, - gchar **msgid); -gint nntp_next (NNTPSession *session, - gint *num, - gchar **msgid); -gint nntp_xover (NNTPSession *session, - gint first, - gint last); -gint nntp_xhdr (NNTPSession *session, - const gchar *header, - gint first, - gint last); -gint nntp_list (NNTPSession *session); -gint nntp_post (NNTPSession *session, - FILE *fp); -gint nntp_newgroups (NNTPSession *session); -gint nntp_newnews (NNTPSession *session); -gint nntp_mode (NNTPSession *sessio, - gboolean stream); - -#endif /* __NNTP_H__ */ diff --git a/src/pop.c b/src/pop.c deleted file mode 100644 index 3a562054..00000000 --- a/src/pop.c +++ /dev/null @@ -1,857 +0,0 @@ -/* - * 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 <glib/gi18n.h> -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <ctype.h> -#include <unistd.h> -#include <time.h> -#include <errno.h> - -#include "pop.h" -#include "md5.h" -#include "prefs_account.h" -#include "utils.h" -#include "recv.h" - -static gint pop3_greeting_recv (Pop3Session *session, - const gchar *msg); -static gint pop3_getauth_user_send (Pop3Session *session); -static gint pop3_getauth_pass_send (Pop3Session *session); -static gint pop3_getauth_apop_send (Pop3Session *session); -#if USE_SSL -static gint pop3_stls_send (Pop3Session *session); -static gint pop3_stls_recv (Pop3Session *session); -#endif -static gint pop3_getrange_stat_send (Pop3Session *session); -static gint pop3_getrange_stat_recv (Pop3Session *session, - const gchar *msg); -static gint pop3_getrange_last_send (Pop3Session *session); -static gint pop3_getrange_last_recv (Pop3Session *session, - const gchar *msg); -static gint pop3_getrange_uidl_send (Pop3Session *session); -static gint pop3_getrange_uidl_recv (Pop3Session *session, - const gchar *data, - guint len); -static gint pop3_getsize_list_send (Pop3Session *session); -static gint pop3_getsize_list_recv (Pop3Session *session, - const gchar *data, - guint len); -static gint pop3_retr_send (Pop3Session *session); -static gint pop3_retr_recv (Pop3Session *session, - const gchar *data, - guint len); -static gint pop3_delete_send (Pop3Session *session); -static gint pop3_delete_recv (Pop3Session *session); -static gint pop3_logout_send (Pop3Session *session); - -static void pop3_gen_send (Pop3Session *session, - const gchar *format, ...); - -static void pop3_session_destroy (Session *session); - -static gint pop3_write_msg_to_file (const gchar *file, - const gchar *data, - guint len); - -static Pop3State pop3_lookup_next (Pop3Session *session); -static Pop3ErrorValue pop3_ok (Pop3Session *session, - const gchar *msg); - -static gint pop3_session_recv_msg (Session *session, - const gchar *msg); -static gint pop3_session_recv_data_finished (Session *session, - guchar *data, - guint len); - - -static gint pop3_greeting_recv(Pop3Session *session, const gchar *msg) -{ - session->state = POP3_GREETING; - - session->greeting = g_strdup(msg); - return PS_SUCCESS; -} - -#if USE_SSL -static gint pop3_stls_send(Pop3Session *session) -{ - session->state = POP3_STLS; - pop3_gen_send(session, "STLS"); - return PS_SUCCESS; -} - -static gint pop3_stls_recv(Pop3Session *session) -{ - if (session_start_tls(SESSION(session)) < 0) { - session->error_val = PS_SOCKET; - return -1; - } - return PS_SUCCESS; -} -#endif /* USE_SSL */ - -static gint pop3_getauth_user_send(Pop3Session *session) -{ - g_return_val_if_fail(session->user != NULL, -1); - - session->state = POP3_GETAUTH_USER; - pop3_gen_send(session, "USER %s", session->user); - return PS_SUCCESS; -} - -static gint pop3_getauth_pass_send(Pop3Session *session) -{ - g_return_val_if_fail(session->pass != NULL, -1); - - session->state = POP3_GETAUTH_PASS; - pop3_gen_send(session, "PASS %s", session->pass); - return PS_SUCCESS; -} - -static gint pop3_getauth_apop_send(Pop3Session *session) -{ - gchar *start, *end; - gchar *apop_str; - gchar md5sum[33]; - - g_return_val_if_fail(session->user != NULL, -1); - g_return_val_if_fail(session->pass != NULL, -1); - - session->state = POP3_GETAUTH_APOP; - - if ((start = strchr(session->greeting, '<')) == NULL) { - log_warning(_("Required APOP timestamp not found " - "in greeting\n")); - session->error_val = PS_PROTOCOL; - return -1; - } - - if ((end = strchr(start, '>')) == NULL || end == start + 1) { - log_warning(_("Timestamp syntax error in greeting\n")); - session->error_val = PS_PROTOCOL; - return -1; - } - - *(end + 1) = '\0'; - - apop_str = g_strconcat(start, session->pass, NULL); - md5_hex_digest(md5sum, apop_str); - g_free(apop_str); - - pop3_gen_send(session, "APOP %s %s", session->user, md5sum); - - return PS_SUCCESS; -} - -static gint pop3_getrange_stat_send(Pop3Session *session) -{ - session->state = POP3_GETRANGE_STAT; - pop3_gen_send(session, "STAT"); - return PS_SUCCESS; -} - -static gint pop3_getrange_stat_recv(Pop3Session *session, const gchar *msg) -{ - if (sscanf(msg, "%d %d", &session->count, &session->total_bytes) != 2) { - log_warning(_("POP3 protocol error\n")); - session->error_val = PS_PROTOCOL; - return -1; - } else { - if (session->count == 0) { - session->uidl_is_valid = TRUE; - } else { - session->msg = g_new0(Pop3MsgInfo, session->count + 1); - session->cur_msg = 1; - } - } - - return PS_SUCCESS; -} - -static gint pop3_getrange_last_send(Pop3Session *session) -{ - session->state = POP3_GETRANGE_LAST; - pop3_gen_send(session, "LAST"); - return PS_SUCCESS; -} - -static gint pop3_getrange_last_recv(Pop3Session *session, const gchar *msg) -{ - gint last; - - if (sscanf(msg, "%d", &last) == 0) { - log_warning(_("POP3 protocol error\n")); - session->error_val = PS_PROTOCOL; - return -1; - } else { - if (session->count > last) { - session->new_msg_exist = TRUE; - session->cur_msg = last + 1; - } else - session->cur_msg = 0; - } - - return PS_SUCCESS; -} - -static gint pop3_getrange_uidl_send(Pop3Session *session) -{ - session->state = POP3_GETRANGE_UIDL; - pop3_gen_send(session, "UIDL"); - return PS_SUCCESS; -} - -static gint pop3_getrange_uidl_recv(Pop3Session *session, const gchar *data, - guint len) -{ - gchar id[IDLEN + 1]; - gchar buf[POPBUFSIZE]; - gint buf_len; - gint num; - time_t recv_time; - const gchar *p = data; - const gchar *lastp = data + len; - const gchar *newline; - - while (p < lastp) { - if ((newline = memchr(p, '\r', lastp - p)) == NULL) - return -1; - buf_len = MIN(newline - p, sizeof(buf) - 1); - memcpy(buf, p, buf_len); - buf[buf_len] = '\0'; - - p = newline + 1; - if (p < lastp && *p == '\n') p++; - - if (sscanf(buf, "%d %" Xstr(IDLEN) "s", &num, id) != 2 || - num <= 0 || num > session->count) { - log_warning(_("invalid UIDL response: %s\n"), buf); - continue; - } - - session->msg[num].uidl = g_strdup(id); - - recv_time = (time_t)g_hash_table_lookup(session->uidl_table, id); - session->msg[num].recv_time = recv_time; - - if (!session->ac_prefs->getall && recv_time != RECV_TIME_NONE) - session->msg[num].received = TRUE; - - if (!session->new_msg_exist && - (session->ac_prefs->getall || recv_time == RECV_TIME_NONE || - session->ac_prefs->rmmail)) { - session->cur_msg = num; - session->new_msg_exist = TRUE; - } - } - - session->uidl_is_valid = TRUE; - return PS_SUCCESS; -} - -static gint pop3_getsize_list_send(Pop3Session *session) -{ - session->state = POP3_GETSIZE_LIST; - pop3_gen_send(session, "LIST"); - return PS_SUCCESS; -} - -static gint pop3_getsize_list_recv(Pop3Session *session, const gchar *data, - guint len) -{ - gchar buf[POPBUFSIZE]; - gint buf_len; - guint num, size; - const gchar *p = data; - const gchar *lastp = data + len; - const gchar *newline; - - while (p < lastp) { - if ((newline = memchr(p, '\r', lastp - p)) == NULL) - return -1; - buf_len = MIN(newline - p, sizeof(buf) - 1); - memcpy(buf, p, buf_len); - buf[buf_len] = '\0'; - - p = newline + 1; - if (p < lastp && *p == '\n') p++; - - if (sscanf(buf, "%u %u", &num, &size) != 2) { - session->error_val = PS_PROTOCOL; - return -1; - } - - if (num > 0 && num <= session->count) - session->msg[num].size = size; - if (num > 0 && num < session->cur_msg) - session->cur_total_bytes += size; - } - - return PS_SUCCESS; -} - -static gint pop3_retr_send(Pop3Session *session) -{ - session->state = POP3_RETR; - pop3_gen_send(session, "RETR %d", session->cur_msg); - return PS_SUCCESS; -} - -static gint pop3_retr_recv(Pop3Session *session, const gchar *data, guint len) -{ - gchar *file; - gint drop_ok; - - file = get_tmp_file(); - if (pop3_write_msg_to_file(file, data, len) < 0) { - g_free(file); - session->error_val = PS_IOERR; - return -1; - } - - drop_ok = session->drop_message(session, file); - g_unlink(file); - g_free(file); - if (drop_ok < 0) { - session->error_val = PS_IOERR; - return -1; - } - - session->cur_total_bytes += session->msg[session->cur_msg].size; - session->cur_total_recv_bytes += session->msg[session->cur_msg].size; - session->cur_total_num++; - - session->msg[session->cur_msg].received = TRUE; - session->msg[session->cur_msg].recv_time = - drop_ok == DROP_DONT_RECEIVE ? RECV_TIME_KEEP - : drop_ok == DROP_DELETE ? RECV_TIME_DELETE - : session->current_time; - - return PS_SUCCESS; -} - -static gint pop3_delete_send(Pop3Session *session) -{ - session->state = POP3_DELETE; - pop3_gen_send(session, "DELE %d", session->cur_msg); - return PS_SUCCESS; -} - -static gint pop3_delete_recv(Pop3Session *session) -{ - session->msg[session->cur_msg].deleted = TRUE; - return PS_SUCCESS; -} - -static gint pop3_logout_send(Pop3Session *session) -{ - session->state = POP3_LOGOUT; - pop3_gen_send(session, "QUIT"); - return PS_SUCCESS; -} - -static void pop3_gen_send(Pop3Session *session, const gchar *format, ...) -{ - gchar buf[POPBUFSIZE + 1]; - va_list args; - - va_start(args, format); - g_vsnprintf(buf, sizeof(buf) - 2, format, args); - va_end(args); - - if (!g_ascii_strncasecmp(buf, "PASS ", 5)) - log_print("POP3> PASS ********\n"); - else - log_print("POP3> %s\n", buf); - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); -} - -Session *pop3_session_new(PrefsAccount *account) -{ - Pop3Session *session; - - g_return_val_if_fail(account != NULL, NULL); - - session = g_new0(Pop3Session, 1); - - session_init(SESSION(session)); - - SESSION(session)->type = SESSION_POP3; - - SESSION(session)->recv_msg = pop3_session_recv_msg; - SESSION(session)->recv_data_finished = pop3_session_recv_data_finished; - SESSION(session)->send_data_finished = NULL; - - SESSION(session)->destroy = pop3_session_destroy; - - session->state = POP3_READY; - session->ac_prefs = account; - session->uidl_table = pop3_get_uidl_table(account); - session->current_time = time(NULL); - session->error_val = PS_SUCCESS; - session->error_msg = NULL; - - return SESSION(session); -} - -static void pop3_session_destroy(Session *session) -{ - Pop3Session *pop3_session = POP3_SESSION(session); - gint n; - - g_return_if_fail(session != NULL); - - for (n = 1; n <= pop3_session->count; n++) - g_free(pop3_session->msg[n].uidl); - g_free(pop3_session->msg); - - if (pop3_session->uidl_table) { - hash_free_strings(pop3_session->uidl_table); - g_hash_table_destroy(pop3_session->uidl_table); - } - - g_free(pop3_session->greeting); - g_free(pop3_session->user); - g_free(pop3_session->pass); - g_free(pop3_session->error_msg); -} - -GHashTable *pop3_get_uidl_table(PrefsAccount *ac_prefs) -{ - GHashTable *table; - gchar *path; - FILE *fp; - gchar buf[POPBUFSIZE]; - gchar uidl[POPBUFSIZE]; - time_t recv_time; - time_t now; - - table = g_hash_table_new(g_str_hash, g_str_equal); - - path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, - UIDL_DIR, G_DIR_SEPARATOR_S, ac_prefs->recv_server, - "-", ac_prefs->userid, NULL); - if ((fp = g_fopen(path, "rb")) == NULL) { - if (ENOENT != errno) FILE_OP_ERROR(path, "fopen"); - g_free(path); - return table; - } - g_free(path); - - now = time(NULL); - - while (fgets(buf, sizeof(buf), fp) != NULL) { - strretchomp(buf); - recv_time = RECV_TIME_NONE; - if (sscanf(buf, "%s\t%ld", uidl, &recv_time) != 2) { - if (sscanf(buf, "%s", uidl) != 1) - continue; - else - recv_time = now; - } - if (recv_time == RECV_TIME_NONE) - recv_time = RECV_TIME_RECEIVED; - g_hash_table_insert(table, g_strdup(uidl), - GINT_TO_POINTER(recv_time)); - } - - fclose(fp); - return table; -} - -gint pop3_write_uidl_list(Pop3Session *session) -{ - gchar *path; - FILE *fp; - Pop3MsgInfo *msg; - gint n; - - if (!session->uidl_is_valid) return 0; - - path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, - "uidl", G_DIR_SEPARATOR_S, - session->ac_prefs->recv_server, - "-", session->ac_prefs->userid, NULL); - if ((fp = g_fopen(path, "wb")) == NULL) { - FILE_OP_ERROR(path, "fopen"); - g_free(path); - return -1; - } - - for (n = 1; n <= session->count; n++) { - msg = &session->msg[n]; - if (msg->uidl && msg->received && !msg->deleted) - fprintf(fp, "%s\t%ld\n", msg->uidl, msg->recv_time); - } - - if (fclose(fp) == EOF) FILE_OP_ERROR(path, "fclose"); - g_free(path); - - return 0; -} - -static gint pop3_write_msg_to_file(const gchar *file, const gchar *data, - guint len) -{ - FILE *fp; - const gchar *prev, *cur; - - g_return_val_if_fail(file != NULL, -1); - - if ((fp = g_fopen(file, "wb")) == NULL) { - FILE_OP_ERROR(file, "fopen"); - return -1; - } - - if (change_file_mode_rw(fp, file) < 0) - FILE_OP_ERROR(file, "chmod"); - - /* +------------------+----------------+--------------------------+ * - * ^data ^prev ^cur data+len-1^ */ - - prev = data; - while ((cur = (gchar *)my_memmem(prev, len - (prev - data), "\r\n", 2)) - != NULL) { - if ((cur > prev && fwrite(prev, cur - prev, 1, fp) < 1) || - fputc('\n', fp) == EOF) { - FILE_OP_ERROR(file, "fwrite"); - g_warning("can't write to file: %s\n", file); - fclose(fp); - g_unlink(file); - return -1; - } - - if (cur == data + len - 1) { - prev = cur + 1; - break; - } - - if (*(cur + 1) == '\n') - prev = cur + 2; - else - prev = cur + 1; - - if (prev - data < len - 1 && *prev == '.' && *(prev + 1) == '.') - prev++; - - if (prev - data >= len) - break; - } - - if (prev - data < len && - fwrite(prev, len - (prev - data), 1, fp) < 1) { - FILE_OP_ERROR(file, "fwrite"); - g_warning("can't write to file: %s\n", file); - fclose(fp); - g_unlink(file); - return -1; - } - if (data[len - 1] != '\r' && data[len - 1] != '\n') { - if (fputc('\n', fp) == EOF) { - FILE_OP_ERROR(file, "fputc"); - g_warning("can't write to file: %s\n", file); - fclose(fp); - g_unlink(file); - return -1; - } - } - - if (fclose(fp) == EOF) { - FILE_OP_ERROR(file, "fclose"); - g_unlink(file); - return -1; - } - - return 0; -} - -static Pop3State pop3_lookup_next(Pop3Session *session) -{ - Pop3MsgInfo *msg; - PrefsAccount *ac = session->ac_prefs; - gint size; - gboolean size_limit_over; - - for (;;) { - msg = &session->msg[session->cur_msg]; - size = msg->size; - size_limit_over = - (ac->enable_size_limit && - ac->size_limit > 0 && - size > ac->size_limit * 1024); - - if (msg->recv_time == RECV_TIME_DELETE || - (ac->rmmail && - msg->recv_time != RECV_TIME_NONE && - msg->recv_time != RECV_TIME_KEEP && - session->current_time - msg->recv_time >= - ac->msg_leave_time * 24 * 60 * 60)) { - log_print(_("POP3: Deleting expired message %d\n"), - session->cur_msg); - pop3_delete_send(session); - return POP3_DELETE; - } - - if (size_limit_over) - log_print - (_("POP3: Skipping message %d (%d bytes)\n"), - session->cur_msg, size); - - if (size == 0 || msg->received || size_limit_over) { - session->cur_total_bytes += size; - if (session->cur_msg == session->count) { - pop3_logout_send(session); - return POP3_LOGOUT; - } else - session->cur_msg++; - } else - break; - } - - pop3_retr_send(session); - return POP3_RETR; -} - -static Pop3ErrorValue pop3_ok(Pop3Session *session, const gchar *msg) -{ - Pop3ErrorValue ok; - - log_print("POP3< %s\n", msg); - - if (!strncmp(msg, "+OK", 3)) - ok = PS_SUCCESS; - else if (!strncmp(msg, "-ERR", 4)) { - if (strstr(msg + 4, "lock") || - strstr(msg + 4, "Lock") || - strstr(msg + 4, "LOCK") || - strstr(msg + 4, "wait")) { - log_warning(_("mailbox is locked\n")); - ok = PS_LOCKBUSY; - } else if (strcasestr(msg + 4, "timeout")) { - log_warning(_("session timeout\n")); - ok = PS_ERROR; - } else { - switch (session->state) { -#if USE_SSL - case POP3_STLS: - log_warning(_("can't start TLS session\n")); - ok = PS_ERROR; - break; -#endif - case POP3_GETAUTH_USER: - case POP3_GETAUTH_PASS: - case POP3_GETAUTH_APOP: - log_warning(_("error occurred on authentication\n")); - ok = PS_AUTHFAIL; - break; - case POP3_GETRANGE_LAST: - case POP3_GETRANGE_UIDL: - log_warning(_("command not supported\n")); - ok = PS_NOTSUPPORTED; - break; - default: - log_warning(_("error occurred on POP3 session\n")); - ok = PS_ERROR; - } - } - - g_free(session->error_msg); - session->error_msg = g_strdup(msg); - fprintf(stderr, "POP3: %s\n", msg); - } else - ok = PS_PROTOCOL; - - session->error_val = ok; - return ok; -} - -static gint pop3_session_recv_msg(Session *session, const gchar *msg) -{ - Pop3Session *pop3_session = POP3_SESSION(session); - Pop3ErrorValue val = PS_SUCCESS; - const gchar *body; - - body = msg; - if (pop3_session->state != POP3_GETRANGE_UIDL_RECV && - pop3_session->state != POP3_GETSIZE_LIST_RECV) { - val = pop3_ok(pop3_session, msg); - if (val != PS_SUCCESS) { - if (val != PS_NOTSUPPORTED) { - pop3_session->state = POP3_ERROR; - return -1; - } - } - - if (*body == '+' || *body == '-') - body++; - while (g_ascii_isalpha(*body)) - body++; - while (g_ascii_isspace(*body)) - body++; - } - - switch (pop3_session->state) { - case POP3_READY: - case POP3_GREETING: - pop3_greeting_recv(pop3_session, body); -#if USE_SSL - if (pop3_session->ac_prefs->ssl_pop == SSL_STARTTLS) - pop3_stls_send(pop3_session); - else -#endif - if (pop3_session->ac_prefs->use_apop_auth) - pop3_getauth_apop_send(pop3_session); - else - pop3_getauth_user_send(pop3_session); - break; -#if USE_SSL - case POP3_STLS: - if (pop3_stls_recv(pop3_session) != PS_SUCCESS) - return -1; - if (pop3_session->ac_prefs->use_apop_auth) - pop3_getauth_apop_send(pop3_session); - else - pop3_getauth_user_send(pop3_session); - break; -#endif - case POP3_GETAUTH_USER: - pop3_getauth_pass_send(pop3_session); - break; - case POP3_GETAUTH_PASS: - case POP3_GETAUTH_APOP: - pop3_getrange_stat_send(pop3_session); - break; - case POP3_GETRANGE_STAT: - if (pop3_getrange_stat_recv(pop3_session, body) < 0) - return -1; - if (pop3_session->count > 0) - pop3_getrange_uidl_send(pop3_session); - else - pop3_logout_send(pop3_session); - break; - case POP3_GETRANGE_LAST: - if (val == PS_NOTSUPPORTED) - pop3_session->error_val = PS_SUCCESS; - else if (pop3_getrange_last_recv(pop3_session, body) < 0) - return -1; - if (pop3_session->cur_msg > 0) - pop3_getsize_list_send(pop3_session); - else - pop3_logout_send(pop3_session); - break; - case POP3_GETRANGE_UIDL: - if (val == PS_NOTSUPPORTED) { - pop3_session->error_val = PS_SUCCESS; - pop3_getrange_last_send(pop3_session); - } else { - pop3_session->state = POP3_GETRANGE_UIDL_RECV; - session_recv_data(session, 0, ".\r\n"); - } - break; - case POP3_GETSIZE_LIST: - pop3_session->state = POP3_GETSIZE_LIST_RECV; - session_recv_data(session, 0, ".\r\n"); - break; - case POP3_RETR: - pop3_session->state = POP3_RETR_RECV; - session_recv_data(session, 0, ".\r\n"); - break; - case POP3_DELETE: - pop3_delete_recv(pop3_session); - if (pop3_session->cur_msg == pop3_session->count) - pop3_logout_send(pop3_session); - else { - pop3_session->cur_msg++; - if (pop3_lookup_next(pop3_session) == POP3_ERROR) - return -1; - } - break; - case POP3_LOGOUT: - session_disconnect(session); - break; - case POP3_ERROR: - default: - return -1; - } - - return 0; -} - -static gint pop3_session_recv_data_finished(Session *session, guchar *data, - guint len) -{ - Pop3Session *pop3_session = POP3_SESSION(session); - Pop3ErrorValue val = PS_SUCCESS; - - switch (pop3_session->state) { - case POP3_GETRANGE_UIDL_RECV: - val = pop3_getrange_uidl_recv(pop3_session, data, len); - if (val == PS_SUCCESS) { - if (pop3_session->new_msg_exist) - pop3_getsize_list_send(pop3_session); - else - pop3_logout_send(pop3_session); - } else - return -1; - break; - case POP3_GETSIZE_LIST_RECV: - val = pop3_getsize_list_recv(pop3_session, data, len); - if (val == PS_SUCCESS) { - if (pop3_lookup_next(pop3_session) == POP3_ERROR) - return -1; - } else - return -1; - break; - case POP3_RETR_RECV: - if (pop3_retr_recv(pop3_session, data, len) < 0) - return -1; - - if (pop3_session->msg[pop3_session->cur_msg].recv_time - == RECV_TIME_DELETE || - (pop3_session->ac_prefs->rmmail && - pop3_session->ac_prefs->msg_leave_time == 0 && - pop3_session->msg[pop3_session->cur_msg].recv_time - != RECV_TIME_KEEP)) - pop3_delete_send(pop3_session); - else if (pop3_session->cur_msg == pop3_session->count) - pop3_logout_send(pop3_session); - else { - pop3_session->cur_msg++; - if (pop3_lookup_next(pop3_session) == POP3_ERROR) - return -1; - } - break; - case POP3_ERROR: - default: - return -1; - } - - return 0; -} diff --git a/src/pop.h b/src/pop.h deleted file mode 100644 index 515bc61b..00000000 --- a/src/pop.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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. - */ - -#ifndef __POP_H__ -#define __POP_H__ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <glib.h> -#include <time.h> - -#include "session.h" -#include "prefs_account.h" - -typedef struct _Pop3MsgInfo Pop3MsgInfo; -typedef struct _Pop3Session Pop3Session; - -#define POP3_SESSION(obj) ((Pop3Session *)obj) - -typedef enum { - POP3_READY, - POP3_GREETING, -#if USE_SSL - POP3_STLS, -#endif - POP3_GETAUTH_USER, - POP3_GETAUTH_PASS, - POP3_GETAUTH_APOP, - POP3_GETRANGE_STAT, - POP3_GETRANGE_LAST, - POP3_GETRANGE_UIDL, - POP3_GETRANGE_UIDL_RECV, - POP3_GETSIZE_LIST, - POP3_GETSIZE_LIST_RECV, - POP3_RETR, - POP3_RETR_RECV, - POP3_DELETE, - POP3_LOGOUT, - POP3_ERROR, - - N_POP3_STATE -} Pop3State; - -typedef enum { - PS_SUCCESS = 0, /* command successful */ - PS_NOMAIL = 1, /* no mail available */ - PS_SOCKET = 2, /* socket I/O woes */ - PS_AUTHFAIL = 3, /* user authorization failed */ - PS_PROTOCOL = 4, /* protocol violation */ - PS_SYNTAX = 5, /* command-line syntax error */ - PS_IOERR = 6, /* file I/O error */ - PS_ERROR = 7, /* protocol error */ - PS_EXCLUDE = 8, /* client-side exclusion error */ - PS_LOCKBUSY = 9, /* server responded lock busy */ - PS_SMTP = 10, /* SMTP error */ - PS_DNS = 11, /* fatal DNS error */ - PS_BSMTP = 12, /* output batch could not be opened */ - PS_MAXFETCH = 13, /* poll ended by fetch limit */ - - PS_NOTSUPPORTED = 14, /* command not supported */ - - /* leave space for more codes */ - - PS_CONTINUE = 128 /* more responses may follow */ -} Pop3ErrorValue; - -typedef enum { - RECV_TIME_NONE = 0, - RECV_TIME_RECEIVED = 1, - RECV_TIME_KEEP = 2, - RECV_TIME_DELETE = 3 -} RecvTime; - -typedef enum { - DROP_OK = 0, - DROP_DONT_RECEIVE = 1, - DROP_DELETE = 2, - DROP_ERROR = -1 -} Pop3DropValue; - -struct _Pop3MsgInfo -{ - gint size; - gchar *uidl; - time_t recv_time; - guint received : 1; - guint deleted : 1; -}; - -struct _Pop3Session -{ - Session session; - - Pop3State state; - - PrefsAccount *ac_prefs; - - gchar *greeting; - gchar *user; - gchar *pass; - gint count; - gint total_bytes; - gint cur_msg; - gint cur_total_num; - gint cur_total_bytes; - gint cur_total_recv_bytes; - - Pop3MsgInfo *msg; - - GHashTable *uidl_table; - - gboolean new_msg_exist; - gboolean uidl_is_valid; - - time_t current_time; - - Pop3ErrorValue error_val; - gchar *error_msg; - - gpointer data; - - /* virtual method to drop message */ - gint (*drop_message) (Pop3Session *session, - const gchar *file); -}; - -#define POPBUFSIZE 512 -/* #define IDLEN 128 */ -#define IDLEN POPBUFSIZE - -Session *pop3_session_new (PrefsAccount *account); -GHashTable *pop3_get_uidl_table (PrefsAccount *account); -gint pop3_write_uidl_list (Pop3Session *session); - -#endif /* __POP_H__ */ diff --git a/src/prefs_account.c b/src/prefs_account.c deleted file mode 100644 index b6d15fba..00000000 --- a/src/prefs_account.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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 <glib/gi18n.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#include "prefs.h" -#include "prefs_account.h" -#include "customheader.h" -#include "account.h" -#include "utils.h" - -static PrefsAccount tmp_ac_prefs; - -static PrefParam param[] = { - /* Basic */ - {"account_name", NULL, &tmp_ac_prefs.account_name, P_STRING}, - {"is_default", "FALSE", &tmp_ac_prefs.is_default, P_BOOL}, - {"name", NULL, &tmp_ac_prefs.name, P_STRING}, - {"address", NULL, &tmp_ac_prefs.address, P_STRING}, - {"organization", NULL, &tmp_ac_prefs.organization, P_STRING}, - {"protocol", NULL, &tmp_ac_prefs.protocol, P_ENUM}, - {"receive_server", NULL, &tmp_ac_prefs.recv_server, P_STRING}, - {"smtp_server", NULL, &tmp_ac_prefs.smtp_server, P_STRING}, - {"nntp_server", NULL, &tmp_ac_prefs.nntp_server, P_STRING}, - {"use_nntp_auth", "FALSE", &tmp_ac_prefs.use_nntp_auth, P_BOOL}, - {"user_id", "ENV_USER", &tmp_ac_prefs.userid, P_STRING}, - {"password", NULL, &tmp_ac_prefs.passwd, P_STRING}, - {"inbox", "inbox", &tmp_ac_prefs.inbox, P_STRING}, - - /* Receive */ - {"use_apop_auth", "FALSE", &tmp_ac_prefs.use_apop_auth, P_BOOL}, - {"remove_mail", "TRUE", &tmp_ac_prefs.rmmail, P_BOOL}, - {"message_leave_time", "0", &tmp_ac_prefs.msg_leave_time, P_INT}, - {"get_all_mail", "FALSE", &tmp_ac_prefs.getall, P_BOOL}, - {"enable_size_limit", "FALSE", &tmp_ac_prefs.enable_size_limit, P_BOOL}, - {"size_limit", "1024", &tmp_ac_prefs.size_limit, P_INT}, - {"filter_on_receive", "TRUE", &tmp_ac_prefs.filter_on_recv, P_BOOL}, - {"imap_auth_method", "0", &tmp_ac_prefs.imap_auth_type, P_ENUM}, - {"max_nntp_articles", "300", &tmp_ac_prefs.max_nntp_articles, P_INT}, - {"receive_at_get_all", "TRUE", &tmp_ac_prefs.recv_at_getall, P_BOOL}, - - /* Send */ - {"add_date", "TRUE", &tmp_ac_prefs.add_date, P_BOOL}, - {"generate_msgid", "TRUE", &tmp_ac_prefs.gen_msgid, P_BOOL}, - {"add_custom_header", "FALSE", &tmp_ac_prefs.add_customhdr, P_BOOL}, - {"use_smtp_auth", "FALSE", &tmp_ac_prefs.use_smtp_auth, P_BOOL}, - {"smtp_auth_method", "0", &tmp_ac_prefs.smtp_auth_type, P_ENUM}, - {"smtp_user_id", NULL, &tmp_ac_prefs.smtp_userid, P_STRING}, - {"smtp_password", NULL, &tmp_ac_prefs.smtp_passwd, P_STRING}, - {"pop_before_smtp", "FALSE", &tmp_ac_prefs.pop_before_smtp, P_BOOL}, - - /* Compose */ - {"signature_type", "0", &tmp_ac_prefs.sig_type, P_ENUM}, - {"signature_path", "~" G_DIR_SEPARATOR_S DEFAULT_SIGNATURE, - &tmp_ac_prefs.sig_path, P_STRING}, - {"set_autocc", "FALSE", &tmp_ac_prefs.set_autocc, P_BOOL}, - {"auto_cc", NULL, &tmp_ac_prefs.auto_cc, P_STRING}, - {"set_autobcc", "FALSE", &tmp_ac_prefs.set_autobcc, P_BOOL}, - {"auto_bcc", NULL, &tmp_ac_prefs.auto_bcc, P_STRING}, - {"set_autoreplyto", "FALSE", &tmp_ac_prefs.set_autoreplyto, P_BOOL}, - {"auto_replyto", NULL, &tmp_ac_prefs.auto_replyto, P_STRING}, - -#if USE_GPGME - /* Privacy */ - {"default_sign", "FALSE", &tmp_ac_prefs.default_sign, P_BOOL}, - {"default_encrypt", "FALSE", &tmp_ac_prefs.default_encrypt, P_BOOL}, - {"encrypt_reply", "TRUE", &tmp_ac_prefs.encrypt_reply, P_BOOL}, - {"ascii_armored", "FALSE", &tmp_ac_prefs.ascii_armored, P_BOOL}, - {"clearsign", "FALSE", &tmp_ac_prefs.clearsign, P_BOOL}, - {"sign_key", NULL, &tmp_ac_prefs.sign_key, P_ENUM}, - {"sign_key_id", NULL, &tmp_ac_prefs.sign_key_id, P_STRING}, -#endif /* USE_GPGME */ - -#if USE_SSL - /* SSL */ - {"ssl_pop", "0", &tmp_ac_prefs.ssl_pop, P_ENUM}, - {"ssl_imap", "0", &tmp_ac_prefs.ssl_imap, P_ENUM}, - {"ssl_nntp", "0", &tmp_ac_prefs.ssl_nntp, P_ENUM}, - {"ssl_smtp", "0", &tmp_ac_prefs.ssl_smtp, P_ENUM}, - {"use_nonblocking_ssl", "1", &tmp_ac_prefs.use_nonblocking_ssl, P_BOOL}, -#endif /* USE_SSL */ - - /* Advanced */ - {"set_smtpport", "FALSE", &tmp_ac_prefs.set_smtpport, P_BOOL}, - {"smtp_port", "25", &tmp_ac_prefs.smtpport, P_USHORT}, - {"set_popport", "FALSE", &tmp_ac_prefs.set_popport, P_BOOL}, - {"pop_port", "110", &tmp_ac_prefs.popport, P_USHORT}, - {"set_imapport", "FALSE", &tmp_ac_prefs.set_imapport, P_BOOL}, - {"imap_port", "143", &tmp_ac_prefs.imapport, P_USHORT}, - {"set_nntpport", "FALSE", &tmp_ac_prefs.set_nntpport, P_BOOL}, - {"nntp_port", "119", &tmp_ac_prefs.nntpport, P_USHORT}, - {"set_domain", "FALSE", &tmp_ac_prefs.set_domain, P_BOOL}, - {"domain", NULL, &tmp_ac_prefs.domain, P_STRING}, - {"imap_directory", NULL, &tmp_ac_prefs.imap_dir, P_STRING}, - {"set_sent_folder", "FALSE", &tmp_ac_prefs.set_sent_folder, P_BOOL}, - {"sent_folder", NULL, &tmp_ac_prefs.sent_folder, P_STRING}, - {"set_draft_folder", "FALSE", &tmp_ac_prefs.set_draft_folder, P_BOOL}, - {"draft_folder", NULL, &tmp_ac_prefs.draft_folder, P_STRING}, - {"set_trash_folder", "FALSE", &tmp_ac_prefs.set_trash_folder, P_BOOL}, - {"trash_folder", NULL, &tmp_ac_prefs.trash_folder, P_STRING}, - - {NULL, NULL, NULL, P_OTHER} -}; - -static gint prefs_account_get_new_id(void); - - -PrefsAccount *prefs_account_get_tmp_prefs(void) -{ - return &tmp_ac_prefs; -} - -void prefs_account_set_tmp_prefs(PrefsAccount *ac_prefs) -{ - tmp_ac_prefs = *ac_prefs; -} - -void prefs_account_apply_tmp_prefs(PrefsAccount *ac_prefs) -{ - *ac_prefs = tmp_ac_prefs; -} - -PrefParam *prefs_account_get_params(void) -{ - return param; -} - -PrefsAccount *prefs_account_new(void) -{ - PrefsAccount *ac_prefs; - - ac_prefs = g_new0(PrefsAccount, 1); - memset(&tmp_ac_prefs, 0, sizeof(PrefsAccount)); - prefs_set_default(param); - *ac_prefs = tmp_ac_prefs; - ac_prefs->account_id = prefs_account_get_new_id(); - - return ac_prefs; -} - -void prefs_account_read_config(PrefsAccount *ac_prefs, const gchar *label) -{ - const gchar *p = label; - gchar *rcpath; - gint id; - - g_return_if_fail(ac_prefs != NULL); - g_return_if_fail(label != NULL); - - memset(&tmp_ac_prefs, 0, sizeof(PrefsAccount)); - - rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ACCOUNT_RC, NULL); - prefs_read_config(param, label, rcpath, NULL); - g_free(rcpath); - - *ac_prefs = tmp_ac_prefs; - while (*p && !g_ascii_isdigit(*p)) p++; - id = atoi(p); - if (id < 0) g_warning("wrong account id: %d\n", id); - ac_prefs->account_id = id; - - if (ac_prefs->protocol == A_APOP) { - debug_print("converting protocol A_APOP to new prefs.\n"); - ac_prefs->protocol = A_POP3; - ac_prefs->use_apop_auth = TRUE; - } - - custom_header_read_config(ac_prefs); -} - -void prefs_account_write_config_all(GList *account_list) -{ - GList *cur; - gchar *rcpath; - PrefFile *pfile; - - rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ACCOUNT_RC, NULL); - if ((pfile = prefs_file_open(rcpath)) == NULL) { - g_free(rcpath); - return; - } - g_free(rcpath); - - for (cur = account_list; cur != NULL; cur = cur->next) { - tmp_ac_prefs = *(PrefsAccount *)cur->data; - if (fprintf(pfile->fp, "[Account: %d]\n", - tmp_ac_prefs.account_id) <= 0 || - prefs_file_write_param(pfile, param) < 0) { - g_warning(_("failed to write configuration to file\n")); - prefs_file_close_revert(pfile); - return; - } - if (cur->next) { - if (fputc('\n', pfile->fp) == EOF) { - FILE_OP_ERROR(rcpath, "fputc"); - prefs_file_close_revert(pfile); - return; - } - } - } - - if (prefs_file_close(pfile) < 0) - g_warning(_("failed to write configuration to file\n")); -} - -void prefs_account_free(PrefsAccount *ac_prefs) -{ - if (!ac_prefs) return; - - tmp_ac_prefs = *ac_prefs; - prefs_free(param); -} - -static gint prefs_account_get_new_id(void) -{ - GList *ac_list; - PrefsAccount *ac; - static gint last_id = 0; - - for (ac_list = account_get_list(); ac_list != NULL; - ac_list = ac_list->next) { - ac = (PrefsAccount *)ac_list->data; - if (last_id < ac->account_id) - last_id = ac->account_id; - } - - return last_id + 1; -} diff --git a/src/prefs_account.h b/src/prefs_account.h deleted file mode 100644 index 13ef8d94..00000000 --- a/src/prefs_account.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __PREFS_ACCOUNT_H__ -#define __PREFS_ACCOUNT_H__ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <glib.h> - -typedef struct _PrefsAccount PrefsAccount; - -#include "folder.h" -#include "smtp.h" -#include "prefs.h" - -typedef enum { - A_POP3, - A_APOP, /* deprecated */ - A_RPOP, /* deprecated */ - A_IMAP4, - A_NNTP, - A_LOCAL -} RecvProtocol; - -typedef enum { - SIG_FILE, - SIG_COMMAND, - SIG_DIRECT -} SigType; - -#if USE_GPGME -typedef enum { - SIGN_KEY_DEFAULT, - SIGN_KEY_BY_FROM, - SIGN_KEY_CUSTOM -} SignKeyType; -#endif /* USE_GPGME */ - -struct _PrefsAccount -{ - gchar *account_name; - - /* Personal info */ - gchar *name; - gchar *address; - gchar *organization; - - /* Server info */ - RecvProtocol protocol; - gchar *recv_server; - gchar *smtp_server; - gchar *nntp_server; - gboolean use_nntp_auth; - gchar *userid; - gchar *passwd; - -#if USE_SSL - /* SSL */ - SSLType ssl_pop; - SSLType ssl_imap; - SSLType ssl_nntp; - SSLType ssl_smtp; - gboolean use_nonblocking_ssl; -#endif /* USE_SSL */ - - /* Temporarily preserved password */ - gchar *tmp_pass; - - /* Receive */ - gboolean use_apop_auth; - gboolean rmmail; - gint msg_leave_time; - gboolean getall; - gboolean recv_at_getall; - gboolean enable_size_limit; - gint size_limit; - gboolean filter_on_recv; - gchar *inbox; - - gint imap_auth_type; - gint max_nntp_articles; - - /* Send */ - gboolean add_date; - gboolean gen_msgid; - gboolean add_customhdr; - gboolean use_smtp_auth; - SMTPAuthType smtp_auth_type; - gchar *smtp_userid; - gchar *smtp_passwd; - - /* Temporarily preserved password */ - gchar *tmp_smtp_pass; - - gboolean pop_before_smtp; - - GSList *customhdr_list; - - /* Compose */ - SigType sig_type; - gchar *sig_path; - gboolean set_autocc; - gchar *auto_cc; - gboolean set_autobcc; - gchar *auto_bcc; - gboolean set_autoreplyto; - gchar *auto_replyto; - -#if USE_GPGME - /* Privacy */ - gboolean default_sign; - gboolean default_encrypt; - gboolean ascii_armored; - gboolean clearsign; - gboolean encrypt_reply; - - SignKeyType sign_key; - gchar *sign_key_id; -#endif /* USE_GPGME */ - - /* Advanced */ - gboolean set_smtpport; - gushort smtpport; - gboolean set_popport; - gushort popport; - gboolean set_imapport; - gushort imapport; - gboolean set_nntpport; - gushort nntpport; - gboolean set_domain; - gchar *domain; - - gchar *imap_dir; - - gboolean set_sent_folder; - gchar *sent_folder; - gboolean set_draft_folder; - gchar *draft_folder; - gboolean set_trash_folder; - gchar *trash_folder; - - /* Default or not */ - gboolean is_default; - /* Unique account ID */ - gint account_id; - - RemoteFolder *folder; -}; - -PrefsAccount *prefs_account_new (void); - -PrefsAccount *prefs_account_get_tmp_prefs (void); -void prefs_account_set_tmp_prefs (PrefsAccount *ac_prefs); -void prefs_account_apply_tmp_prefs (PrefsAccount *ac_prefs); -PrefParam *prefs_account_get_params (void); - -void prefs_account_read_config (PrefsAccount *ac_prefs, - const gchar *label); -void prefs_account_write_config_all (GList *account_list); - -void prefs_account_free (PrefsAccount *ac_prefs); - -#endif /* __PREFS_ACCOUNT_H__ */ diff --git a/src/prefs_common.c b/src/prefs_common.c deleted file mode 100644 index eb1a1864..00000000 --- a/src/prefs_common.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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 <glib/gi18n.h> -#include <stdio.h> -#include <errno.h> - -#include "prefs.h" -#include "prefs_common.h" -#include "filter.h" -#include "codeconv.h" -#include "utils.h" - -PrefsCommon prefs_common; - -static PrefParam param[] = { - /* Receive */ - {"use_ext_inc", "FALSE", &prefs_common.use_extinc, P_BOOL}, - {"ext_inc_path", DEFAULT_INC_PATH, &prefs_common.extinc_cmd, P_STRING}, - - {"inc_local", "FALSE", &prefs_common.inc_local, P_BOOL}, - {"filter_on_inc_local", "TRUE", &prefs_common.filter_on_inc, P_BOOL}, - {"spool_path", DEFAULT_SPOOL_PATH, &prefs_common.spool_path, P_STRING}, - - {"autochk_newmail", "FALSE", &prefs_common.autochk_newmail, P_BOOL}, - {"autochk_interval", "10", &prefs_common.autochk_itv, P_INT}, - {"check_on_startup", "FALSE", &prefs_common.chk_on_startup, P_BOOL}, - {"scan_all_after_inc", "FALSE", &prefs_common.scan_all_after_inc, - P_BOOL}, - {"enable_newmsg_notify", "FALSE", &prefs_common.enable_newmsg_notify, - P_BOOL}, - {"newmsg_notify_command", NULL, &prefs_common.newmsg_notify_cmd, - P_STRING}, - - /* Send */ - {"use_ext_sendmail", "FALSE", &prefs_common.use_extsend, P_BOOL}, - {"ext_sendmail_cmd", DEFAULT_SENDMAIL_CMD, &prefs_common.extsend_cmd, - P_STRING}, - {"save_message", "TRUE", &prefs_common.savemsg, P_BOOL}, - {"filter_sent_message", "FALSE", &prefs_common.filter_sent, P_BOOL}, - - {"outgoing_charset", CS_AUTO, &prefs_common.outgoing_charset, P_STRING}, - {"encoding_method", "0", &prefs_common.encoding_method, P_ENUM}, - - {"allow_jisx0201_kana", "FALSE", &prefs_common.allow_jisx0201_kana, - P_BOOL}, - - /* Compose */ - {"auto_signature", "TRUE", &prefs_common.auto_sig, P_BOOL}, - {"signature_separator", "-- ", &prefs_common.sig_sep, P_STRING}, - - {"auto_ext_editor", "FALSE", &prefs_common.auto_exteditor, P_BOOL}, - - {"undo_level", "50", &prefs_common.undolevels, P_INT}, - - {"linewrap_length", "72", &prefs_common.linewrap_len, P_INT}, - {"linewrap_quotation", "FALSE", &prefs_common.linewrap_quote, P_BOOL}, - {"linewrap_auto", "FALSE", &prefs_common.autowrap, P_BOOL}, - {"linewrap_before_sending", "FALSE", &prefs_common.linewrap_at_send, - P_BOOL}, - - {"reply_with_quote", "TRUE", &prefs_common.reply_with_quote, P_BOOL}, - {"reply_account_autoselect", "TRUE", - &prefs_common.reply_account_autosel, P_BOOL}, - {"default_reply_list", "TRUE", &prefs_common.default_reply_list, - P_BOOL}, - - {"show_ruler", "TRUE", &prefs_common.show_ruler, P_BOOL}, - - /* Quote */ - {"reply_quote_mark", "> ", &prefs_common.quotemark, P_STRING}, - {"reply_quote_format", "On %d\\n%f wrote:\\n\\n%Q", - &prefs_common.quotefmt, P_STRING}, - - {"forward_quote_mark", "> ", &prefs_common.fw_quotemark, P_STRING}, - {"forward_quote_format", - "\\n\\nBegin forwarded message:\\n\\n" - "?d{Date: %d\\n}?f{From: %f\\n}?t{To: %t\\n}?c{Cc: %c\\n}" - "?n{Newsgroups: %n\\n}?s{Subject: %s\\n}\\n\\n%M", - &prefs_common.fw_quotefmt, P_STRING}, - - /* Display */ - {"message_font_name", DEFAULT_MESSAGE_FONT, &prefs_common.textfont, - P_STRING}, - - {"display_folder_unread_num", "TRUE", - &prefs_common.display_folder_unread, P_BOOL}, - {"newsgroup_abbrev_len", "16", &prefs_common.ng_abbrev_len, P_INT}, - - {"translate_header", "TRUE", &prefs_common.trans_hdr, P_BOOL}, - - /* Display: Summary View */ - {"enable_swap_from", "FALSE", &prefs_common.swap_from, P_BOOL}, - {"date_format", "%y/%m/%d(%a) %H:%M", &prefs_common.date_format, - P_STRING}, - {"expand_thread", "TRUE", &prefs_common.expand_thread, P_BOOL}, - - {"enable_rules_hint", "TRUE", &prefs_common.enable_rules_hint, P_BOOL}, - {"bold_unread", "TRUE", &prefs_common.bold_unread, P_BOOL}, - - {"toolbar_style", "3", &prefs_common.toolbar_style, P_ENUM}, - {"show_statusbar", "TRUE", &prefs_common.show_statusbar, P_BOOL}, - - {"folderview_vscrollbar_policy", "0", - &prefs_common.folderview_vscrollbar_policy, P_ENUM}, - - {"summary_col_show_mark", "TRUE", - &prefs_common.summary_col_visible[S_COL_MARK], P_BOOL}, - {"summary_col_show_unread", "TRUE", - &prefs_common.summary_col_visible[S_COL_UNREAD], P_BOOL}, - {"summary_col_show_mime", "TRUE", - &prefs_common.summary_col_visible[S_COL_MIME], P_BOOL}, - {"summary_col_show_subject", "TRUE", - &prefs_common.summary_col_visible[S_COL_SUBJECT], P_BOOL}, - {"summary_col_show_from", "TRUE", - &prefs_common.summary_col_visible[S_COL_FROM], P_BOOL}, - {"summary_col_show_date", "TRUE", - &prefs_common.summary_col_visible[S_COL_DATE], P_BOOL}, - {"summary_col_show_size", "TRUE", - &prefs_common.summary_col_visible[S_COL_SIZE], P_BOOL}, - {"summary_col_show_number", "FALSE", - &prefs_common.summary_col_visible[S_COL_NUMBER], P_BOOL}, - - {"summary_col_pos_mark", "0", - &prefs_common.summary_col_pos[S_COL_MARK], P_INT}, - {"summary_col_pos_unread", "1", - &prefs_common.summary_col_pos[S_COL_UNREAD], P_INT}, - {"summary_col_pos_mime", "2", - &prefs_common.summary_col_pos[S_COL_MIME], P_INT}, - {"summary_col_pos_subject", "3", - &prefs_common.summary_col_pos[S_COL_SUBJECT], P_INT}, - {"summary_col_pos_from", "4", - &prefs_common.summary_col_pos[S_COL_FROM], P_INT}, - {"summary_col_pos_date", "5", - &prefs_common.summary_col_pos[S_COL_DATE], P_INT}, - {"summary_col_pos_size", "6", - &prefs_common.summary_col_pos[S_COL_SIZE], P_INT}, - {"summary_col_pos_number", "7", - &prefs_common.summary_col_pos[S_COL_NUMBER], P_INT}, - - {"summary_col_size_mark", "10", - &prefs_common.summary_col_size[S_COL_MARK], P_INT}, - {"summary_col_size_unread", "13", - &prefs_common.summary_col_size[S_COL_UNREAD], P_INT}, - {"summary_col_size_mime", "10", - &prefs_common.summary_col_size[S_COL_MIME], P_INT}, - {"summary_col_size_subject", "200", - &prefs_common.summary_col_size[S_COL_SUBJECT], P_INT}, - {"summary_col_size_from", "120", - &prefs_common.summary_col_size[S_COL_FROM], P_INT}, - {"summary_col_size_date", "118", - &prefs_common.summary_col_size[S_COL_DATE], P_INT}, - {"summary_col_size_size", "45", - &prefs_common.summary_col_size[S_COL_SIZE], P_INT}, - {"summary_col_size_number", "40", - &prefs_common.summary_col_size[S_COL_NUMBER], P_INT}, - - /* Widget size */ - {"folderwin_x", "16", &prefs_common.folderwin_x, P_INT}, - {"folderwin_y", "16", &prefs_common.folderwin_y, P_INT}, - {"folderview_width", "179", &prefs_common.folderview_width, P_INT}, - {"folderview_height", "450", &prefs_common.folderview_height, P_INT}, - {"folderview_visible", "TRUE", &prefs_common.folderview_visible, - P_BOOL}, - - {"folder_col_folder", "150", &prefs_common.folder_col_folder, P_INT}, - {"folder_col_new", "32", &prefs_common.folder_col_new, P_INT}, - {"folder_col_unread", "32", &prefs_common.folder_col_unread, P_INT}, - {"folder_col_total", "32", &prefs_common.folder_col_total, P_INT}, - - {"summaryview_width", "600", &prefs_common.summaryview_width, P_INT}, - {"summaryview_height", "157", &prefs_common.summaryview_height, P_INT}, - - {"main_messagewin_x", "256", &prefs_common.main_msgwin_x, P_INT}, - {"main_messagewin_y", "210", &prefs_common.main_msgwin_y, P_INT}, - {"messageview_width", "600", &prefs_common.msgview_width, P_INT}, - {"messageview_height", "300", &prefs_common.msgview_height, P_INT}, - {"messageview_visible", "TRUE", &prefs_common.msgview_visible, P_BOOL}, - - {"mainview_x", "64", &prefs_common.mainview_x, P_INT}, - {"mainview_y", "64", &prefs_common.mainview_y, P_INT}, - {"mainview_width", "600", &prefs_common.mainview_width, P_INT}, - {"mainview_height", "600", &prefs_common.mainview_height, P_INT}, - {"mainwin_x", "64", &prefs_common.mainwin_x, P_INT}, - {"mainwin_y", "64", &prefs_common.mainwin_y, P_INT}, - {"mainwin_width", "800", &prefs_common.mainwin_width, P_INT}, - {"mainwin_height", "600", &prefs_common.mainwin_height, P_INT}, - {"messagewin_width", "600", &prefs_common.msgwin_width, P_INT}, - {"messagewin_height", "540", &prefs_common.msgwin_height, P_INT}, - {"sourcewin_width", "600", &prefs_common.sourcewin_width, P_INT}, - {"sourcewin_height", "500", &prefs_common.sourcewin_height, P_INT}, - {"compose_width", "600", &prefs_common.compose_width, P_INT}, - {"compose_height", "560", &prefs_common.compose_height, P_INT}, - - /* Message */ - {"enable_color", "TRUE", &prefs_common.enable_color, P_BOOL}, - - {"quote_level1_color", "179", &prefs_common.quote_level1_col, P_INT}, - {"quote_level2_color", "179", &prefs_common.quote_level2_col, P_INT}, - {"quote_level3_color", "179", &prefs_common.quote_level3_col, P_INT}, - {"uri_color", "32512", &prefs_common.uri_col, P_INT}, - {"signature_color", "0", &prefs_common.sig_col, P_USHORT}, - {"recycle_quote_colors", "FALSE", &prefs_common.recycle_quote_colors, - P_BOOL}, - - {"convert_mb_alnum", "FALSE", &prefs_common.conv_mb_alnum, P_BOOL}, - {"display_header_pane", "TRUE", &prefs_common.display_header_pane, - P_BOOL}, - {"display_header", "TRUE", &prefs_common.display_header, P_BOOL}, - {"render_html", "TRUE", &prefs_common.render_html, P_BOOL}, - {"line_space", "2", &prefs_common.line_space, P_INT}, - - {"textview_cursor_visible", "FALSE", - &prefs_common.textview_cursor_visible, P_BOOL}, - - {"enable_smooth_scroll", "FALSE", &prefs_common.enable_smooth_scroll, - P_BOOL}, - {"scroll_step", "1", &prefs_common.scroll_step, P_INT}, - {"scroll_half_page", "FALSE", &prefs_common.scroll_halfpage, P_BOOL}, - - {"resize_image", "TRUE", &prefs_common.resize_image, P_BOOL}, - {"inline_image", "TRUE", &prefs_common.inline_image, P_BOOL}, - - {"show_other_header", "FALSE", &prefs_common.show_other_header, P_BOOL}, - - /* MIME viewer */ - {"mime_image_viewer", "display '%s'", &prefs_common.mime_image_viewer, - P_STRING}, - {"mime_audio_player", "play '%s'", &prefs_common.mime_audio_player, - P_STRING}, - {"mime_open_command", "gedit '%s'", &prefs_common.mime_open_cmd, - P_STRING}, - - /* Junk mail */ - {"enable_junk", "FALSE", &prefs_common.enable_junk, P_BOOL}, - {"junk_learn_command", "bogofilter -s -I", &prefs_common.junk_learncmd, - P_STRING}, - {"nojunk_learn_command", "bogofilter -n -I", - &prefs_common.nojunk_learncmd, P_STRING}, - {"junk_classify_command", "bogofilter -I", - &prefs_common.junk_classify_cmd, P_STRING}, - {"junk_folder", NULL, &prefs_common.junk_folder, P_STRING}, - {"filter_junk_on_receive", "FALSE", &prefs_common.filter_junk_on_recv, - P_BOOL}, - -#if USE_GPGME - /* Privacy */ - {"auto_check_signatures", "TRUE", &prefs_common.auto_check_signatures, - P_BOOL}, - {"gpg_signature_popup", "FALSE", &prefs_common.gpg_signature_popup, - P_BOOL}, - {"store_passphrase", "FALSE", &prefs_common.store_passphrase, P_BOOL}, - {"store_passphrase_timeout", "0", - &prefs_common.store_passphrase_timeout, P_INT}, -#ifndef G_OS_WIN32 - {"passphrase_grab", "FALSE", &prefs_common.passphrase_grab, P_BOOL}, -#endif /* G_OS_WIN32 */ - {"gpg_warning", "TRUE", &prefs_common.gpg_warning, P_BOOL}, -#endif /* USE_GPGME */ - - /* Interface */ - {"separate_folder", "FALSE", &prefs_common.sep_folder, P_BOOL}, - {"separate_message", "FALSE", &prefs_common.sep_msg, P_BOOL}, - - {"always_show_message_when_selected", "FALSE", - &prefs_common.always_show_msg, P_BOOL}, - {"open_unread_on_enter", "FALSE", &prefs_common.open_unread_on_enter, - P_BOOL}, - {"mark_as_read_on_new_window", "FALSE", - &prefs_common.mark_as_read_on_new_window, P_BOOL}, - {"open_inbox_on_inc", "FALSE", &prefs_common.open_inbox_on_inc, P_BOOL}, - {"immediate_execution", "TRUE", &prefs_common.immediate_exec, P_BOOL}, - {"receive_dialog_mode", "1", &prefs_common.recv_dialog_mode, P_ENUM}, - {"no_receive_error_panel", "FALSE", &prefs_common.no_recv_err_panel, - P_BOOL}, - {"close_receive_dialog", "TRUE", &prefs_common.close_recv_dialog, - P_BOOL}, - -#ifdef G_OS_WIN32 - {"comply_gnome_hig", "FALSE", &prefs_common.comply_gnome_hig, P_BOOL}, -#else - {"comply_gnome_hig", "TRUE", &prefs_common.comply_gnome_hig, P_BOOL}, -#endif - - /* Other */ - {"uri_open_command", DEFAULT_BROWSER_CMD, &prefs_common.uri_cmd, - P_STRING}, - {"print_command", "lpr %s", &prefs_common.print_cmd, P_STRING}, - {"ext_editor_command", "gedit %s", &prefs_common.ext_editor_cmd, - P_STRING}, - - {"add_address_by_click", "FALSE", &prefs_common.add_address_by_click, - P_BOOL}, - - {"confirm_on_exit", "FALSE", &prefs_common.confirm_on_exit, P_BOOL}, - {"clean_trash_on_exit", "FALSE", &prefs_common.clean_on_exit, P_BOOL}, - {"ask_on_cleaning", "TRUE", &prefs_common.ask_on_clean, P_BOOL}, - {"warn_queued_on_exit", "TRUE", &prefs_common.warn_queued_on_exit, - P_BOOL}, - - {"logwindow_line_limit", "1000", &prefs_common.logwin_line_limit, - P_INT}, - - /* Advanced */ - {"strict_cache_check", "FALSE", &prefs_common.strict_cache_check, - P_BOOL}, - {"io_timeout_secs", "60", &prefs_common.io_timeout_secs, P_INT}, - - {NULL, NULL, NULL, P_OTHER} -}; - - -PrefParam *prefs_common_get_params(void) -{ - return param; -} - -void prefs_common_read_config(void) -{ - FILE *fp; - gchar *path; - gchar buf[PREFSBUFSIZE]; - - path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL); - - prefs_read_config(param, "Common", path, NULL); - g_free(path); - - prefs_common.online_mode = TRUE; - - prefs_common_junk_filter_list_set(); - - path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMAND_HISTORY, - NULL); - if ((fp = g_fopen(path, "rb")) == NULL) { - if (ENOENT != errno) FILE_OP_ERROR(path, "fopen"); - g_free(path); - return; - } - g_free(path); - while (fgets(buf, sizeof(buf), fp) != NULL) { - g_strstrip(buf); - if (buf[0] == '\0') continue; - prefs_common.mime_open_cmd_history = - add_history(prefs_common.mime_open_cmd_history, buf); - } - fclose(fp); - - prefs_common.mime_open_cmd_history = - g_list_reverse(prefs_common.mime_open_cmd_history); -} - -void prefs_common_write_config(void) -{ - GList *cur; - FILE *fp; - gchar *path; - - prefs_write_config(param, "Common", COMMON_RC); - - path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMAND_HISTORY, - NULL); - if ((fp = g_fopen(path, "wb")) == NULL) { - FILE_OP_ERROR(path, "fopen"); - g_free(path); - return; - } - - for (cur = prefs_common.mime_open_cmd_history; - cur != NULL; cur = cur->next) { - fputs((gchar *)cur->data, fp); - fputc('\n', fp); - } - - fclose(fp); - g_free(path); -} - -void prefs_common_junk_filter_list_set(void) -{ - FilterRule *rule; - FilterCond *cond; - FilterAction *action; - GSList *cond_list = NULL, *action_list = NULL; - - if (prefs_common.junk_fltlist) { - filter_rule_list_free(prefs_common.junk_fltlist); - prefs_common.junk_fltlist = NULL; - } - - if (!prefs_common.junk_classify_cmd || !prefs_common.junk_folder) - return; - - cond = filter_cond_new(FLT_COND_CMD_TEST, 0, 0, NULL, - prefs_common.junk_classify_cmd); - cond_list = g_slist_append(NULL, cond); - action = filter_action_new(FLT_ACTION_COPY, prefs_common.junk_folder); - action_list = g_slist_append(NULL, action); - action = filter_action_new(FLT_ACTION_DELETE, NULL); - action_list = g_slist_append(action_list, action); - - rule = filter_rule_new(_("Junk mail filter"), FLT_OR, - cond_list, action_list); - - prefs_common.junk_fltlist = g_slist_append(NULL, rule); -} diff --git a/src/prefs_common.h b/src/prefs_common.h deleted file mode 100644 index afc5f1d0..00000000 --- a/src/prefs_common.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __PREFS_COMMON_H__ -#define __PREFS_COMMON_H__ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <glib.h> - -typedef struct _PrefsCommon PrefsCommon; - -#include "enums.h" -#include "prefs.h" - -typedef enum { - RECV_DIALOG_ALWAYS, - RECV_DIALOG_MANUAL, - RECV_DIALOG_NEVER -} RecvDialogMode; - -typedef enum { - CTE_AUTO, - CTE_BASE64, - CTE_QUOTED_PRINTABLE, - CTE_8BIT -} TransferEncodingMethod; - -struct _PrefsCommon -{ - /* Receive */ - gboolean use_extinc; - gchar *extinc_cmd; - gboolean inc_local; - gboolean filter_on_inc; - gchar *spool_path; - gboolean scan_all_after_inc; - gboolean autochk_newmail; - gint autochk_itv; - gboolean chk_on_startup; - gboolean enable_newmsg_notify; - gchar *newmsg_notify_cmd; - - /* Send */ - gboolean use_extsend; - gchar *extsend_cmd; - gboolean savemsg; - gboolean filter_sent; - gchar *outgoing_charset; - TransferEncodingMethod encoding_method; - - gboolean allow_jisx0201_kana; - - /* Compose */ - gboolean auto_sig; - gchar *sig_sep; - gint undolevels; - gint linewrap_len; - gboolean linewrap_quote; - gboolean autowrap; - gboolean linewrap_at_send; - gboolean auto_exteditor; - gboolean reply_account_autosel; - gboolean default_reply_list; - gboolean show_ruler; - - /* Quote */ - gboolean reply_with_quote; - gchar *quotemark; - gchar *quotefmt; - gchar *fw_quotemark; - gchar *fw_quotefmt; - - /* Display */ - gchar *textfont; - - gboolean trans_hdr; - gboolean display_folder_unread; - gint ng_abbrev_len; - - gboolean swap_from; - gboolean expand_thread; - gchar *date_format; - - gboolean enable_rules_hint; - gboolean bold_unread; - - ToolbarStyle toolbar_style; - gboolean show_statusbar; - - gint folderview_vscrollbar_policy; - - /* Summary columns visibility, position and size */ - gboolean summary_col_visible[N_SUMMARY_COLS]; - gint summary_col_pos[N_SUMMARY_COLS]; - gint summary_col_size[N_SUMMARY_COLS]; - - /* Widget visibility, position and size */ - gint folderwin_x; - gint folderwin_y; - gint folderview_width; - gint folderview_height; - gboolean folderview_visible; - - gint folder_col_folder; - gint folder_col_new; - gint folder_col_unread; - gint folder_col_total; - - gint summaryview_width; - gint summaryview_height; - - gint main_msgwin_x; - gint main_msgwin_y; - gint msgview_width; - gint msgview_height; - gboolean msgview_visible; - - gint mainview_x; - gint mainview_y; - gint mainview_width; - gint mainview_height; - gint mainwin_x; - gint mainwin_y; - gint mainwin_width; - gint mainwin_height; - - gint msgwin_width; - gint msgwin_height; - - gint sourcewin_width; - gint sourcewin_height; - - gint compose_width; - gint compose_height; - - /* Message */ - gboolean enable_color; - gint quote_level1_col; - gint quote_level2_col; - gint quote_level3_col; - gint uri_col; - gushort sig_col; - gboolean recycle_quote_colors; - gboolean conv_mb_alnum; - gboolean display_header_pane; - gboolean display_header; - gint line_space; - gboolean render_html; - gboolean textview_cursor_visible; - gboolean enable_smooth_scroll; - gint scroll_step; - gboolean scroll_halfpage; - - gboolean resize_image; - gboolean inline_image; - - gchar *force_charset; - - gboolean show_other_header; - GSList *disphdr_list; - - /* MIME viewer */ - gchar *mime_image_viewer; - gchar *mime_audio_player; - gchar *mime_open_cmd; - - GList *mime_open_cmd_history; - - /* Junk Mail */ - gboolean enable_junk; - gchar *junk_learncmd; - gchar *nojunk_learncmd; - gchar *junk_classify_cmd; - gchar *junk_folder; - gboolean filter_junk_on_recv; - -#if USE_GPGME - /* Privacy */ - gboolean auto_check_signatures; - gboolean gpg_signature_popup; - gboolean store_passphrase; - gint store_passphrase_timeout; - gboolean passphrase_grab; - gboolean gpg_warning; -#endif /* USE_GPGME */ - - /* Interface */ - gboolean sep_folder; - gboolean sep_msg; - gboolean always_show_msg; - gboolean open_unread_on_enter; - gboolean mark_as_read_on_new_window; - gboolean open_inbox_on_inc; - gboolean immediate_exec; - RecvDialogMode recv_dialog_mode; - gboolean no_recv_err_panel; - gboolean close_recv_dialog; - gboolean comply_gnome_hig; - - /* Other */ - gchar *uri_cmd; - gchar *print_cmd; - gchar *ext_editor_cmd; - - gboolean add_address_by_click; - - gboolean confirm_on_exit; - gboolean clean_on_exit; - gboolean ask_on_clean; - gboolean warn_queued_on_exit; - - gint logwin_line_limit; - - /* Advanced */ - gboolean strict_cache_check; - gint io_timeout_secs; - - /* Filtering */ - GSList *fltlist; - GSList *junk_fltlist; - - /* Actions */ - GSList *actions_list; - - /* Online / Offline */ - gboolean online_mode; -}; - -extern PrefsCommon prefs_common; - -PrefParam *prefs_common_get_params (void); - -void prefs_common_read_config (void); -void prefs_common_write_config (void); - -void prefs_common_junk_filter_list_set (void); - -#endif /* __PREFS_COMMON_H__ */ diff --git a/src/procheader.c b/src/procheader.c deleted file mode 100644 index 4ca1490c..00000000 --- a/src/procheader.c +++ /dev/null @@ -1,799 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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 <glib.h> -#include <glib/gi18n.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <time.h> -#include <sys/stat.h> - -#include "procheader.h" -#include "procmsg.h" -#include "codeconv.h" -#include "prefs_common.h" -#include "utils.h" - -#define BUFFSIZE 8192 - -gint procheader_get_one_field(gchar *buf, size_t len, FILE *fp, - HeaderEntry hentry[]) -{ - gint nexthead; - gint hnum = 0; - HeaderEntry *hp = NULL; - - if (hentry != NULL) { - /* skip non-required headers */ - do { - do { - if (fgets(buf, len, fp) == NULL) - return -1; - if (buf[0] == '\r' || buf[0] == '\n') - return -1; - } while (buf[0] == ' ' || buf[0] == '\t'); - - for (hp = hentry, hnum = 0; hp->name != NULL; - hp++, hnum++) { - if (!g_ascii_strncasecmp(hp->name, buf, - strlen(hp->name))) - break; - } - } while (hp->name == NULL); - } else { - if (fgets(buf, len, fp) == NULL) return -1; - if (buf[0] == '\r' || buf[0] == '\n') return -1; - } - - /* unfold the specified folded line */ - if (hp && hp->unfold) { - gboolean folded = FALSE; - gchar *bufp = buf + strlen(buf); - - for (; bufp > buf && - (*(bufp - 1) == '\n' || *(bufp - 1) == '\r'); - bufp--) - *(bufp - 1) = '\0'; - - while (1) { - nexthead = fgetc(fp); - - /* folded */ - if (nexthead == ' ' || nexthead == '\t') - folded = TRUE; - else if (nexthead == EOF) - break; - else if (folded == TRUE) { - if ((len - (bufp - buf)) <= 2) break; - - if (nexthead == '\n') { - folded = FALSE; - continue; - } - - /* replace return code on the tail end - with space */ - *bufp++ = ' '; - *bufp++ = nexthead; - *bufp = '\0'; - - /* concatenate next line */ - if (fgets(bufp, len - (bufp - buf), fp) - == NULL) break; - bufp += strlen(bufp); - - for (; bufp > buf && - (*(bufp - 1) == '\n' || *(bufp - 1) == '\r'); - bufp--) - *(bufp - 1) = '\0'; - - folded = FALSE; - } else { - ungetc(nexthead, fp); - break; - } - } - - return hnum; - } - - while (1) { - nexthead = fgetc(fp); - if (nexthead == ' ' || nexthead == '\t') { - size_t buflen = strlen(buf); - - /* concatenate next line */ - if ((len - buflen) > 2) { - gchar *p = buf + buflen; - - *p++ = nexthead; - *p = '\0'; - buflen++; - if (fgets(p, len - buflen, fp) == NULL) - break; - } else - break; - } else { - if (nexthead != EOF) - ungetc(nexthead, fp); - break; - } - } - - /* remove trailing return code */ - strretchomp(buf); - - return hnum; -} - -gchar *procheader_get_unfolded_line(gchar *buf, size_t len, FILE *fp) -{ - gboolean folded = FALSE; - gint nexthead; - gchar *bufp; - - if (fgets(buf, len, fp) == NULL) return NULL; - if (buf[0] == '\r' || buf[0] == '\n') return NULL; - bufp = buf + strlen(buf); - - for (; bufp > buf && - (*(bufp - 1) == '\n' || *(bufp - 1) == '\r'); - bufp--) - *(bufp - 1) = '\0'; - - while (1) { - nexthead = fgetc(fp); - - /* folded */ - if (nexthead == ' ' || nexthead == '\t') - folded = TRUE; - else if (nexthead == EOF) - break; - else if (folded == TRUE) { - if ((len - (bufp - buf)) <= 2) break; - - if (nexthead == '\n') { - folded = FALSE; - continue; - } - - /* replace return code on the tail end - with space */ - *bufp++ = ' '; - *bufp++ = nexthead; - *bufp = '\0'; - - /* concatenate next line */ - if (fgets(bufp, len - (bufp - buf), fp) - == NULL) break; - bufp += strlen(bufp); - - for (; bufp > buf && - (*(bufp - 1) == '\n' || *(bufp - 1) == '\r'); - bufp--) - *(bufp - 1) = '\0'; - - folded = FALSE; - } else { - ungetc(nexthead, fp); - break; - } - } - - /* remove trailing return code */ - strretchomp(buf); - - return buf; -} - -GSList *procheader_get_header_list_from_file(const gchar *file) -{ - FILE *fp; - GSList *hlist; - - if ((fp = g_fopen(file, "rb")) == NULL) { - FILE_OP_ERROR(file, "fopen"); - return NULL; - } - - hlist = procheader_get_header_list(fp); - - fclose(fp); - return hlist; -} - -GSList *procheader_get_header_list(FILE *fp) -{ - gchar buf[BUFFSIZE]; - gchar *p; - GSList *hlist = NULL; - Header *header; - - g_return_val_if_fail(fp != NULL, NULL); - - while (procheader_get_unfolded_line(buf, sizeof(buf), fp) != NULL) { - if (*buf == ':') continue; - for (p = buf; *p && *p != ' '; p++) { - if (*p == ':') { - header = g_new(Header, 1); - header->name = g_strndup(buf, p - buf); - p++; - while (*p == ' ' || *p == '\t') p++; - header->body = conv_unmime_header(p, NULL); - - hlist = g_slist_append(hlist, header); - break; - } - } - } - - return hlist; -} - -GSList *procheader_add_header_list(GSList *hlist, const gchar *header_name, - const gchar *body) -{ - Header *header; - - g_return_val_if_fail(header_name != NULL, hlist); - - header = g_new(Header, 1); - header->name = g_strdup(header_name); - header->body = g_strdup(body); - - return g_slist_append(hlist, header); -} - -GSList *procheader_merge_header_list(GSList *hlist1, GSList *hlist2) -{ - GSList *cur; - - for (cur = hlist2; cur != NULL; cur = cur->next) { - Header *header = (Header *)cur->data; - if (procheader_find_header_list(hlist1, header->name) < 0) - hlist1 = g_slist_append(hlist1, header); - } - - return hlist1; -} - -gint procheader_find_header_list(GSList *hlist, const gchar *header_name) -{ - GSList *cur; - gint index = 0; - Header *header; - - g_return_val_if_fail(header_name != NULL, -1); - - for (cur = hlist; cur != NULL; cur = cur->next, index++) { - header = (Header *)cur->data; - if (g_ascii_strcasecmp(header->name, header_name) == 0) - return index; - } - - return -1; -} - -GPtrArray *procheader_get_header_array(FILE *fp, const gchar *encoding) -{ - gchar buf[BUFFSIZE]; - gchar *p; - GPtrArray *headers; - Header *header; - - g_return_val_if_fail(fp != NULL, NULL); - - headers = g_ptr_array_new(); - - while (procheader_get_unfolded_line(buf, sizeof(buf), fp) != NULL) { - if (*buf == ':') continue; - for (p = buf; *p && *p != ' '; p++) { - if (*p == ':') { - header = g_new(Header, 1); - header->name = g_strndup(buf, p - buf); - p++; - while (*p == ' ' || *p == '\t') p++; - header->body = conv_unmime_header(p, encoding); - - g_ptr_array_add(headers, header); - break; - } - } - } - - return headers; -} - -GPtrArray *procheader_get_header_array_asis(FILE *fp, const gchar *encoding) -{ - gchar buf[BUFFSIZE]; - gchar *p; - GPtrArray *headers; - Header *header; - - g_return_val_if_fail(fp != NULL, NULL); - - headers = g_ptr_array_new(); - - while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1) { - if (*buf == ':') continue; - for (p = buf; *p && *p != ' '; p++) { - if (*p == ':') { - header = g_new(Header, 1); - header->name = g_strndup(buf, p - buf); - p++; - header->body = conv_unmime_header(p, encoding); - - g_ptr_array_add(headers, header); - break; - } - } - } - - return headers; -} - -void procheader_header_list_destroy(GSList *hlist) -{ - Header *header; - - while (hlist != NULL) { - header = hlist->data; - procheader_header_free(header); - hlist = g_slist_remove(hlist, header); - } -} - -void procheader_header_array_destroy(GPtrArray *harray) -{ - gint i; - Header *header; - - for (i = 0; i < harray->len; i++) { - header = g_ptr_array_index(harray, i); - procheader_header_free(header); - } - - g_ptr_array_free(harray, TRUE); -} - -void procheader_header_free(Header *header) -{ - if (!header) return; - - g_free(header->name); - g_free(header->body); - g_free(header); -} - -void procheader_get_header_fields(FILE *fp, HeaderEntry hentry[]) -{ - gchar buf[BUFFSIZE]; - HeaderEntry *hp; - gint hnum; - gchar *p; - - if (hentry == NULL) return; - - while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry)) - != -1) { - hp = hentry + hnum; - - p = buf + strlen(hp->name); - while (*p == ' ' || *p == '\t') p++; - - if (hp->body == NULL) - hp->body = g_strdup(p); - else if (!g_ascii_strcasecmp(hp->name, "To:") || - !g_ascii_strcasecmp(hp->name, "Cc:")) { - gchar *tp = hp->body; - hp->body = g_strconcat(tp, ", ", p, NULL); - g_free(tp); - } - } -} - -MsgInfo *procheader_parse_file(const gchar *file, MsgFlags flags, - gboolean full) -{ - struct stat s; - FILE *fp; - MsgInfo *msginfo; - - if (g_stat(file, &s) < 0) { - FILE_OP_ERROR(file, "stat"); - return NULL; - } - if (!S_ISREG(s.st_mode)) - return NULL; - - if ((fp = g_fopen(file, "rb")) == NULL) { - FILE_OP_ERROR(file, "fopen"); - return NULL; - } - - msginfo = procheader_parse_stream(fp, flags, full); - fclose(fp); - - if (msginfo) { - msginfo->size = s.st_size; - msginfo->mtime = s.st_mtime; - } - - return msginfo; -} - -MsgInfo *procheader_parse_str(const gchar *str, MsgFlags flags, gboolean full) -{ - FILE *fp; - MsgInfo *msginfo; - - if ((fp = str_open_as_stream(str)) == NULL) - return NULL; - - msginfo = procheader_parse_stream(fp, flags, full); - fclose(fp); - return msginfo; -} - -enum -{ - H_DATE = 0, - H_FROM = 1, - H_TO = 2, - H_NEWSGROUPS = 3, - H_SUBJECT = 4, - H_MSG_ID = 5, - H_REFERENCES = 6, - H_IN_REPLY_TO = 7, - H_CONTENT_TYPE = 8, - H_SEEN = 9, - H_CC = 10, - H_X_FACE = 11 -}; - -MsgInfo *procheader_parse_stream(FILE *fp, MsgFlags flags, gboolean full) -{ - static HeaderEntry hentry_full[] = {{"Date:", NULL, FALSE}, - {"From:", NULL, TRUE}, - {"To:", NULL, TRUE}, - {"Newsgroups:", NULL, TRUE}, - {"Subject:", NULL, TRUE}, - {"Message-Id:", NULL, FALSE}, - {"References:", NULL, FALSE}, - {"In-Reply-To:", NULL, FALSE}, - {"Content-Type:", NULL, FALSE}, - {"Seen:", NULL, FALSE}, - {"Cc:", NULL, TRUE}, - {"X-Face:", NULL, FALSE}, - {NULL, NULL, FALSE}}; - - static HeaderEntry hentry_short[] = {{"Date:", NULL, FALSE}, - {"From:", NULL, TRUE}, - {"To:", NULL, TRUE}, - {"Newsgroups:", NULL, TRUE}, - {"Subject:", NULL, TRUE}, - {"Message-Id:", NULL, FALSE}, - {"References:", NULL, FALSE}, - {"In-Reply-To:", NULL, FALSE}, - {"Content-Type:", NULL, FALSE}, - {"Seen:", NULL, FALSE}, - {NULL, NULL, FALSE}}; - - MsgInfo *msginfo; - gchar buf[BUFFSIZE]; - gchar *p; - gchar *hp; - HeaderEntry *hentry; - gint hnum; - gchar *from = NULL, *to = NULL, *subject = NULL, *cc = NULL; - gchar *charset = NULL; - - hentry = full ? hentry_full : hentry_short; - - if (MSG_IS_QUEUED(flags)) { - while (fgets(buf, sizeof(buf), fp) != NULL) - if (buf[0] == '\r' || buf[0] == '\n') break; - } - - msginfo = g_new0(MsgInfo, 1); - msginfo->flags = flags; - msginfo->references = NULL; - msginfo->inreplyto = NULL; - - while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry)) - != -1) { - hp = buf + strlen(hentry[hnum].name); - while (*hp == ' ' || *hp == '\t') hp++; - - switch (hnum) { - case H_DATE: - if (msginfo->date) break; - msginfo->date_t = - procheader_date_parse(NULL, hp, 0); - msginfo->date = g_strdup(hp); - break; - case H_FROM: - if (from) break; - from = g_strdup(hp); - break; - case H_TO: - if (to) { - p = to; - to = g_strconcat(p, ", ", hp, NULL); - g_free(p); - } else - to = g_strdup(hp); - break; - case H_NEWSGROUPS: - if (msginfo->newsgroups) { - p = msginfo->newsgroups; - msginfo->newsgroups = - g_strconcat(p, ",", hp, NULL); - g_free(p); - } else - msginfo->newsgroups = g_strdup(buf + 12); - break; - case H_SUBJECT: - if (msginfo->subject) break; - subject = g_strdup(hp); - break; - case H_MSG_ID: - if (msginfo->msgid) break; - - extract_parenthesis(hp, '<', '>'); - remove_space(hp); - msginfo->msgid = g_strdup(hp); - break; - case H_REFERENCES: - msginfo->references = - references_list_prepend(msginfo->references, - hp); - break; - case H_IN_REPLY_TO: - if (msginfo->inreplyto) break; - - eliminate_parenthesis(hp, '(', ')'); - if ((p = strrchr(hp, '<')) != NULL && - strchr(p + 1, '>') != NULL) { - extract_parenthesis(p, '<', '>'); - remove_space(p); - if (*p != '\0') - msginfo->inreplyto = g_strdup(p); - } - break; - case H_CONTENT_TYPE: - if (!g_ascii_strncasecmp(hp, "multipart", 9)) { - MSG_SET_TMP_FLAGS(msginfo->flags, MSG_MIME); - } else if (!charset) { - procmime_scan_content_type_str - (hp, NULL, &charset, NULL, NULL); - } - break; - case H_SEEN: - /* mnews Seen header */ - MSG_UNSET_PERM_FLAGS(msginfo->flags, MSG_NEW|MSG_UNREAD); - break; - case H_CC: - if (cc) { - p = cc; - cc = g_strconcat(p, ", ", hp, NULL); - g_free(p); - } else - cc = g_strdup(hp); - break; - case H_X_FACE: - if (msginfo->xface) break; - msginfo->xface = g_strdup(hp); - break; - default: - break; - } - } - - if (from) { - msginfo->from = conv_unmime_header(from, charset); - msginfo->fromname = procheader_get_fromname(msginfo->from); - g_free(from); - } - if (to) { - msginfo->to = conv_unmime_header(to, charset); - g_free(to); - } - if (subject) { - msginfo->subject = conv_unmime_header(subject, charset); - g_free(subject); - } - if (cc) { - msginfo->cc = conv_unmime_header(cc, charset); - g_free(cc); - } - - if (!msginfo->inreplyto && msginfo->references) - msginfo->inreplyto = - g_strdup((gchar *)msginfo->references->data); - - g_free(charset); - - return msginfo; -} - -gchar *procheader_get_fromname(const gchar *str) -{ - gchar *tmp, *name; - - Xstrdup_a(tmp, str, return NULL); - - if (*tmp == '\"') { - extract_quote(tmp, '\"'); - g_strstrip(tmp); - } else if (strchr(tmp, '<')) { - eliminate_parenthesis(tmp, '<', '>'); - g_strstrip(tmp); - if (*tmp == '\0') { - strcpy(tmp, str); - extract_parenthesis(tmp, '<', '>'); - g_strstrip(tmp); - } - } else if (strchr(tmp, '(')) { - extract_parenthesis(tmp, '(', ')'); - g_strstrip(tmp); - } - - if (*tmp == '\0') - name = g_strdup(str); - else - name = g_strdup(tmp); - - return name; -} - -static gint procheader_scan_date_string(const gchar *str, - gchar *weekday, gint *day, - gchar *month, gint *year, - gint *hh, gint *mm, gint *ss, - gchar *zone) -{ - gint result; - - result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d %5s", - weekday, day, month, year, hh, mm, ss, zone); - if (result == 8) return 0; - - result = sscanf(str, "%3s,%d %9s %d %2d:%2d:%2d %5s", - weekday, day, month, year, hh, mm, ss, zone); - if (result == 8) return 0; - - result = sscanf(str, "%d %9s %d %2d:%2d:%2d %5s", - day, month, year, hh, mm, ss, zone); - if (result == 7) return 0; - - *zone = '\0'; - result = sscanf(str, "%10s %d %9s %d %2d:%2d:%2d", - weekday, day, month, year, hh, mm, ss); - if (result == 7) return 0; - - result = sscanf(str, "%d %9s %d %2d:%2d:%2d", - day, month, year, hh, mm, ss); - if (result == 6) return 0; - - *ss = 0; - result = sscanf(str, "%10s %d %9s %d %2d:%2d %5s", - weekday, day, month, year, hh, mm, zone); - if (result == 7) return 0; - - result = sscanf(str, "%d %9s %d %2d:%2d %5s", - day, month, year, hh, mm, zone); - if (result == 6) return 0; - - *zone = '\0'; - result = sscanf(str, "%10s %d %9s %d %2d:%2d", - weekday, day, month, year, hh, mm); - if (result == 6) return 0; - - result = sscanf(str, "%d %9s %d %2d:%2d", - day, month, year, hh, mm); - if (result == 5) return 0; - - return -1; -} - -time_t procheader_date_parse(gchar *dest, const gchar *src, gint len) -{ - static gchar monthstr[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; - gchar weekday[11]; - gint day; - gchar month[10]; - gint year; - gint hh, mm, ss; - gchar zone[6]; - GDateMonth dmonth = G_DATE_BAD_MONTH; - struct tm t; - gchar *p; - time_t timer; - time_t tz_offset; - - if (procheader_scan_date_string(src, weekday, &day, month, &year, - &hh, &mm, &ss, zone) < 0) { - if (dest && len > 0) - strncpy2(dest, src, len); - return 0; - } - - /* Y2K compliant :) */ - if (year < 1000) { - if (year < 50) - year += 2000; - else - year += 1900; - } - - month[3] = '\0'; - for (p = monthstr; *p != '\0'; p += 3) { - if (!g_ascii_strncasecmp(p, month, 3)) { - dmonth = (gint)(p - monthstr) / 3 + 1; - break; - } - } - - t.tm_sec = ss; - t.tm_min = mm; - t.tm_hour = hh; - t.tm_mday = day; - t.tm_mon = dmonth - 1; - t.tm_year = year - 1900; - t.tm_wday = 0; - t.tm_yday = 0; - t.tm_isdst = -1; - - timer = mktime(&t); - tz_offset = remote_tzoffset_sec(zone); - if (tz_offset != -1) - timer += tzoffset_sec(&timer) - tz_offset; - - if (dest) - procheader_date_get_localtime(dest, len, timer); - - return timer; -} - -void procheader_date_get_localtime(gchar *dest, gint len, const time_t timer) -{ - struct tm *lt; - gchar *default_format = "%y/%m/%d(%a) %H:%M"; - gchar *tmp, *buf; - - Xalloca(tmp, len + 1, dest[0] = '\0'; return;); - - lt = localtime(&timer); - - if (prefs_common.date_format) - strftime(tmp, len, prefs_common.date_format, lt); - else - strftime(tmp, len, default_format, lt); - - buf = conv_localetodisp(tmp, NULL); - strncpy2(dest, buf, len); - g_free(buf); -} diff --git a/src/procheader.h b/src/procheader.h deleted file mode 100644 index 1667b4ed..00000000 --- a/src/procheader.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __PROCHEADER_H__ -#define __PROCHEADER_H__ - -#include <glib.h> -#include <stdio.h> -#include <time.h> - -#include "procmsg.h" - -typedef struct _HeaderEntry HeaderEntry; -typedef struct _Header Header; - -struct _HeaderEntry -{ - gchar *name; - gchar *body; - gboolean unfold; -}; - -struct _Header -{ - gchar *name; - gchar *body; -}; - -gint procheader_get_one_field (gchar *buf, - size_t len, - FILE *fp, - HeaderEntry hentry[]); -gchar *procheader_get_unfolded_line (gchar *buf, - size_t len, - FILE *fp); - -GSList *procheader_get_header_list_from_file (const gchar *file); -GSList *procheader_get_header_list (FILE *fp); -GSList *procheader_add_header_list (GSList *hlist, - const gchar *header_name, - const gchar *body); -GSList *procheader_merge_header_list (GSList *hlist1, - GSList *hlist2); -gint procheader_find_header_list (GSList *hlist, - const gchar *header_name); -void procheader_header_list_destroy (GSList *hlist); - -GPtrArray *procheader_get_header_array (FILE *fp, - const gchar *encoding); -GPtrArray *procheader_get_header_array_asis (FILE *fp, - const gchar *encoding); -void procheader_header_array_destroy (GPtrArray *harray); - -void procheader_header_free (Header *header); - -void procheader_get_header_fields (FILE *fp, - HeaderEntry hentry[]); -MsgInfo *procheader_parse_file (const gchar *file, - MsgFlags flags, - gboolean full); -MsgInfo *procheader_parse_str (const gchar *str, - MsgFlags flags, - gboolean full); -MsgInfo *procheader_parse_stream (FILE *fp, - MsgFlags flags, - gboolean full); - -gchar *procheader_get_fromname (const gchar *str); - -time_t procheader_date_parse (gchar *dest, - const gchar *src, - gint len); -void procheader_date_get_localtime (gchar *dest, - gint len, - const time_t timer); - -#endif /* __PROCHEADER_H__ */ diff --git a/src/procmime.c b/src/procmime.c deleted file mode 100644 index 1787aa2c..00000000 --- a/src/procmime.c +++ /dev/null @@ -1,1170 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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 <glib/gi18n.h> -#include <stdio.h> -#include <string.h> -#include <locale.h> -#include <ctype.h> - -#include "procmime.h" -#include "procheader.h" -#include "base64.h" -#include "quoted-printable.h" -#include "uuencode.h" -#include "html.h" -#include "codeconv.h" -#include "utils.h" -#include "prefs_common.h" - -#if USE_GPGME -# include "rfc2015.h" -#endif - -static GHashTable *procmime_get_mime_type_table (void); -static GList *procmime_get_mime_type_list (const gchar *file); - - -MimeInfo *procmime_mimeinfo_new(void) -{ - MimeInfo *mimeinfo; - - mimeinfo = g_new0(MimeInfo, 1); - mimeinfo->mime_type = MIME_UNKNOWN; - mimeinfo->encoding_type = ENC_UNKNOWN; - - return mimeinfo; -} - -void procmime_mimeinfo_free_all(MimeInfo *mimeinfo) -{ - while (mimeinfo != NULL) { - MimeInfo *next; - - g_free(mimeinfo->encoding); - g_free(mimeinfo->content_type); - g_free(mimeinfo->charset); - g_free(mimeinfo->name); - g_free(mimeinfo->boundary); - g_free(mimeinfo->content_disposition); - g_free(mimeinfo->filename); -#if USE_GPGME - g_free(mimeinfo->plaintextfile); - g_free(mimeinfo->sigstatus); - g_free(mimeinfo->sigstatus_full); -#endif - - procmime_mimeinfo_free_all(mimeinfo->sub); - procmime_mimeinfo_free_all(mimeinfo->children); -#if USE_GPGME - procmime_mimeinfo_free_all(mimeinfo->plaintext); -#endif - - next = mimeinfo->next; - g_free(mimeinfo); - mimeinfo = next; - } -} - -MimeInfo *procmime_mimeinfo_insert(MimeInfo *parent, MimeInfo *mimeinfo) -{ - MimeInfo *child = parent->children; - - if (!child) - parent->children = mimeinfo; - else { - while (child->next != NULL) - child = child->next; - - child->next = mimeinfo; - } - - mimeinfo->parent = parent; - mimeinfo->level = parent->level + 1; - - return mimeinfo; -} - -void procmime_mimeinfo_replace(MimeInfo *old, MimeInfo *new) -{ - MimeInfo *parent = old->parent; - MimeInfo *child; - - g_return_if_fail(parent != NULL); - g_return_if_fail(new->next == NULL); - - for (child = parent->children; child && child != old; - child = child->next) - ; - if (!child) { - g_warning("oops: parent can't find it's own child"); - return; - } - procmime_mimeinfo_free_all(old); - - if (child == parent->children) { - new->next = parent->children->next; - parent->children = new; - } else { - new->next = child->next; - child = new; - } -} - -MimeInfo *procmime_mimeinfo_next(MimeInfo *mimeinfo) -{ - if (!mimeinfo) return NULL; - - if (mimeinfo->children) - return mimeinfo->children; - if (mimeinfo->sub) - return mimeinfo->sub; - if (mimeinfo->next) - return mimeinfo->next; - - if (mimeinfo->main) { - mimeinfo = mimeinfo->main; - if (mimeinfo->next) - return mimeinfo->next; - } - - for (mimeinfo = mimeinfo->parent; mimeinfo != NULL; - mimeinfo = mimeinfo->parent) { - if (mimeinfo->next) - return mimeinfo->next; - if (mimeinfo->main) { - mimeinfo = mimeinfo->main; - if (mimeinfo->next) - return mimeinfo->next; - } - } - - return NULL; -} - -#if 0 -void procmime_dump_mimeinfo(MimeInfo *mimeinfo) -{ - gint i; - - g_print("\n"); - - for (; mimeinfo != NULL; mimeinfo = procmime_mimeinfo_next(mimeinfo)) { - for (i = 0; i < mimeinfo->level; i++) - g_print(" "); - g_print("%s%s\n", mimeinfo->main ? "sub: " : "", - mimeinfo->content_type); - } -} -#endif - -MimeInfo *procmime_scan_message(MsgInfo *msginfo) -{ - FILE *fp; - MimeInfo *mimeinfo; - - g_return_val_if_fail(msginfo != NULL, NULL); - -#if USE_GPGME - if ((fp = procmsg_open_message_decrypted(msginfo, &mimeinfo)) == NULL) - return NULL; -#else - if ((fp = procmsg_open_message(msginfo)) == NULL) return NULL; - mimeinfo = procmime_scan_mime_header(fp); -#endif - - if (mimeinfo) { - mimeinfo->size = msginfo->size; - mimeinfo->content_size = get_left_file_size(fp); - if (mimeinfo->encoding_type == ENC_BASE64) - mimeinfo->content_size = mimeinfo->content_size / 4 * 3; - if (mimeinfo->mime_type == MIME_MULTIPART || - mimeinfo->mime_type == MIME_MESSAGE_RFC822) - procmime_scan_multipart_message(mimeinfo, fp); - } - - fclose(fp); - - return mimeinfo; -} - -void procmime_scan_multipart_message(MimeInfo *mimeinfo, FILE *fp) -{ - gchar *p; - gchar *boundary; - gint boundary_len = 0; - gchar buf[BUFFSIZE]; - glong fpos, prev_fpos; - - g_return_if_fail(mimeinfo != NULL); - g_return_if_fail(mimeinfo->mime_type == MIME_MULTIPART || - mimeinfo->mime_type == MIME_MESSAGE_RFC822); - - if (mimeinfo->mime_type == MIME_MULTIPART) { - g_return_if_fail(mimeinfo->boundary != NULL); - g_return_if_fail(mimeinfo->sub == NULL); - } - g_return_if_fail(fp != NULL); - - boundary = mimeinfo->boundary; - - if (boundary) { - boundary_len = strlen(boundary); - - /* look for first boundary */ - while ((p = fgets(buf, sizeof(buf), fp)) != NULL) - if (IS_BOUNDARY(buf, boundary, boundary_len)) break; - if (!p) return; - } else if (mimeinfo->parent && mimeinfo->parent->boundary) { - boundary = mimeinfo->parent->boundary; - boundary_len = strlen(boundary); - } - - if ((fpos = ftell(fp)) < 0) { - perror("ftell"); - return; - } - - for (;;) { - MimeInfo *partinfo; - gboolean eom = FALSE; - glong content_pos; - gboolean is_base64; - gint len; - guint b64_content_len = 0; - gint b64_pad_len = 0; - - prev_fpos = fpos; - debug_print("prev_fpos: %ld\n", fpos); - - /* scan part header */ - if (mimeinfo->mime_type == MIME_MESSAGE_RFC822) { - MimeInfo *sub; - - mimeinfo->sub = sub = procmime_scan_mime_header(fp); - if (!sub) break; - - debug_print("message/rfc822 part found\n"); - sub->level = mimeinfo->level + 1; - sub->parent = mimeinfo->parent; - sub->main = mimeinfo; - - partinfo = sub; - } else { - partinfo = procmime_scan_mime_header(fp); - if (!partinfo) break; - procmime_mimeinfo_insert(mimeinfo, partinfo); - debug_print("content-type: %s\n", - partinfo->content_type); - } - - /* begin content */ - content_pos = ftell(fp); - debug_print("content_pos: %ld\n", content_pos); - - if (partinfo->mime_type == MIME_MULTIPART || - partinfo->mime_type == MIME_MESSAGE_RFC822) { - if (partinfo->level < 8) - procmime_scan_multipart_message(partinfo, fp); - } - - /* look for next boundary */ - buf[0] = '\0'; - is_base64 = partinfo->encoding_type == ENC_BASE64; - while ((p = fgets(buf, sizeof(buf), fp)) != NULL) { - if (IS_BOUNDARY(buf, boundary, boundary_len)) { - if (buf[2 + boundary_len] == '-' && - buf[2 + boundary_len + 1] == '-') - eom = TRUE; - break; - } else if (is_base64) { - const gchar *s; - for (s = buf; *s && *s != '\r' && *s != '\n'; - ++s) - if (*s == '=') - ++b64_pad_len; - b64_content_len += s - buf; - } - } - if (p == NULL) { - /* broken MIME, or single part MIME message */ - buf[0] = '\0'; - eom = TRUE; - } - debug_print("boundary: %s\n", buf); - - fpos = ftell(fp); - debug_print("fpos: %ld\n", fpos); - - len = strlen(buf); - partinfo->size = fpos - prev_fpos - len; - if (is_base64) - partinfo->content_size = - b64_content_len / 4 * 3 - b64_pad_len; - else - partinfo->content_size = fpos - content_pos - len; - debug_print("partinfo->size: %d\n", partinfo->size); - debug_print("partinfo->content_size: %d\n", - partinfo->content_size); - if (partinfo->sub && !partinfo->sub->sub && - !partinfo->sub->children) { - partinfo->sub->size = - fpos - partinfo->sub->fpos - strlen(buf); - debug_print("partinfo->sub->size: %d\n", - partinfo->sub->size); - } - - if (mimeinfo->mime_type == MIME_MESSAGE_RFC822) { - if (len > 0 && fseek(fp, fpos - len, SEEK_SET) < 0) - perror("fseek"); - break; - } - - if (eom) break; - } -} - -void procmime_scan_encoding(MimeInfo *mimeinfo, const gchar *encoding) -{ - gchar *buf; - - Xstrdup_a(buf, encoding, return); - - g_free(mimeinfo->encoding); - - mimeinfo->encoding = g_strdup(g_strstrip(buf)); - if (!g_ascii_strcasecmp(buf, "7bit")) - mimeinfo->encoding_type = ENC_7BIT; - else if (!g_ascii_strcasecmp(buf, "8bit")) - mimeinfo->encoding_type = ENC_8BIT; - else if (!g_ascii_strcasecmp(buf, "quoted-printable")) - mimeinfo->encoding_type = ENC_QUOTED_PRINTABLE; - else if (!g_ascii_strcasecmp(buf, "base64")) - mimeinfo->encoding_type = ENC_BASE64; - else if (!g_ascii_strcasecmp(buf, "x-uuencode")) - mimeinfo->encoding_type = ENC_X_UUENCODE; - else - mimeinfo->encoding_type = ENC_UNKNOWN; - -} - -void procmime_scan_content_type(MimeInfo *mimeinfo, const gchar *content_type) -{ - g_free(mimeinfo->content_type); - g_free(mimeinfo->charset); - g_free(mimeinfo->name); - g_free(mimeinfo->boundary); - mimeinfo->content_type = NULL; - mimeinfo->charset = NULL; - mimeinfo->name = NULL; - mimeinfo->boundary = NULL; - - procmime_scan_content_type_str(content_type, &mimeinfo->content_type, - &mimeinfo->charset, &mimeinfo->name, - &mimeinfo->boundary); - - mimeinfo->mime_type = procmime_scan_mime_type(mimeinfo->content_type); - if (mimeinfo->mime_type == MIME_MULTIPART && !mimeinfo->boundary) - mimeinfo->mime_type = MIME_TEXT; -} - -void procmime_scan_content_type_str(const gchar *content_type, - gchar **mime_type, gchar **charset, - gchar **name, gchar **boundary) -{ - gchar *delim, *p; - gchar *buf; - - Xstrdup_a(buf, content_type, return); - - if ((delim = strchr(buf, ';'))) *delim = '\0'; - if (mime_type) - *mime_type = g_strdup(g_strstrip(buf)); - - if (!delim) return; - p = delim + 1; - - for (;;) { - gchar *eq; - gchar *attr, *value; - - if ((delim = strchr(p, ';'))) *delim = '\0'; - - if (!(eq = strchr(p, '='))) break; - - *eq = '\0'; - attr = p; - g_strstrip(attr); - value = eq + 1; - g_strstrip(value); - - if (*value == '"') - extract_quote(value, '"'); - else { - eliminate_parenthesis(value, '(', ')'); - g_strstrip(value); - } - - if (*value) { - if (charset && !g_ascii_strcasecmp(attr, "charset")) - *charset = g_strdup(value); - else if (name && !g_ascii_strcasecmp(attr, "name")) - *name = conv_unmime_header(value, NULL); - else if (boundary && - !g_ascii_strcasecmp(attr, "boundary")) - *boundary = g_strdup(value); - } - - if (!delim) break; - p = delim + 1; - } -} - -void procmime_scan_content_disposition(MimeInfo *mimeinfo, - const gchar *content_disposition) -{ - gchar *delim, *p, *dispos; - gchar *buf; - - Xstrdup_a(buf, content_disposition, return); - - if ((delim = strchr(buf, ';'))) *delim = '\0'; - mimeinfo->content_disposition = dispos = g_strdup(g_strstrip(buf)); - - if (!delim) return; - p = delim + 1; - - for (;;) { - gchar *eq; - gchar *attr, *value; - - if ((delim = strchr(p, ';'))) *delim = '\0'; - - if (!(eq = strchr(p, '='))) break; - - *eq = '\0'; - attr = p; - g_strstrip(attr); - value = eq + 1; - g_strstrip(value); - - if (*value == '"') - extract_quote(value, '"'); - else { - eliminate_parenthesis(value, '(', ')'); - g_strstrip(value); - } - - if (*value) { - if (!g_ascii_strcasecmp(attr, "filename")) { - g_free(mimeinfo->filename); - mimeinfo->filename = - conv_unmime_header(value, NULL); - break; - } - } - - if (!delim) break; - p = delim + 1; - } -} - -enum -{ - H_CONTENT_TRANSFER_ENCODING = 0, - H_CONTENT_TYPE = 1, - H_CONTENT_DISPOSITION = 2 -}; - -MimeInfo *procmime_scan_mime_header(FILE *fp) -{ - static HeaderEntry hentry[] = {{"Content-Transfer-Encoding:", - NULL, FALSE}, - {"Content-Type:", NULL, TRUE}, - {"Content-Disposition:", - NULL, TRUE}, - {NULL, NULL, FALSE}}; - gchar buf[BUFFSIZE]; - gint hnum; - HeaderEntry *hp; - MimeInfo *mimeinfo; - - g_return_val_if_fail(fp != NULL, NULL); - - mimeinfo = procmime_mimeinfo_new(); - mimeinfo->mime_type = MIME_TEXT; - mimeinfo->encoding_type = ENC_7BIT; - mimeinfo->fpos = ftell(fp); - - while ((hnum = procheader_get_one_field(buf, sizeof(buf), fp, hentry)) - != -1) { - hp = hentry + hnum; - - if (H_CONTENT_TRANSFER_ENCODING == hnum) { - procmime_scan_encoding - (mimeinfo, buf + strlen(hp->name)); - } else if (H_CONTENT_TYPE == hnum) { - procmime_scan_content_type - (mimeinfo, buf + strlen(hp->name)); - } else if (H_CONTENT_DISPOSITION == hnum) { - procmime_scan_content_disposition - (mimeinfo, buf + strlen(hp->name)); - } - } - - if (mimeinfo->mime_type == MIME_APPLICATION_OCTET_STREAM && - mimeinfo->name) { - const gchar *type; - type = procmime_get_mime_type(mimeinfo->name); - if (type) - mimeinfo->mime_type = procmime_scan_mime_type(type); - } - - if (!mimeinfo->content_type) - mimeinfo->content_type = g_strdup("text/plain"); - - return mimeinfo; -} - -FILE *procmime_decode_content(FILE *outfp, FILE *infp, MimeInfo *mimeinfo) -{ - gchar buf[BUFFSIZE]; - gchar *boundary = NULL; - gint boundary_len = 0; - gboolean tmp_file = FALSE; - - g_return_val_if_fail(infp != NULL, NULL); - g_return_val_if_fail(mimeinfo != NULL, NULL); - - if (!outfp) { - outfp = my_tmpfile(); - if (!outfp) { - perror("tmpfile"); - return NULL; - } - tmp_file = TRUE; - } - - if (mimeinfo->parent && mimeinfo->parent->boundary) { - boundary = mimeinfo->parent->boundary; - boundary_len = strlen(boundary); - } - - if (mimeinfo->encoding_type == ENC_QUOTED_PRINTABLE) { - while (fgets(buf, sizeof(buf), infp) != NULL && - (!boundary || - !IS_BOUNDARY(buf, boundary, boundary_len))) { - gint len; - len = qp_decode_line(buf); - fwrite(buf, len, 1, outfp); - } - } else if (mimeinfo->encoding_type == ENC_BASE64) { - gchar outbuf[BUFFSIZE]; - gint len; - Base64Decoder *decoder; - gboolean uncanonicalize = FALSE; - FILE *tmpfp = outfp; - ContentType content_type; - - content_type = procmime_scan_mime_type(mimeinfo->content_type); - if (content_type == MIME_TEXT || - content_type == MIME_TEXT_HTML || - content_type == MIME_MESSAGE_RFC822) { - uncanonicalize = TRUE; - tmpfp = my_tmpfile(); - if (!tmpfp) { - perror("tmpfile"); - if (tmp_file) fclose(outfp); - return NULL; - } - } - - decoder = base64_decoder_new(); - while (fgets(buf, sizeof(buf), infp) != NULL && - (!boundary || - !IS_BOUNDARY(buf, boundary, boundary_len))) { - len = base64_decoder_decode(decoder, buf, outbuf); - if (len < 0) { - g_warning("Bad BASE64 content\n"); - break; - } - fwrite(outbuf, sizeof(gchar), len, tmpfp); - } - base64_decoder_free(decoder); - - if (uncanonicalize) { - rewind(tmpfp); - while (fgets(buf, sizeof(buf), tmpfp) != NULL) { - strcrchomp(buf); - fputs(buf, outfp); - } - fclose(tmpfp); - } - } else if (mimeinfo->encoding_type == ENC_X_UUENCODE) { - gchar outbuf[BUFFSIZE]; - gint len; - gboolean flag = FALSE; - - while (fgets(buf, sizeof(buf), infp) != NULL && - (!boundary || - !IS_BOUNDARY(buf, boundary, boundary_len))) { - if(!flag && strncmp(buf,"begin ", 6)) continue; - - if (flag) { - len = fromuutobits(outbuf, buf); - if (len <= 0) { - if (len < 0) - g_warning("Bad UUENCODE content(%d)\n", len); - break; - } - fwrite(outbuf, sizeof(gchar), len, outfp); - } else - flag = TRUE; - } - } else { - while (fgets(buf, sizeof(buf), infp) != NULL && - (!boundary || - !IS_BOUNDARY(buf, boundary, boundary_len))) { - fputs(buf, outfp); - } - } - - if (tmp_file) rewind(outfp); - return outfp; -} - -gint procmime_get_part(const gchar *outfile, const gchar *infile, - MimeInfo *mimeinfo) -{ - FILE *infp; - gint ret; - - g_return_val_if_fail(outfile != NULL, -1); - g_return_val_if_fail(infile != NULL, -1); - g_return_val_if_fail(mimeinfo != NULL, -1); - - if ((infp = g_fopen(infile, "rb")) == NULL) { - FILE_OP_ERROR(infile, "fopen"); - return -1; - } - ret = procmime_get_part_fp(outfile, infp, mimeinfo); - fclose(infp); - - return ret; -} - -gint procmime_get_part_fp(const gchar *outfile, FILE *infp, MimeInfo *mimeinfo) -{ - FILE *outfp; - gchar buf[BUFFSIZE]; - - g_return_val_if_fail(outfile != NULL, -1); - g_return_val_if_fail(infp != NULL, -1); - g_return_val_if_fail(mimeinfo != NULL, -1); - - if (fseek(infp, mimeinfo->fpos, SEEK_SET) < 0) { - FILE_OP_ERROR("procmime_get_part_fp()", "fseek"); - return -1; - } - if ((outfp = g_fopen(outfile, "wb")) == NULL) { - FILE_OP_ERROR(outfile, "fopen"); - return -1; - } - - while (fgets(buf, sizeof(buf), infp) != NULL) - if (buf[0] == '\r' || buf[0] == '\n') break; - - procmime_decode_content(outfp, infp, mimeinfo); - - if (fclose(outfp) == EOF) { - FILE_OP_ERROR(outfile, "fclose"); - g_unlink(outfile); - return -1; - } - - return 0; -} - -FILE *procmime_get_text_content(MimeInfo *mimeinfo, FILE *infp, - const gchar *encoding) -{ - FILE *tmpfp, *outfp; - const gchar *src_encoding; - gboolean conv_fail = FALSE; - gchar buf[BUFFSIZE]; - - g_return_val_if_fail(mimeinfo != NULL, NULL); - g_return_val_if_fail(infp != NULL, NULL); - g_return_val_if_fail(mimeinfo->mime_type == MIME_TEXT || - mimeinfo->mime_type == MIME_TEXT_HTML, NULL); - - if (fseek(infp, mimeinfo->fpos, SEEK_SET) < 0) { - perror("fseek"); - return NULL; - } - - while (fgets(buf, sizeof(buf), infp) != NULL) - if (buf[0] == '\r' || buf[0] == '\n') break; - - tmpfp = procmime_decode_content(NULL, infp, mimeinfo); - if (!tmpfp) - return NULL; - - if ((outfp = my_tmpfile()) == NULL) { - perror("tmpfile"); - fclose(tmpfp); - return NULL; - } - - src_encoding = prefs_common.force_charset - ? prefs_common.force_charset : mimeinfo->charset; - - if (mimeinfo->mime_type == MIME_TEXT) { - while (fgets(buf, sizeof(buf), tmpfp) != NULL) { - gchar *str; - - str = conv_codeset_strdup(buf, src_encoding, encoding); - if (str) { - fputs(str, outfp); - g_free(str); - } else { - conv_fail = TRUE; - fputs(buf, outfp); - } - } - } else if (mimeinfo->mime_type == MIME_TEXT_HTML) { - HTMLParser *parser; - CodeConverter *conv; - const gchar *str; - - conv = conv_code_converter_new(src_encoding, encoding); - parser = html_parser_new(tmpfp, conv); - while ((str = html_parse(parser)) != NULL) { - fputs(str, outfp); - } - html_parser_destroy(parser); - conv_code_converter_destroy(conv); - } - - if (conv_fail) - g_warning(_("procmime_get_text_content(): Code conversion failed.\n")); - - fclose(tmpfp); - rewind(outfp); - - return outfp; -} - -/* search the first text part of (multipart) MIME message, - decode, convert it and output to outfp. */ -FILE *procmime_get_first_text_content(MsgInfo *msginfo, const gchar *encoding) -{ - FILE *infp, *outfp = NULL; - MimeInfo *mimeinfo, *partinfo; - - g_return_val_if_fail(msginfo != NULL, NULL); - - mimeinfo = procmime_scan_message(msginfo); - if (!mimeinfo) return NULL; - - if ((infp = procmsg_open_message(msginfo)) == NULL) { - procmime_mimeinfo_free_all(mimeinfo); - return NULL; - } - - partinfo = mimeinfo; - while (partinfo && partinfo->mime_type != MIME_TEXT) - partinfo = procmime_mimeinfo_next(partinfo); - if (!partinfo) { - partinfo = mimeinfo; - while (partinfo && partinfo->mime_type != MIME_TEXT_HTML) - partinfo = procmime_mimeinfo_next(partinfo); - } - - if (partinfo) - outfp = procmime_get_text_content(partinfo, infp, encoding); - - fclose(infp); - procmime_mimeinfo_free_all(mimeinfo); - - return outfp; -} - -gboolean procmime_find_string_part(MimeInfo *mimeinfo, const gchar *filename, - const gchar *str, StrFindFunc find_func) -{ - - FILE *infp, *outfp; - gchar buf[BUFFSIZE]; - - g_return_val_if_fail(mimeinfo != NULL, FALSE); - g_return_val_if_fail(mimeinfo->mime_type == MIME_TEXT || - mimeinfo->mime_type == MIME_TEXT_HTML, FALSE); - g_return_val_if_fail(str != NULL, FALSE); - g_return_val_if_fail(find_func != NULL, FALSE); - - if ((infp = g_fopen(filename, "rb")) == NULL) { - FILE_OP_ERROR(filename, "fopen"); - return FALSE; - } - - outfp = procmime_get_text_content(mimeinfo, infp, NULL); - fclose(infp); - - if (!outfp) - return FALSE; - - while (fgets(buf, sizeof(buf), outfp) != NULL) { - strretchomp(buf); - if (find_func(buf, str)) { - fclose(outfp); - return TRUE; - } - } - - fclose(outfp); - - return FALSE; -} - -gboolean procmime_find_string(MsgInfo *msginfo, const gchar *str, - StrFindFunc find_func) -{ - MimeInfo *mimeinfo; - MimeInfo *partinfo; - gchar *filename; - gboolean found = FALSE; - - g_return_val_if_fail(msginfo != NULL, FALSE); - g_return_val_if_fail(str != NULL, FALSE); - g_return_val_if_fail(find_func != NULL, FALSE); - - filename = procmsg_get_message_file(msginfo); - if (!filename) return FALSE; - mimeinfo = procmime_scan_message(msginfo); - - for (partinfo = mimeinfo; partinfo != NULL; - partinfo = procmime_mimeinfo_next(partinfo)) { - if (partinfo->mime_type == MIME_TEXT || - partinfo->mime_type == MIME_TEXT_HTML) { - if (procmime_find_string_part - (partinfo, filename, str, find_func) == TRUE) { - found = TRUE; - break; - } - } - } - - procmime_mimeinfo_free_all(mimeinfo); - g_free(filename); - - return found; -} - -gchar *procmime_get_part_file_name(MimeInfo *mimeinfo) -{ - gchar *base; - const gchar *base_; - - base_ = mimeinfo->filename ? mimeinfo->filename - : mimeinfo->name ? mimeinfo->name : "mimetmp"; - base_ = g_basename(base_); - if (*base_ == '\0') base_ = "mimetmp"; - base = conv_filename_from_utf8(base_); - subst_for_filename(base); - - return base; -} - -gchar *procmime_get_tmp_file_name(MimeInfo *mimeinfo) -{ - static guint32 id = 0; - gchar *base; - gchar *filename; - gchar f_prefix[10]; - - g_return_val_if_fail(mimeinfo != NULL, NULL); - - g_snprintf(f_prefix, sizeof(f_prefix), "%08x.", id++); - - if (MIME_TEXT_HTML == mimeinfo->mime_type) - base = g_strdup("mimetmp.html"); - else - base = procmime_get_part_file_name(mimeinfo); - - filename = g_strconcat(get_mime_tmp_dir(), G_DIR_SEPARATOR_S, - f_prefix, base, NULL); - - g_free(base); - - return filename; -} - -ContentType procmime_scan_mime_type(const gchar *mime_type) -{ - ContentType type; - - if (!g_ascii_strncasecmp(mime_type, "text/html", 9)) - type = MIME_TEXT_HTML; - else if (!g_ascii_strncasecmp(mime_type, "text/", 5)) - type = MIME_TEXT; - else if (!g_ascii_strncasecmp(mime_type, "message/rfc822", 14)) - type = MIME_MESSAGE_RFC822; - else if (!g_ascii_strncasecmp(mime_type, "message/", 8)) - type = MIME_TEXT; - else if (!g_ascii_strncasecmp(mime_type, "application/octet-stream", - 24)) - type = MIME_APPLICATION_OCTET_STREAM; - else if (!g_ascii_strncasecmp(mime_type, "application/", 12)) - type = MIME_APPLICATION; - else if (!g_ascii_strncasecmp(mime_type, "multipart/", 10)) - type = MIME_MULTIPART; - else if (!g_ascii_strncasecmp(mime_type, "image/", 6)) - type = MIME_IMAGE; - else if (!g_ascii_strncasecmp(mime_type, "audio/", 6)) - type = MIME_AUDIO; - else if (!g_ascii_strcasecmp(mime_type, "text")) - type = MIME_TEXT; - else - type = MIME_UNKNOWN; - - return type; -} - -static GList *mime_type_list = NULL; - -gchar *procmime_get_mime_type(const gchar *filename) -{ - static GHashTable *mime_type_table = NULL; - MimeType *mime_type; - const gchar *p; - gchar *ext; - - if (!mime_type_table) { - mime_type_table = procmime_get_mime_type_table(); - if (!mime_type_table) return NULL; - } - - filename = g_basename(filename); - p = strrchr(filename, '.'); - if (!p) return NULL; - - Xstrdup_a(ext, p + 1, return NULL); - g_strdown(ext); - mime_type = g_hash_table_lookup(mime_type_table, ext); - if (mime_type) { - gchar *str; - - str = g_strconcat(mime_type->type, "/", mime_type->sub_type, - NULL); - return str; - } - - return NULL; -} - -static GHashTable *procmime_get_mime_type_table(void) -{ - GHashTable *table = NULL; - GList *cur; - MimeType *mime_type; - gchar **exts; - - if (!mime_type_list) { - GList *list; - gchar *dir; - - mime_type_list = - procmime_get_mime_type_list(SYSCONFDIR "/mime.types"); - if (!mime_type_list) { - list = procmime_get_mime_type_list("/etc/mime.types"); - mime_type_list = g_list_concat(mime_type_list, list); - } - dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, - "mime.types", NULL); - list = procmime_get_mime_type_list(dir); - g_free(dir); - mime_type_list = g_list_concat(mime_type_list, list); - - if (!mime_type_list) { - g_warning("mime.types not found\n"); - return NULL; - } - } - - table = g_hash_table_new(g_str_hash, g_str_equal); - - for (cur = mime_type_list; cur != NULL; cur = cur->next) { - gint i; - gchar *key; - - mime_type = (MimeType *)cur->data; - - if (!mime_type->extension) continue; - - exts = g_strsplit(mime_type->extension, " ", 16); - for (i = 0; exts[i] != NULL; i++) { - /* make the key case insensitive */ - g_strdown(exts[i]); - /* use previously dup'd key on overwriting */ - if (g_hash_table_lookup(table, exts[i])) - key = exts[i]; - else - key = g_strdup(exts[i]); - g_hash_table_insert(table, key, mime_type); - } - g_strfreev(exts); - } - - return table; -} - -static GList *procmime_get_mime_type_list(const gchar *file) -{ - GList *list = NULL; - FILE *fp; - gchar buf[BUFFSIZE]; - gchar *p; - gchar *delim; - MimeType *mime_type; - - if ((fp = g_fopen(file, "rb")) == NULL) return NULL; - - debug_print("Reading %s ...\n", file); - - while (fgets(buf, sizeof(buf), fp) != NULL) { - p = strchr(buf, '#'); - if (p) *p = '\0'; - g_strstrip(buf); - - p = buf; - while (*p && !g_ascii_isspace(*p)) p++; - if (*p) { - *p = '\0'; - p++; - } - delim = strchr(buf, '/'); - if (delim == NULL) continue; - *delim = '\0'; - - mime_type = g_new(MimeType, 1); - mime_type->type = g_strdup(buf); - mime_type->sub_type = g_strdup(delim + 1); - - while (*p && g_ascii_isspace(*p)) p++; - if (*p) - mime_type->extension = g_strdup(p); - else - mime_type->extension = NULL; - - list = g_list_append(list, mime_type); - } - - fclose(fp); - - if (!list) - g_warning("Can't read mime.types\n"); - - return list; -} - -EncodingType procmime_get_encoding_for_charset(const gchar *charset) -{ - if (!charset) - return ENC_8BIT; - else if (!g_ascii_strncasecmp(charset, "ISO-2022-", 9) || - !g_ascii_strcasecmp(charset, "US-ASCII")) - return ENC_7BIT; - else if (!g_ascii_strcasecmp(charset, "ISO-8859-5") || - !g_ascii_strncasecmp(charset, "KOI8-", 5) || - !g_ascii_strcasecmp(charset, "Windows-1251")) - return ENC_8BIT; - else if (!g_ascii_strncasecmp(charset, "ISO-8859-", 9)) - return ENC_QUOTED_PRINTABLE; - else - return ENC_8BIT; -} - -EncodingType procmime_get_encoding_for_text_file(const gchar *file) -{ - FILE *fp; - guchar buf[BUFFSIZE]; - size_t len; - size_t octet_chars = 0; - size_t total_len = 0; - gfloat octet_percentage; - - if ((fp = g_fopen(file, "rb")) == NULL) { - FILE_OP_ERROR(file, "fopen"); - return ENC_UNKNOWN; - } - - while ((len = fread(buf, sizeof(guchar), sizeof(buf), fp)) > 0) { - guchar *p; - gint i; - - for (p = buf, i = 0; i < len; ++p, ++i) { - if (*p & 0x80) - ++octet_chars; - } - total_len += len; - } - - fclose(fp); - - if (total_len > 0) - octet_percentage = (gfloat)octet_chars / (gfloat)total_len; - else - octet_percentage = 0.0; - - debug_print("procmime_get_encoding_for_text_file(): " - "8bit chars: %d / %d (%f%%)\n", octet_chars, total_len, - 100.0 * octet_percentage); - - if (octet_percentage > 0.20) { - debug_print("using BASE64\n"); - return ENC_BASE64; - } else if (octet_chars > 0) { - debug_print("using quoted-printable\n"); - return ENC_QUOTED_PRINTABLE; - } else { - debug_print("using 7bit\n"); - return ENC_7BIT; - } -} - -const gchar *procmime_get_encoding_str(EncodingType encoding) -{ - static const gchar *encoding_str[] = { - "7bit", "8bit", "quoted-printable", "base64", "x-uuencode", - NULL - }; - - if (encoding >= ENC_7BIT && encoding <= ENC_UNKNOWN) - return encoding_str[encoding]; - else - return NULL; -} diff --git a/src/procmime.h b/src/procmime.h deleted file mode 100644 index fc2085a9..00000000 --- a/src/procmime.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __PROCMIME_H__ -#define __PROCMIME_H__ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <glib.h> -#include <stdio.h> - -typedef struct _MimeType MimeType; -typedef struct _MimeInfo MimeInfo; - -#include "procmsg.h" -#include "utils.h" - -typedef enum -{ - ENC_7BIT, - ENC_8BIT, - ENC_QUOTED_PRINTABLE, - ENC_BASE64, - ENC_X_UUENCODE, - ENC_UNKNOWN -} EncodingType; - -typedef enum -{ - MIME_TEXT, - MIME_TEXT_HTML, - MIME_MESSAGE_RFC822, - MIME_APPLICATION, - MIME_APPLICATION_OCTET_STREAM, - MIME_MULTIPART, - MIME_IMAGE, - MIME_AUDIO, - MIME_UNKNOWN -} ContentType; - -struct _MimeType -{ - gchar *type; - gchar *sub_type; - - gchar *extension; -}; - -/* - * An example of MimeInfo structure: - * - * multipart/mixed root <-+ parent - * | - * multipart/alternative children <-+ parent - * | - * text/plain children --+ - * | - * text/html next <-+ - * - * message/rfc822 next <-+ main - * | - * sub (capsulated message) - * - * image/jpeg next - */ - -struct _MimeInfo -{ - gchar *encoding; - - EncodingType encoding_type; - ContentType mime_type; - - gchar *content_type; - gchar *charset; - gchar *name; - gchar *boundary; - - gchar *content_disposition; - gchar *filename; - - glong fpos; - guint size; - guint content_size; - - MimeInfo *main; - MimeInfo *sub; - - MimeInfo *next; - MimeInfo *parent; - MimeInfo *children; - -#if USE_GPGME - MimeInfo *plaintext; - gchar *plaintextfile; - gchar *sigstatus; - gchar *sigstatus_full; -#endif - - gint level; -}; - -#define IS_BOUNDARY(s, bnd, len) \ - (bnd && s[0] == '-' && s[1] == '-' && !strncmp(s + 2, bnd, len)) - -/* MimeInfo handling */ - -MimeInfo *procmime_mimeinfo_new (void); -void procmime_mimeinfo_free_all (MimeInfo *mimeinfo); - -MimeInfo *procmime_mimeinfo_insert (MimeInfo *parent, - MimeInfo *mimeinfo); -void procmime_mimeinfo_replace (MimeInfo *old, - MimeInfo *new); - -MimeInfo *procmime_mimeinfo_next (MimeInfo *mimeinfo); - -MimeInfo *procmime_scan_message (MsgInfo *msginfo); -void procmime_scan_multipart_message (MimeInfo *mimeinfo, - FILE *fp); - -/* scan headers */ - -void procmime_scan_encoding (MimeInfo *mimeinfo, - const gchar *encoding); -void procmime_scan_content_type (MimeInfo *mimeinfo, - const gchar *content_type); -void procmime_scan_content_type_str (const gchar *content_type, - gchar **mime_type, - gchar **charset, - gchar **name, - gchar **boundary); -void procmime_scan_content_disposition (MimeInfo *mimeinfo, - const gchar *content_disposition); -MimeInfo *procmime_scan_mime_header (FILE *fp); - -FILE *procmime_decode_content (FILE *outfp, - FILE *infp, - MimeInfo *mimeinfo); -gint procmime_get_part (const gchar *outfile, - const gchar *infile, - MimeInfo *mimeinfo); -gint procmime_get_part_fp (const gchar *outfile, - FILE *infp, - MimeInfo *mimeinfo); -FILE *procmime_get_text_content (MimeInfo *mimeinfo, - FILE *infp, - const gchar *encoding); -FILE *procmime_get_first_text_content (MsgInfo *msginfo, - const gchar *encoding); - -gboolean procmime_find_string_part (MimeInfo *mimeinfo, - const gchar *filename, - const gchar *str, - StrFindFunc find_func); -gboolean procmime_find_string (MsgInfo *msginfo, - const gchar *str, - StrFindFunc find_func); - -gchar *procmime_get_part_file_name (MimeInfo *mimeinfo); -gchar *procmime_get_tmp_file_name (MimeInfo *mimeinfo); - -ContentType procmime_scan_mime_type (const gchar *mime_type); -gchar *procmime_get_mime_type (const gchar *filename); - -EncodingType procmime_get_encoding_for_charset (const gchar *charset); -EncodingType procmime_get_encoding_for_text_file(const gchar *file); -const gchar *procmime_get_encoding_str (EncodingType encoding); - -#endif /* __PROCMIME_H__ */ diff --git a/src/procmsg.c b/src/procmsg.c deleted file mode 100644 index 0ecae5b4..00000000 --- a/src/procmsg.c +++ /dev/null @@ -1,1446 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#include "defs.h" - -#include <glib.h> -#include <glib/gi18n.h> -#include <stdio.h> -#include <stdlib.h> - -#include "utils.h" -#include "procmsg.h" -#include "procheader.h" -#include "account.h" -#include "procmime.h" -#include "prefs_common.h" -#include "folder.h" -#include "codeconv.h" -#if USE_GPGME -# include "rfc2015.h" -#endif - -static void mark_sum_func (gpointer key, - gpointer value, - gpointer data); - -static GHashTable *procmsg_read_mark_file (FolderItem *item); -static void procmsg_write_mark_file (FolderItem *item, - GHashTable *mark_table); - -static FILE *procmsg_open_data_file (const gchar *file, - guint version, - DataOpenMode mode, - gchar *buf, - size_t buf_size); -static FILE *procmsg_open_cache_file_with_buffer(FolderItem *item, - DataOpenMode mode, - gchar *buf, - size_t buf_size); - -static gint procmsg_cmp_by_mark (gconstpointer a, - gconstpointer b); -static gint procmsg_cmp_by_unread (gconstpointer a, - gconstpointer b); -static gint procmsg_cmp_by_mime (gconstpointer a, - gconstpointer b); -static gint procmsg_cmp_by_label (gconstpointer a, - gconstpointer b); -static gint procmsg_cmp_by_number (gconstpointer a, - gconstpointer b); -static gint procmsg_cmp_by_size (gconstpointer a, - gconstpointer b); -static gint procmsg_cmp_by_date (gconstpointer a, - gconstpointer b); -static gint procmsg_cmp_by_from (gconstpointer a, - gconstpointer b); -static gint procmsg_cmp_by_to (gconstpointer a, - gconstpointer b); -static gint procmsg_cmp_by_subject (gconstpointer a, - gconstpointer b); - - -GHashTable *procmsg_msg_hash_table_create(GSList *mlist) -{ - GHashTable *msg_table; - - if (mlist == NULL) return NULL; - - msg_table = g_hash_table_new(NULL, g_direct_equal); - procmsg_msg_hash_table_append(msg_table, mlist); - - return msg_table; -} - -void procmsg_msg_hash_table_append(GHashTable *msg_table, GSList *mlist) -{ - GSList *cur; - MsgInfo *msginfo; - - if (msg_table == NULL || mlist == NULL) return; - - for (cur = mlist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - - g_hash_table_insert(msg_table, - GUINT_TO_POINTER(msginfo->msgnum), - msginfo); - } -} - -GHashTable *procmsg_to_folder_hash_table_create(GSList *mlist) -{ - GHashTable *msg_table; - GSList *cur; - MsgInfo *msginfo; - - if (mlist == NULL) return NULL; - - msg_table = g_hash_table_new(NULL, g_direct_equal); - - for (cur = mlist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - g_hash_table_insert(msg_table, msginfo->to_folder, msginfo); - } - - return msg_table; -} - -static gint procmsg_read_cache_data_str(FILE *fp, gchar **str) -{ - gchar buf[BUFFSIZE]; - gint ret = 0; - guint32 len; - - if (fread(&len, sizeof(len), 1, fp) == 1) { - if (len > G_MAXINT) - ret = -1; - else { - gchar *tmp = NULL; - - while (len > 0) { - size_t size = MIN(len, BUFFSIZE - 1); - - if (fread(buf, size, 1, fp) != 1) { - ret = -1; - if (tmp) g_free(tmp); - *str = NULL; - break; - } - - buf[size] = '\0'; - if (tmp) { - *str = g_strconcat(tmp, buf, NULL); - g_free(tmp); - tmp = *str; - } else - tmp = *str = g_strdup(buf); - - len -= size; - } - } - } else - ret = -1; - - if (ret < 0) - g_warning("Cache data is corrupted\n"); - - return ret; -} - -#define READ_CACHE_DATA(data, fp) \ -{ \ - if (procmsg_read_cache_data_str(fp, &data) < 0) { \ - procmsg_msginfo_free(msginfo); \ - procmsg_msg_list_free(mlist); \ - mlist = NULL; \ - break; \ - } \ -} - -#define READ_CACHE_DATA_INT(n, fp) \ -{ \ - guint32 idata; \ - \ - if (fread(&idata, sizeof(idata), 1, fp) != 1) { \ - g_warning("Cache data is corrupted\n"); \ - procmsg_msginfo_free(msginfo); \ - procmsg_msg_list_free(mlist); \ - mlist = NULL; \ - break; \ - } else \ - n = idata; \ -} - -GSList *procmsg_read_cache(FolderItem *item, gboolean scan_file) -{ - GSList *mlist = NULL; - GSList *last = NULL; - FILE *fp; - MsgInfo *msginfo; - MsgFlags default_flags; - gchar file_buf[BUFFSIZE]; - guint32 num; - guint refnum; - FolderType type; - - g_return_val_if_fail(item != NULL, NULL); - g_return_val_if_fail(item->folder != NULL, NULL); - type = FOLDER_TYPE(item->folder); - - default_flags.perm_flags = MSG_NEW|MSG_UNREAD; - default_flags.tmp_flags = 0; - if (type == F_MH || type == F_IMAP) { - if (item->stype == F_QUEUE) { - MSG_SET_TMP_FLAGS(default_flags, MSG_QUEUED); - } else if (item->stype == F_DRAFT) { - MSG_SET_TMP_FLAGS(default_flags, MSG_DRAFT); - } - } - if (type == F_IMAP) { - MSG_SET_TMP_FLAGS(default_flags, MSG_IMAP); - } else if (type == F_NEWS) { - MSG_SET_TMP_FLAGS(default_flags, MSG_NEWS); - } - - if (type == F_MH) { - gchar *path; - - path = folder_item_get_path(item); - if (change_dir(path) < 0) { - g_free(path); - return NULL; - } - g_free(path); - } - - if ((fp = procmsg_open_cache_file_with_buffer - (item, DATA_READ, file_buf, sizeof(file_buf))) == NULL) { - item->cache_dirty = TRUE; - return NULL; - } - - debug_print("Reading summary cache..."); - - while (fread(&num, sizeof(num), 1, fp) == 1) { - msginfo = g_new0(MsgInfo, 1); - msginfo->msgnum = num; - READ_CACHE_DATA_INT(msginfo->size, fp); - READ_CACHE_DATA_INT(msginfo->mtime, fp); - READ_CACHE_DATA_INT(msginfo->date_t, fp); - READ_CACHE_DATA_INT(msginfo->flags.tmp_flags, fp); - - READ_CACHE_DATA(msginfo->fromname, fp); - - READ_CACHE_DATA(msginfo->date, fp); - READ_CACHE_DATA(msginfo->from, fp); - READ_CACHE_DATA(msginfo->to, fp); - READ_CACHE_DATA(msginfo->newsgroups, fp); - READ_CACHE_DATA(msginfo->subject, fp); - READ_CACHE_DATA(msginfo->msgid, fp); - READ_CACHE_DATA(msginfo->inreplyto, fp); - - READ_CACHE_DATA_INT(refnum, fp); - for (; refnum != 0; refnum--) { - gchar *ref; - - READ_CACHE_DATA(ref, fp); - msginfo->references = - g_slist_prepend(msginfo->references, ref); - } - if (msginfo->references) - msginfo->references = - g_slist_reverse(msginfo->references); - - MSG_SET_PERM_FLAGS(msginfo->flags, default_flags.perm_flags); - MSG_SET_TMP_FLAGS(msginfo->flags, default_flags.tmp_flags); - - /* if the message file doesn't exist or is changed, - don't add the data */ - if ((type == F_MH && scan_file && - folder_item_is_msg_changed(item, msginfo)) || num == 0) { - procmsg_msginfo_free(msginfo); - item->cache_dirty = TRUE; - } else { - msginfo->folder = item; - - if (!mlist) - last = mlist = g_slist_append(NULL, msginfo); - else { - last = g_slist_append(last, msginfo); - last = last->next; - } - } - } - - fclose(fp); - - debug_print("done.\n"); - - return mlist; -} - -#undef READ_CACHE_DATA -#undef READ_CACHE_DATA_INT - -static void mark_unset_new_func(gpointer key, gpointer value, gpointer data) -{ - MSG_UNSET_PERM_FLAGS(*((MsgFlags *)value), MSG_NEW); -} - -void procmsg_set_flags(GSList *mlist, FolderItem *item) -{ - GSList *cur; - gint new = 0, unread = 0, total = 0; - gint lastnum = 0; - gint unflagged = 0; - gboolean mark_queue_exist; - MsgInfo *msginfo; - GHashTable *mark_table; - MsgFlags *flags; - - g_return_if_fail(item != NULL); - g_return_if_fail(item->folder != NULL); - - debug_print("Marking the messages...\n"); - - mark_queue_exist = (item->mark_queue != NULL); - mark_table = procmsg_read_mark_file(item); - if (!mark_table) { - item->new = item->unread = item->total = g_slist_length(mlist); - item->updated = TRUE; - item->mark_dirty = TRUE; - return; - } - - /* unset new flags if new (unflagged) messages exist */ - if (!mark_queue_exist) { - for (cur = mlist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - flags = g_hash_table_lookup - (mark_table, GUINT_TO_POINTER(msginfo->msgnum)); - if (!flags) { - g_hash_table_foreach(mark_table, - mark_unset_new_func, NULL); - item->mark_dirty = TRUE; - break; - } - } - } - - for (cur = mlist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - - if (lastnum < msginfo->msgnum) - lastnum = msginfo->msgnum; - - flags = g_hash_table_lookup - (mark_table, GUINT_TO_POINTER(msginfo->msgnum)); - - if (flags != NULL) { - /* add the permanent flags only */ - msginfo->flags.perm_flags = flags->perm_flags; - if (MSG_IS_NEW(*flags)) - ++new; - if (MSG_IS_UNREAD(*flags)) - ++unread; - if (FOLDER_TYPE(item->folder) == F_IMAP) { - MSG_SET_TMP_FLAGS(msginfo->flags, MSG_IMAP); - } else if (FOLDER_TYPE(item->folder) == F_NEWS) { - MSG_SET_TMP_FLAGS(msginfo->flags, MSG_NEWS); - } - } else { - ++unflagged; - ++new; - ++unread; - } - - ++total; - } - - item->new = new; - item->unread = unread; - item->total = total; - item->unmarked_num = unflagged; - item->last_num = lastnum; - item->updated = TRUE; - - if (unflagged > 0) - item->mark_dirty = TRUE; - - debug_print("new: %d unread: %d unflagged: %d total: %d\n", - new, unread, unflagged, total); - - hash_free_value_mem(mark_table); - g_hash_table_destroy(mark_table); -} - -static FolderSortType cmp_func_sort_type; - -GSList *procmsg_sort_msg_list(GSList *mlist, FolderSortKey sort_key, - FolderSortType sort_type) -{ - GCompareFunc cmp_func; - - switch (sort_key) { - case SORT_BY_MARK: - cmp_func = procmsg_cmp_by_mark; break; - case SORT_BY_UNREAD: - cmp_func = procmsg_cmp_by_unread; break; - case SORT_BY_MIME: - cmp_func = procmsg_cmp_by_mime; break; - case SORT_BY_LABEL: - cmp_func = procmsg_cmp_by_label; break; - case SORT_BY_NUMBER: - cmp_func = procmsg_cmp_by_number; break; - case SORT_BY_SIZE: - cmp_func = procmsg_cmp_by_size; break; - case SORT_BY_DATE: - cmp_func = procmsg_cmp_by_date; break; - case SORT_BY_FROM: - cmp_func = procmsg_cmp_by_from; break; - case SORT_BY_SUBJECT: - cmp_func = procmsg_cmp_by_subject; break; - case SORT_BY_TO: - cmp_func = procmsg_cmp_by_to; break; - default: - return mlist; - } - - cmp_func_sort_type = sort_type; - - mlist = g_slist_sort(mlist, cmp_func); - - return mlist; -} - -gint procmsg_get_last_num_in_msg_list(GSList *mlist) -{ - GSList *cur; - MsgInfo *msginfo; - gint last = 0; - - for (cur = mlist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - if (msginfo && msginfo->msgnum > last) - last = msginfo->msgnum; - } - - return last; -} - -void procmsg_msg_list_free(GSList *mlist) -{ - GSList *cur; - MsgInfo *msginfo; - - for (cur = mlist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - procmsg_msginfo_free(msginfo); - } - g_slist_free(mlist); -} - -void procmsg_write_cache(MsgInfo *msginfo, FILE *fp) -{ - MsgTmpFlags flags = msginfo->flags.tmp_flags & MSG_CACHED_FLAG_MASK; - GSList *cur; - - WRITE_CACHE_DATA_INT(msginfo->msgnum, fp); - WRITE_CACHE_DATA_INT(msginfo->size, fp); - WRITE_CACHE_DATA_INT(msginfo->mtime, fp); - WRITE_CACHE_DATA_INT(msginfo->date_t, fp); - WRITE_CACHE_DATA_INT(flags, fp); - - WRITE_CACHE_DATA(msginfo->fromname, fp); - - WRITE_CACHE_DATA(msginfo->date, fp); - WRITE_CACHE_DATA(msginfo->from, fp); - WRITE_CACHE_DATA(msginfo->to, fp); - WRITE_CACHE_DATA(msginfo->newsgroups, fp); - WRITE_CACHE_DATA(msginfo->subject, fp); - WRITE_CACHE_DATA(msginfo->msgid, fp); - WRITE_CACHE_DATA(msginfo->inreplyto, fp); - - WRITE_CACHE_DATA_INT(g_slist_length(msginfo->references), fp); - for (cur = msginfo->references; cur != NULL; cur = cur->next) { - WRITE_CACHE_DATA((gchar *)cur->data, fp); - } -} - -void procmsg_write_flags(MsgInfo *msginfo, FILE *fp) -{ - MsgPermFlags flags = msginfo->flags.perm_flags; - - WRITE_CACHE_DATA_INT(msginfo->msgnum, fp); - WRITE_CACHE_DATA_INT(flags, fp); -} - -void procmsg_flush_mark_queue(FolderItem *item, FILE *fp) -{ - MsgInfo *flaginfo; - - g_return_if_fail(item != NULL); - g_return_if_fail(fp != NULL); - - if (item->mark_queue) - debug_print("flushing mark_queue...\n"); - - while (item->mark_queue != NULL) { - flaginfo = (MsgInfo *)item->mark_queue->data; - procmsg_write_flags(flaginfo, fp); - procmsg_msginfo_free(flaginfo); - item->mark_queue = g_slist_remove(item->mark_queue, flaginfo); - } -} - -void procmsg_add_mark_queue(FolderItem *item, gint num, MsgFlags flags) -{ - MsgInfo *queue_msginfo; - - queue_msginfo = g_new0(MsgInfo, 1); - queue_msginfo->msgnum = num; - queue_msginfo->flags = flags; - item->mark_queue = g_slist_append - (item->mark_queue, queue_msginfo); - return; -} - -void procmsg_add_flags(FolderItem *item, gint num, MsgFlags flags) -{ - FILE *fp; - MsgInfo msginfo; - - g_return_if_fail(item != NULL); - - if (item->opened) { - procmsg_add_mark_queue(item, num, flags); - return; - } - - if ((fp = procmsg_open_mark_file(item, DATA_APPEND)) == NULL) { - g_warning(_("can't open mark file\n")); - return; - } - - msginfo.msgnum = num; - msginfo.flags = flags; - - procmsg_write_flags(&msginfo, fp); - fclose(fp); -} - -struct MarkSum { - gint *new; - gint *unread; - gint *total; - gint *min; - gint *max; - gint first; -}; - -static void mark_sum_func(gpointer key, gpointer value, gpointer data) -{ - MsgFlags *flags = value; - gint num = GPOINTER_TO_INT(key); - struct MarkSum *marksum = data; - - if (marksum->first <= num) { - if (MSG_IS_NEW(*flags)) (*marksum->new)++; - if (MSG_IS_UNREAD(*flags)) (*marksum->unread)++; - if (num > *marksum->max) *marksum->max = num; - if (num < *marksum->min || *marksum->min == 0) *marksum->min = num; - (*marksum->total)++; - } - - g_free(flags); -} - -void procmsg_get_mark_sum(FolderItem *item, - gint *new, gint *unread, gint *total, - gint *min, gint *max, - gint first) -{ - GHashTable *mark_table; - struct MarkSum marksum; - - *new = *unread = *total = *min = *max = 0; - marksum.new = new; - marksum.unread = unread; - marksum.total = total; - marksum.min = min; - marksum.max = max; - marksum.first = first; - - mark_table = procmsg_read_mark_file(item); - - if (mark_table) { - g_hash_table_foreach(mark_table, mark_sum_func, &marksum); - g_hash_table_destroy(mark_table); - } -} - -static GHashTable *procmsg_read_mark_file(FolderItem *item) -{ - FILE *fp; - GHashTable *mark_table = NULL; - guint32 idata; - guint num; - MsgFlags *flags; - MsgPermFlags perm_flags; - GSList *cur; - - if ((fp = procmsg_open_mark_file(item, DATA_READ)) == NULL) - return NULL; - - mark_table = g_hash_table_new(NULL, g_direct_equal); - - while (fread(&idata, sizeof(idata), 1, fp) == 1) { - num = idata; - if (fread(&idata, sizeof(idata), 1, fp) != 1) break; - perm_flags = idata; - - flags = g_hash_table_lookup(mark_table, GUINT_TO_POINTER(num)); - if (flags != NULL) - g_free(flags); - - flags = g_new0(MsgFlags, 1); - flags->perm_flags = perm_flags; - - g_hash_table_insert(mark_table, GUINT_TO_POINTER(num), flags); - } - - fclose(fp); - - if (item->mark_queue) { - g_hash_table_foreach(mark_table, mark_unset_new_func, NULL); - item->mark_dirty = TRUE; - } - - for (cur = item->mark_queue; cur != NULL; cur = cur->next) { - MsgInfo *msginfo = (MsgInfo *)cur->data; - - flags = g_hash_table_lookup(mark_table, - GUINT_TO_POINTER(msginfo->msgnum)); - if (flags != NULL) - g_free(flags); - - flags = g_new0(MsgFlags, 1); - flags->perm_flags = msginfo->flags.perm_flags; - - g_hash_table_insert(mark_table, - GUINT_TO_POINTER(msginfo->msgnum), flags); - - } - - if (item->mark_queue && !item->opened) { - procmsg_write_mark_file(item, mark_table); - procmsg_msg_list_free(item->mark_queue); - item->mark_queue = NULL; - item->mark_dirty = FALSE; - } - - return mark_table; -} - -static void write_mark_func(gpointer key, gpointer value, gpointer data) -{ - MsgInfo msginfo; - - msginfo.msgnum = GPOINTER_TO_UINT(key); - msginfo.flags.perm_flags = ((MsgFlags *)value)->perm_flags; - procmsg_write_flags(&msginfo, (FILE *)data); -} - -static void procmsg_write_mark_file(FolderItem *item, GHashTable *mark_table) -{ - FILE *fp; - - fp = procmsg_open_mark_file(item, DATA_WRITE); - g_hash_table_foreach(mark_table, write_mark_func, fp); - fclose(fp); -} - -static FILE *procmsg_open_data_file(const gchar *file, guint version, - DataOpenMode mode, - gchar *buf, size_t buf_size) -{ - FILE *fp; - guint32 data_ver; - - g_return_val_if_fail(file != NULL, NULL); - - if (mode == DATA_WRITE) { - if ((fp = g_fopen(file, "wb")) == NULL) { - FILE_OP_ERROR(file, "fopen"); - return NULL; - } - if (change_file_mode_rw(fp, file) < 0) - FILE_OP_ERROR(file, "chmod"); - - WRITE_CACHE_DATA_INT(version, fp); - return fp; - } - - /* check version */ - if ((fp = g_fopen(file, "rb")) == NULL) - debug_print("Mark/Cache file '%s' not found\n", file); - else { - if (buf && buf_size > 0) - setvbuf(fp, buf, _IOFBF, buf_size); - if (fread(&data_ver, sizeof(data_ver), 1, fp) != 1 || - version != data_ver) { - g_message("%s: Mark/Cache version is different (%u != %u). Discarding it.\n", - file, data_ver, version); - fclose(fp); - fp = NULL; - } - } - - if (mode == DATA_READ) - return fp; - - if (fp) { - /* reopen with append mode */ - fclose(fp); - if ((fp = g_fopen(file, "ab")) == NULL) - FILE_OP_ERROR(file, "fopen"); - } else { - /* open with overwrite mode if mark file doesn't exist or - version is different */ - fp = procmsg_open_data_file(file, version, DATA_WRITE, buf, - buf_size); - } - - return fp; -} - -static FILE *procmsg_open_cache_file_with_buffer(FolderItem *item, - DataOpenMode mode, - gchar *buf, size_t buf_size) -{ - gchar *cachefile; - FILE *fp; - - cachefile = folder_item_get_cache_file(item); - fp = procmsg_open_data_file(cachefile, CACHE_VERSION, mode, buf, - buf_size); - g_free(cachefile); - - return fp; -} - -FILE *procmsg_open_cache_file(FolderItem *item, DataOpenMode mode) -{ - gchar *cachefile; - FILE *fp; - - cachefile = folder_item_get_cache_file(item); - fp = procmsg_open_data_file(cachefile, CACHE_VERSION, mode, NULL, 0); - g_free(cachefile); - - return fp; -} - -FILE *procmsg_open_mark_file(FolderItem *item, DataOpenMode mode) -{ - gchar *markfile; - FILE *fp; - - markfile = folder_item_get_mark_file(item); - fp = procmsg_open_data_file(markfile, MARK_VERSION, mode, NULL, 0); - g_free(markfile); - - return fp; -} - -void procmsg_clear_cache(FolderItem *item) -{ - FILE *fp; - - fp = procmsg_open_cache_file(item, DATA_WRITE); - if (fp) - fclose(fp); -} - -void procmsg_clear_mark(FolderItem *item) -{ - FILE *fp; - - fp = procmsg_open_mark_file(item, DATA_WRITE); - if (fp) - fclose(fp); -} - -/* return the reversed thread tree */ -GNode *procmsg_get_thread_tree(GSList *mlist) -{ - GNode *root, *parent, *node, *next; - GHashTable *table; - MsgInfo *msginfo; - const gchar *msgid; - GSList *reflist; - - root = g_node_new(NULL); - table = g_hash_table_new(g_str_hash, g_str_equal); - - for (; mlist != NULL; mlist = mlist->next) { - msginfo = (MsgInfo *)mlist->data; - parent = root; - - /* only look for the real parent first */ - if (msginfo->inreplyto) { - parent = g_hash_table_lookup(table, msginfo->inreplyto); - if (parent == NULL) - parent = root; - } - - node = g_node_insert_data_before - (parent, parent == root ? parent->children : NULL, - msginfo); - if ((msgid = msginfo->msgid) && - g_hash_table_lookup(table, msgid) == NULL) - g_hash_table_insert(table, (gchar *)msgid, node); - } - - /* complete the unfinished threads */ - for (node = root->children; node != NULL; ) { - next = node->next; - msginfo = (MsgInfo *)node->data; - parent = NULL; - - if (msginfo->inreplyto) - parent = g_hash_table_lookup(table, msginfo->inreplyto); - - /* try looking for the indirect parent */ - if (!parent && msginfo->references) { - for (reflist = msginfo->references; - reflist != NULL; reflist = reflist->next) - if ((parent = g_hash_table_lookup - (table, reflist->data)) != NULL) - break; - } - - /* node should not be the parent, and node should not - be an ancestor of parent (circular reference) */ - if (parent && parent != node && - !g_node_is_ancestor(node, parent)) { - g_node_unlink(node); - g_node_insert_before - (parent, parent->children, node); - } - node = next; - } - - g_hash_table_destroy(table); - - return root; -} - -gint procmsg_move_messages(GSList *mlist) -{ - GSList *cur, *movelist = NULL; - MsgInfo *msginfo; - FolderItem *dest = NULL; - GHashTable *hash; - gint val = 0; - - if (!mlist) return 0; - - hash = procmsg_to_folder_hash_table_create(mlist); - folder_item_scan_foreach(hash); - g_hash_table_destroy(hash); - - for (cur = mlist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - if (!dest) { - dest = msginfo->to_folder; - movelist = g_slist_append(movelist, msginfo); - } else if (dest == msginfo->to_folder) { - movelist = g_slist_append(movelist, msginfo); - } else { - val = folder_item_move_msgs(dest, movelist); - g_slist_free(movelist); - movelist = NULL; - if (val == -1) - return val; - dest = msginfo->to_folder; - movelist = g_slist_append(movelist, msginfo); - } - } - - if (movelist) { - val = folder_item_move_msgs(dest, movelist); - g_slist_free(movelist); - } - - return val == -1 ? -1 : 0; -} - -gint procmsg_copy_messages(GSList *mlist) -{ - GSList *cur, *copylist = NULL; - MsgInfo *msginfo; - FolderItem *dest = NULL; - GHashTable *hash; - gint val = 0; - - if (!mlist) return 0; - - hash = procmsg_to_folder_hash_table_create(mlist); - folder_item_scan_foreach(hash); - g_hash_table_destroy(hash); - - for (cur = mlist; cur != NULL; cur = cur->next) { - msginfo = (MsgInfo *)cur->data; - if (!dest) { - dest = msginfo->to_folder; - copylist = g_slist_append(copylist, msginfo); - } else if (dest == msginfo->to_folder) { - copylist = g_slist_append(copylist, msginfo); - } else { - val = folder_item_copy_msgs(dest, copylist); - g_slist_free(copylist); - copylist = NULL; - if (val == -1) - return val; - dest = msginfo->to_folder; - copylist = g_slist_append(copylist, msginfo); - } - } - - if (copylist) { - val = folder_item_copy_msgs(dest, copylist); - g_slist_free(copylist); - } - - return val == -1 ? -1 : 0; -} - -gchar *procmsg_get_message_file_path(MsgInfo *msginfo) -{ - gchar *path, *file; - - g_return_val_if_fail(msginfo != NULL, NULL); - - if (msginfo->plaintext_file) - file = g_strdup(msginfo->plaintext_file); - else if (msginfo->file_path) - return g_strdup(msginfo->file_path); - else { - path = folder_item_get_path(msginfo->folder); - file = g_strconcat(path, G_DIR_SEPARATOR_S, - itos(msginfo->msgnum), NULL); - g_free(path); - } - - return file; -} - -gchar *procmsg_get_message_file(MsgInfo *msginfo) -{ - gchar *filename = NULL; - - g_return_val_if_fail(msginfo != NULL, NULL); - - if (msginfo->file_path) - return g_strdup(msginfo->file_path); - - filename = folder_item_fetch_msg(msginfo->folder, msginfo->msgnum); - if (!filename) - debug_print(_("can't fetch message %d\n"), msginfo->msgnum); - - return filename; -} - -GSList *procmsg_get_message_file_list(GSList *mlist) -{ - GSList *file_list = NULL; - MsgInfo *msginfo; - MsgFileInfo *fileinfo; - gchar *file; - - while (mlist != NULL) { - msginfo = (MsgInfo *)mlist->data; - file = procmsg_get_message_file(msginfo); - if (!file) { - procmsg_message_file_list_free(file_list); - return NULL; - } - fileinfo = g_new(MsgFileInfo, 1); - fileinfo->file = file; - fileinfo->flags = g_new(MsgFlags, 1); - *fileinfo->flags = msginfo->flags; - file_list = g_slist_prepend(file_list, fileinfo); - mlist = mlist->next; - } - - file_list = g_slist_reverse(file_list); - - return file_list; -} - -void procmsg_message_file_list_free(GSList *file_list) -{ - GSList *cur; - MsgFileInfo *fileinfo; - - for (cur = file_list; cur != NULL; cur = cur->next) { - fileinfo = (MsgFileInfo *)cur->data; - g_free(fileinfo->file); - g_free(fileinfo->flags); - g_free(fileinfo); - } - - g_slist_free(file_list); -} - -FILE *procmsg_open_message(MsgInfo *msginfo) -{ - FILE *fp; - gchar *file; - - g_return_val_if_fail(msginfo != NULL, NULL); - - file = procmsg_get_message_file_path(msginfo); - g_return_val_if_fail(file != NULL, NULL); - - if (!is_file_exist(file)) { - g_free(file); - file = procmsg_get_message_file(msginfo); - if (!file) - return NULL; - } - - if ((fp = g_fopen(file, "rb")) == NULL) { - FILE_OP_ERROR(file, "fopen"); - g_free(file); - return NULL; - } - - g_free(file); - - if (MSG_IS_QUEUED(msginfo->flags)) { - gchar buf[BUFFSIZE]; - - while (fgets(buf, sizeof(buf), fp) != NULL) - if (buf[0] == '\r' || buf[0] == '\n') break; - } - - return fp; -} - -#if USE_GPGME -FILE *procmsg_open_message_decrypted(MsgInfo *msginfo, MimeInfo **mimeinfo) -{ - FILE *fp; - MimeInfo *mimeinfo_; - glong fpos; - - g_return_val_if_fail(msginfo != NULL, NULL); - - if (mimeinfo) *mimeinfo = NULL; - - if ((fp = procmsg_open_message(msginfo)) == NULL) return NULL; - - mimeinfo_ = procmime_scan_mime_header(fp); - if (!mimeinfo_) { - fclose(fp); - return NULL; - } - - if (!MSG_IS_ENCRYPTED(msginfo->flags) && - rfc2015_is_encrypted(mimeinfo_)) { - MSG_SET_TMP_FLAGS(msginfo->flags, MSG_ENCRYPTED); - } - - if (MSG_IS_ENCRYPTED(msginfo->flags) && - !msginfo->plaintext_file && - !msginfo->decryption_failed) { - fpos = ftell(fp); - rfc2015_decrypt_message(msginfo, mimeinfo_, fp); - if (msginfo->plaintext_file && - !msginfo->decryption_failed) { - fclose(fp); - procmime_mimeinfo_free_all(mimeinfo_); - if ((fp = procmsg_open_message(msginfo)) == NULL) - return NULL; - mimeinfo_ = procmime_scan_mime_header(fp); - if (!mimeinfo_) { - fclose(fp); - return NULL; - } - } else { - if (fseek(fp, fpos, SEEK_SET) < 0) - perror("fseek"); - } - } - - if (mimeinfo) *mimeinfo = mimeinfo_; - return fp; -} -#endif - -gboolean procmsg_msg_exist(MsgInfo *msginfo) -{ - gchar *path; - gboolean ret; - - if (!msginfo) return FALSE; - - path = folder_item_get_path(msginfo->folder); - change_dir(path); - ret = !folder_item_is_msg_changed(msginfo->folder, msginfo); - g_free(path); - - return ret; -} - -void procmsg_empty_trash(FolderItem *trash) -{ - if (trash && trash->total > 0) { - debug_print("Emptying messages in %s ...\n", trash->path); - - folder_item_remove_all_msg(trash); - procmsg_clear_cache(trash); - procmsg_clear_mark(trash); - trash->cache_dirty = FALSE; - trash->mark_dirty = FALSE; - } -} - -void procmsg_empty_all_trash(void) -{ - FolderItem *trash; - GList *cur; - - for (cur = folder_get_list(); cur != NULL; cur = cur->next) { - trash = FOLDER(cur->data)->trash; - procmsg_empty_trash(trash); - } -} - -gint procmsg_save_to_outbox(FolderItem *outbox, const gchar *file) -{ - gint num; - MsgFlags flag = {0, 0}; - - debug_print("saving sent message...\n"); - - if (!outbox) - outbox = folder_get_default_outbox(); - g_return_val_if_fail(outbox != NULL, -1); - - folder_item_scan(outbox); - if ((num = folder_item_add_msg(outbox, file, &flag, FALSE)) < 0) { - g_warning("can't save message\n"); - return -1; - } - - return 0; -} - -void procmsg_print_message(MsgInfo *msginfo, const gchar *cmdline) -{ - static const gchar *def_cmd = "lpr %s"; - static guint id = 0; - gchar *prtmp; - FILE *tmpfp, *prfp; - gchar buf[1024]; - gchar *p; - - g_return_if_fail(msginfo); - - if ((tmpfp = procmime_get_first_text_content - (msginfo, conv_get_locale_charset_str())) == NULL) { - g_warning(_("Can't get text part\n")); - return; - } - - prtmp = g_strdup_printf("%s%cprinttmp.%08x", - get_mime_tmp_dir(), G_DIR_SEPARATOR, id++); - - if ((prfp = g_fopen(prtmp, "wb")) == NULL) { - FILE_OP_ERROR(prtmp, "fopen"); - g_free(prtmp); - fclose(tmpfp); - return; - } - -#define OUTPUT_HEADER(s, fmt) \ - if (s) { \ - gchar *locale_str; \ - locale_str = conv_codeset_strdup \ - (s, CS_INTERNAL, conv_get_locale_charset_str()); \ - fprintf(prfp, fmt, locale_str ? locale_str : s); \ - g_free(locale_str); \ - } - - OUTPUT_HEADER(msginfo->date, "Date: %s\n"); - OUTPUT_HEADER(msginfo->from, "From: %s\n"); - OUTPUT_HEADER(msginfo->to, "To: %s\n"); - OUTPUT_HEADER(msginfo->newsgroups, "Newsgroups: %s\n"); - OUTPUT_HEADER(msginfo->subject, "Subject: %s\n"); - fputc('\n', prfp); - -#undef OUTPUT_HEADER - - while (fgets(buf, sizeof(buf), tmpfp) != NULL) - fputs(buf, prfp); - - fclose(prfp); - fclose(tmpfp); - - if (cmdline && (p = strchr(cmdline, '%')) && *(p + 1) == 's' && - !strchr(p + 2, '%')) - g_snprintf(buf, sizeof(buf) - 1, cmdline, prtmp); - else { - if (cmdline) - g_warning(_("Print command line is invalid: `%s'\n"), - cmdline); - g_snprintf(buf, sizeof(buf) - 1, def_cmd, prtmp); - } - - g_free(prtmp); - - g_strchomp(buf); - if (buf[strlen(buf) - 1] != '&') strcat(buf, "&"); - system(buf); -} - -MsgInfo *procmsg_msginfo_copy(MsgInfo *msginfo) -{ - MsgInfo *newmsginfo; - - if (msginfo == NULL) return NULL; - - newmsginfo = g_new0(MsgInfo, 1); - -#define MEMBCOPY(mmb) newmsginfo->mmb = msginfo->mmb -#define MEMBDUP(mmb) newmsginfo->mmb = msginfo->mmb ? \ - g_strdup(msginfo->mmb) : NULL - - MEMBCOPY(msgnum); - MEMBCOPY(size); - MEMBCOPY(mtime); - MEMBCOPY(date_t); - - MEMBCOPY(flags); - - MEMBDUP(fromname); - - MEMBDUP(date); - MEMBDUP(from); - MEMBDUP(to); - MEMBDUP(cc); - MEMBDUP(newsgroups); - MEMBDUP(subject); - MEMBDUP(msgid); - MEMBDUP(inreplyto); - - MEMBCOPY(folder); - MEMBCOPY(to_folder); - - MEMBDUP(xface); - - MEMBDUP(file_path); - - MEMBDUP(plaintext_file); - MEMBCOPY(decryption_failed); - - return newmsginfo; -} - -MsgInfo *procmsg_msginfo_get_full_info(MsgInfo *msginfo) -{ - MsgInfo *full_msginfo; - gchar *file; - - if (msginfo == NULL) return NULL; - - file = procmsg_get_message_file(msginfo); - if (!file) { - g_warning("procmsg_msginfo_get_full_info(): can't get message file.\n"); - return NULL; - } - - full_msginfo = procheader_parse_file(file, msginfo->flags, TRUE); - g_free(file); - if (!full_msginfo) return NULL; - - full_msginfo->msgnum = msginfo->msgnum; - full_msginfo->size = msginfo->size; - full_msginfo->mtime = msginfo->mtime; - full_msginfo->folder = msginfo->folder; - full_msginfo->to_folder = msginfo->to_folder; - - full_msginfo->file_path = g_strdup(msginfo->file_path); - -#if USE_GPGME - full_msginfo->plaintext_file = g_strdup(msginfo->plaintext_file); - full_msginfo->decryption_failed = msginfo->decryption_failed; -#endif - - return full_msginfo; -} - -gboolean procmsg_msginfo_equal(MsgInfo *msginfo_a, MsgInfo *msginfo_b) -{ - if (!msginfo_a || !msginfo_b) - return FALSE; - - if (msginfo_a == msginfo_b) - return TRUE; - - if (msginfo_a->folder == msginfo_b->folder && - msginfo_a->msgnum == msginfo_b->msgnum && - msginfo_a->size == msginfo_b->size && - msginfo_a->mtime == msginfo_b->mtime) - return TRUE; - - return FALSE; -} - -void procmsg_msginfo_free(MsgInfo *msginfo) -{ - if (msginfo == NULL) return; - - g_free(msginfo->xface); - - g_free(msginfo->fromname); - - g_free(msginfo->date); - g_free(msginfo->from); - g_free(msginfo->to); - g_free(msginfo->cc); - g_free(msginfo->newsgroups); - g_free(msginfo->subject); - g_free(msginfo->msgid); - g_free(msginfo->inreplyto); - - slist_free_strings(msginfo->references); - g_slist_free(msginfo->references); - - g_free(msginfo->file_path); - - g_free(msginfo->plaintext_file); - - g_free(msginfo); -} - -gint procmsg_cmp_msgnum_for_sort(gconstpointer a, gconstpointer b) -{ - const MsgInfo *msginfo1 = a; - const MsgInfo *msginfo2 = b; - - if (!msginfo1 || !msginfo2) - return 0; - - return msginfo1->msgnum - msginfo2->msgnum; -} - -#define CMP_FUNC_DEF(func_name, val) \ -static gint func_name(gconstpointer a, gconstpointer b) \ -{ \ - const MsgInfo *msginfo1 = a; \ - const MsgInfo *msginfo2 = b; \ - gint ret; \ - \ - if (!msginfo1 || !msginfo2) \ - return 0; \ - \ - ret = (val); \ - if (ret == 0) \ - ret = msginfo1->date_t - msginfo2->date_t; \ - \ - return ret * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1); \ -} - -CMP_FUNC_DEF(procmsg_cmp_by_mark, - MSG_IS_MARKED(msginfo1->flags) - MSG_IS_MARKED(msginfo2->flags)) -CMP_FUNC_DEF(procmsg_cmp_by_unread, - MSG_IS_UNREAD(msginfo1->flags) - MSG_IS_UNREAD(msginfo2->flags)) -CMP_FUNC_DEF(procmsg_cmp_by_mime, - MSG_IS_MIME(msginfo1->flags) - MSG_IS_MIME(msginfo2->flags)) -CMP_FUNC_DEF(procmsg_cmp_by_label, - MSG_GET_COLORLABEL(msginfo1->flags) - - MSG_GET_COLORLABEL(msginfo2->flags)) -CMP_FUNC_DEF(procmsg_cmp_by_size, msginfo1->size - msginfo2->size) - -#undef CMP_FUNC_DEF -#define CMP_FUNC_DEF(func_name, val) \ -static gint func_name(gconstpointer a, gconstpointer b) \ -{ \ - const MsgInfo *msginfo1 = a; \ - const MsgInfo *msginfo2 = b; \ - \ - if (!msginfo1 || !msginfo2) \ - return 0; \ - \ - return (val) * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1); \ -} - -CMP_FUNC_DEF(procmsg_cmp_by_number, msginfo1->msgnum - msginfo2->msgnum) -CMP_FUNC_DEF(procmsg_cmp_by_date, msginfo1->date_t - msginfo2->date_t) - -#undef CMP_FUNC_DEF -#define CMP_FUNC_DEF(func_name, var_name) \ -static gint func_name(gconstpointer a, gconstpointer b) \ -{ \ - const MsgInfo *msginfo1 = a; \ - const MsgInfo *msginfo2 = b; \ - gint ret; \ - \ - if (!msginfo1->var_name) \ - return (msginfo2->var_name != NULL) * \ - (cmp_func_sort_type == SORT_ASCENDING ? -1 : 1);\ - if (!msginfo2->var_name) \ - return (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1); \ - \ - ret = g_ascii_strcasecmp \ - (msginfo1->var_name, msginfo2->var_name); \ - if (ret == 0) \ - ret = msginfo1->date_t - msginfo2->date_t; \ - \ - return ret * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1); \ -} - -CMP_FUNC_DEF(procmsg_cmp_by_from, fromname) -CMP_FUNC_DEF(procmsg_cmp_by_to, to) - -#undef CMP_FUNC_DEF - -static gint procmsg_cmp_by_subject(gconstpointer a, gconstpointer b) -{ - const MsgInfo *msginfo1 = a; - const MsgInfo *msginfo2 = b; - gint ret; - - if (!msginfo1->subject) - return (msginfo2->subject != NULL) * - (cmp_func_sort_type == SORT_ASCENDING ? -1 : 1); - if (!msginfo2->subject) - return (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1); - - ret = subject_compare_for_sort(msginfo1->subject, msginfo2->subject); - if (ret == 0) - ret = msginfo1->date_t - msginfo2->date_t; - - return ret * (cmp_func_sort_type == SORT_ASCENDING ? 1 : -1); -} diff --git a/src/procmsg.h b/src/procmsg.h deleted file mode 100644 index 9e6d45b8..00000000 --- a/src/procmsg.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __PROCMSG_H__ -#define __PROCMSG_H__ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <glib.h> -#include <stdio.h> -#include <time.h> -#include <sys/types.h> -#include <string.h> - -typedef struct _MsgInfo MsgInfo; -typedef struct _MsgFlags MsgFlags; -typedef struct _MsgFileInfo MsgFileInfo; - -#include "folder.h" -#include "procmime.h" -#include "prefs_filter.h" - -typedef enum -{ - DATA_READ, - DATA_WRITE, - DATA_APPEND -} DataOpenMode; - -#define MSG_NEW (1U << 0) -#define MSG_UNREAD (1U << 1) -#define MSG_MARKED (1U << 2) -#define MSG_DELETED (1U << 3) -#define MSG_REPLIED (1U << 4) -#define MSG_FORWARDED (1U << 5) - -#define MSG_CLABEL_SBIT (7) /* start bit of color label */ -#define MAKE_MSG_CLABEL(h, m, l) (((h) << (MSG_CLABEL_SBIT + 2)) | \ - ((m) << (MSG_CLABEL_SBIT + 1)) | \ - ((l) << (MSG_CLABEL_SBIT + 0))) - -#define MSG_CLABEL_NONE MAKE_MSG_CLABEL(0U, 0U, 0U) -#define MSG_CLABEL_1 MAKE_MSG_CLABEL(0U, 0U, 1U) -#define MSG_CLABEL_2 MAKE_MSG_CLABEL(0U, 1U, 0U) -#define MSG_CLABEL_3 MAKE_MSG_CLABEL(0U, 1U, 1U) -#define MSG_CLABEL_4 MAKE_MSG_CLABEL(1U, 0U, 0U) -#define MSG_CLABEL_5 MAKE_MSG_CLABEL(1U, 0U, 1U) -#define MSG_CLABEL_6 MAKE_MSG_CLABEL(1U, 1U, 0U) -#define MSG_CLABEL_7 MAKE_MSG_CLABEL(1U, 1U, 1U) - -#define MSG_CLABEL_ORANGE MSG_CLABEL_1 -#define MSG_CLABEL_RED MSG_CLABEL_2 -#define MSG_CLABEL_PINK MSG_CLABEL_3 -#define MSG_CLABEL_SKYBLUE MSG_CLABEL_4 -#define MSG_CLABEL_BLUE MSG_CLABEL_5 -#define MSG_CLABEL_GREEN MSG_CLABEL_6 -#define MSG_CLABEL_BROWN MSG_CLABEL_7 - -/* RESERVED */ -#define MSG_RESERVED (1U << 31) - -#define MSG_CLABEL_FLAG_MASK (MSG_CLABEL_7) - -typedef guint32 MsgPermFlags; - -#define MSG_MOVE (1U << 0) -#define MSG_COPY (1U << 1) -#define MSG_QUEUED (1U << 16) -#define MSG_DRAFT (1U << 17) -#define MSG_ENCRYPTED (1U << 18) -#define MSG_IMAP (1U << 19) -#define MSG_NEWS (1U << 20) -#define MSG_SIGNED (1U << 21) -#define MSG_CACHED (1U << 28) -#define MSG_MIME (1U << 29) -#define MSG_INVALID (1U << 30) -#define MSG_RECEIVED (1U << 31) - -#define MSG_CACHED_FLAG_MASK (MSG_MIME) - -typedef guint32 MsgTmpFlags; - -#define MSG_SET_FLAGS(msg, flags) { (msg) |= (flags); } -#define MSG_UNSET_FLAGS(msg, flags) { (msg) &= ~(flags); } -#define MSG_SET_PERM_FLAGS(msg, flags) \ - MSG_SET_FLAGS((msg).perm_flags, flags) -#define MSG_SET_TMP_FLAGS(msg, flags) \ - MSG_SET_FLAGS((msg).tmp_flags, flags) -#define MSG_UNSET_PERM_FLAGS(msg, flags) \ - MSG_UNSET_FLAGS((msg).perm_flags, flags) -#define MSG_UNSET_TMP_FLAGS(msg, flags) \ - MSG_UNSET_FLAGS((msg).tmp_flags, flags) - -#define MSG_IS_NEW(msg) (((msg).perm_flags & MSG_NEW) != 0) -#define MSG_IS_UNREAD(msg) (((msg).perm_flags & MSG_UNREAD) != 0) -#define MSG_IS_MARKED(msg) (((msg).perm_flags & MSG_MARKED) != 0) -#define MSG_IS_DELETED(msg) (((msg).perm_flags & MSG_DELETED) != 0) -#define MSG_IS_REPLIED(msg) (((msg).perm_flags & MSG_REPLIED) != 0) -#define MSG_IS_FORWARDED(msg) (((msg).perm_flags & MSG_FORWARDED) != 0) - -#define MSG_GET_COLORLABEL(msg) (((msg).perm_flags & MSG_CLABEL_FLAG_MASK)) -#define MSG_GET_COLORLABEL_VALUE(msg) (MSG_GET_COLORLABEL(msg) >> MSG_CLABEL_SBIT) -#define MSG_SET_COLORLABEL_VALUE(msg, val) \ - MSG_SET_PERM_FLAGS(msg, ((((guint)(val)) & 7) << MSG_CLABEL_SBIT)) - -#define MSG_IS_MOVE(msg) (((msg).tmp_flags & MSG_MOVE) != 0) -#define MSG_IS_COPY(msg) (((msg).tmp_flags & MSG_COPY) != 0) - -#define MSG_IS_QUEUED(msg) (((msg).tmp_flags & MSG_QUEUED) != 0) -#define MSG_IS_DRAFT(msg) (((msg).tmp_flags & MSG_DRAFT) != 0) -#define MSG_IS_ENCRYPTED(msg) (((msg).tmp_flags & MSG_ENCRYPTED) != 0) -#define MSG_IS_IMAP(msg) (((msg).tmp_flags & MSG_IMAP) != 0) -#define MSG_IS_NEWS(msg) (((msg).tmp_flags & MSG_NEWS) != 0) -#define MSG_IS_SIGNED(msg) (((msg).tmp_flags & MSG_SIGNED) != 0) -#define MSG_IS_CACHED(msg) (((msg).tmp_flags & MSG_CACHED) != 0) -#define MSG_IS_MIME(msg) (((msg).tmp_flags & MSG_MIME) != 0) -#define MSG_IS_INVALID(msg) (((msg).tmp_flags & MSG_INVALID) != 0) -#define MSG_IS_RECEIVED(msg) (((msg).tmp_flags & MSG_RECEIVED) != 0) - -#define WRITE_CACHE_DATA_INT(n, fp) \ -{ \ - guint32 idata; \ - \ - idata = (guint32)n; \ - fwrite(&idata, sizeof(idata), 1, fp); \ -} - -#define WRITE_CACHE_DATA(data, fp) \ -{ \ - size_t len; \ - \ - if (data == NULL) { \ - len = 0; \ - WRITE_CACHE_DATA_INT(len, fp); \ - } else { \ - len = strlen(data); \ - WRITE_CACHE_DATA_INT(len, fp); \ - if (len > 0) \ - fwrite(data, len, 1, fp); \ - } \ -} - -struct _MsgFlags -{ - MsgPermFlags perm_flags; - MsgTmpFlags tmp_flags; -}; - -struct _MsgInfo -{ - guint msgnum; - off_t size; - time_t mtime; - time_t date_t; - - MsgFlags flags; - - gchar *fromname; - - gchar *date; - gchar *from; - gchar *to; - gchar *cc; - gchar *newsgroups; - gchar *subject; - gchar *msgid; - gchar *inreplyto; - - GSList *references; - - FolderItem *folder; - FolderItem *to_folder; - - gchar *xface; - - /* used only for temporary messages */ - gchar *file_path; - - /* used only for encrypted messages */ - gchar *plaintext_file; - guint decryption_failed : 1; -}; - -struct _MsgFileInfo -{ - gchar *file; - MsgFlags *flags; -}; - -GHashTable *procmsg_msg_hash_table_create (GSList *mlist); -void procmsg_msg_hash_table_append (GHashTable *msg_table, - GSList *mlist); -GHashTable *procmsg_to_folder_hash_table_create (GSList *mlist); - -GSList *procmsg_read_cache (FolderItem *item, - gboolean scan_file); -void procmsg_set_flags (GSList *mlist, - FolderItem *item); -GSList *procmsg_sort_msg_list (GSList *mlist, - FolderSortKey sort_key, - FolderSortType sort_type); -gint procmsg_get_last_num_in_msg_list(GSList *mlist); -void procmsg_msg_list_free (GSList *mlist); -void procmsg_write_cache (MsgInfo *msginfo, - FILE *fp); -void procmsg_write_flags (MsgInfo *msginfo, - FILE *fp); -void procmsg_flush_mark_queue (FolderItem *item, - FILE *fp); -void procmsg_add_mark_queue (FolderItem *item, - gint num, - MsgFlags flags); -void procmsg_add_flags (FolderItem *item, - gint num, - MsgFlags flags); -void procmsg_get_mark_sum (FolderItem *item, - gint *new, - gint *unread, - gint *total, - gint *min, - gint *max, - gint first); -FILE *procmsg_open_cache_file (FolderItem *item, - DataOpenMode mode); -FILE *procmsg_open_mark_file (FolderItem *item, - DataOpenMode mode); - -void procmsg_clear_cache (FolderItem *item); -void procmsg_clear_mark (FolderItem *item); - -GNode *procmsg_get_thread_tree (GSList *mlist); - -gint procmsg_move_messages (GSList *mlist); -gint procmsg_copy_messages (GSList *mlist); - -gchar *procmsg_get_message_file_path (MsgInfo *msginfo); -gchar *procmsg_get_message_file (MsgInfo *msginfo); -GSList *procmsg_get_message_file_list (GSList *mlist); -void procmsg_message_file_list_free (GSList *file_list); -FILE *procmsg_open_message (MsgInfo *msginfo); -#if USE_GPGME -FILE *procmsg_open_message_decrypted (MsgInfo *msginfo, - MimeInfo **mimeinfo); -#endif -gboolean procmsg_msg_exist (MsgInfo *msginfo); - -void procmsg_empty_trash (FolderItem *trash); -void procmsg_empty_all_trash (void); - -gint procmsg_save_to_outbox (FolderItem *outbox, - const gchar *file); -void procmsg_print_message (MsgInfo *msginfo, - const gchar *cmdline); - -MsgInfo *procmsg_msginfo_copy (MsgInfo *msginfo); -MsgInfo *procmsg_msginfo_get_full_info (MsgInfo *msginfo); -gboolean procmsg_msginfo_equal (MsgInfo *msginfo_a, - MsgInfo *msginfo_b); -void procmsg_msginfo_free (MsgInfo *msginfo); - -gint procmsg_cmp_msgnum_for_sort (gconstpointer a, - gconstpointer b); - -#endif /* __PROCMSG_H__ */ diff --git a/src/rfc2015.c b/src/rfc2015.c index ef6a9230..8708dc81 100644 --- a/src/rfc2015.c +++ b/src/rfc2015.c @@ -35,6 +35,7 @@ #include <gpgme.h> +#include "procmsg.h" #include "procmime.h" #include "procheader.h" #include "base64.h" @@ -637,6 +638,55 @@ void rfc2015_decrypt_message(MsgInfo *msginfo, MimeInfo *mimeinfo, FILE *fp) #undef DECRYPTION_ABORT +FILE *rfc2015_open_message_decrypted(MsgInfo *msginfo, MimeInfo **mimeinfo) +{ + FILE *fp; + MimeInfo *mimeinfo_; + glong fpos; + + g_return_val_if_fail(msginfo != NULL, NULL); + + if (mimeinfo) *mimeinfo = NULL; + + if ((fp = procmsg_open_message(msginfo)) == NULL) return NULL; + + mimeinfo_ = procmime_scan_mime_header(fp); + if (!mimeinfo_) { + fclose(fp); + return NULL; + } + + if (!MSG_IS_ENCRYPTED(msginfo->flags) && + rfc2015_is_encrypted(mimeinfo_)) { + MSG_SET_TMP_FLAGS(msginfo->flags, MSG_ENCRYPTED); + } + + if (MSG_IS_ENCRYPTED(msginfo->flags) && + !msginfo->plaintext_file && + !msginfo->decryption_failed) { + fpos = ftell(fp); + rfc2015_decrypt_message(msginfo, mimeinfo_, fp); + if (msginfo->plaintext_file && + !msginfo->decryption_failed) { + fclose(fp); + procmime_mimeinfo_free_all(mimeinfo_); + if ((fp = procmsg_open_message(msginfo)) == NULL) + return NULL; + mimeinfo_ = procmime_scan_mime_header(fp); + if (!mimeinfo_) { + fclose(fp); + return NULL; + } + } else { + if (fseek(fp, fpos, SEEK_SET) < 0) + perror("fseek"); + } + } + + if (mimeinfo) *mimeinfo = mimeinfo_; + return fp; +} + /* * plain contains an entire mime object. diff --git a/src/rfc2015.h b/src/rfc2015.h index 464b0154..e70605e1 100644 --- a/src/rfc2015.h +++ b/src/rfc2015.h @@ -23,6 +23,7 @@ #include <glib.h> #include <stdio.h> +#include "procmsg.h" #include "procmime.h" void rfc2015_disable_all (void); @@ -31,11 +32,15 @@ MimeInfo **rfc2015_find_signature (MimeInfo *mimeinfo); gboolean rfc2015_has_signature (MimeInfo *mimeinfo); void rfc2015_check_signature (MimeInfo *mimeinfo, FILE *fp); + gint rfc2015_is_encrypted (MimeInfo *mimeinfo); gboolean rfc2015_msg_is_encrypted (const gchar *file); void rfc2015_decrypt_message (MsgInfo *msginfo, MimeInfo *mimeinfo, FILE *fp); +FILE *rfc2015_open_message_decrypted (MsgInfo *msginfo, + MimeInfo **mimeinfo); + GSList *rfc2015_create_signers_list (const gchar *keyid); gint rfc2015_encrypt (const gchar *file, GSList *recp_list, diff --git a/src/smtp.c b/src/smtp.c deleted file mode 100644 index 25a0f71a..00000000 --- a/src/smtp.c +++ /dev/null @@ -1,613 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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 <glib.h> -#include <glib/gi18n.h> -#include <stdio.h> -#include <string.h> - -#include "smtp.h" -#include "md5.h" -#include "base64.h" -#include "utils.h" - -static void smtp_session_destroy(Session *session); - -static gint smtp_from(SMTPSession *session); - -static gint smtp_auth(SMTPSession *session); -static gint smtp_starttls(SMTPSession *session); -static gint smtp_auth_cram_md5(SMTPSession *session); -static gint smtp_auth_plain(SMTPSession *session); -static gint smtp_auth_login(SMTPSession *session); - -static gint smtp_ehlo(SMTPSession *session); -static gint smtp_ehlo_recv(SMTPSession *session, const gchar *msg); - -static gint smtp_helo(SMTPSession *session); -static gint smtp_rcpt(SMTPSession *session); -static gint smtp_data(SMTPSession *session); -static gint smtp_send_data(SMTPSession *session); -/* static gint smtp_rset(SMTPSession *session); */ -static gint smtp_quit(SMTPSession *session); -static gint smtp_eom(SMTPSession *session); - -static gint smtp_session_recv_msg(Session *session, const gchar *msg); -static gint smtp_session_send_data_finished(Session *session, guint len); - - -Session *smtp_session_new(void) -{ - SMTPSession *session; - - session = g_new0(SMTPSession, 1); - - session_init(SESSION(session)); - - SESSION(session)->type = SESSION_SMTP; - - SESSION(session)->recv_msg = smtp_session_recv_msg; - - SESSION(session)->recv_data_finished = NULL; - SESSION(session)->send_data_finished = smtp_session_send_data_finished; - - SESSION(session)->destroy = smtp_session_destroy; - - session->state = SMTP_READY; - -#if USE_SSL - session->tls_init_done = FALSE; -#endif - - session->hostname = NULL; - session->user = NULL; - session->pass = NULL; - - session->from = NULL; - session->to_list = NULL; - session->cur_to = NULL; - - session->send_data = NULL; - session->send_data_len = 0; - - session->avail_auth_type = 0; - session->forced_auth_type = 0; - session->auth_type = 0; - - session->error_val = SM_OK; - session->error_msg = NULL; - - return SESSION(session); -} - -static void smtp_session_destroy(Session *session) -{ - SMTPSession *smtp_session = SMTP_SESSION(session); - - g_free(smtp_session->hostname); - g_free(smtp_session->user); - g_free(smtp_session->pass); - g_free(smtp_session->from); - - g_free(smtp_session->send_data); - - g_free(smtp_session->error_msg); -} - -static gint smtp_from(SMTPSession *session) -{ - gchar buf[MSGBUFSIZE]; - - g_return_val_if_fail(session->from != NULL, SM_ERROR); - - session->state = SMTP_FROM; - - if (strchr(session->from, '<')) - g_snprintf(buf, sizeof(buf), "MAIL FROM:%s", session->from); - else - g_snprintf(buf, sizeof(buf), "MAIL FROM:<%s>", session->from); - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); - log_print("SMTP> %s\n", buf); - - return SM_OK; -} - -static gint smtp_auth(SMTPSession *session) -{ - - g_return_val_if_fail(session->user != NULL, SM_ERROR); - - session->state = SMTP_AUTH; - - if (session->forced_auth_type == SMTPAUTH_CRAM_MD5 || - (session->forced_auth_type == 0 && - (session->avail_auth_type & SMTPAUTH_CRAM_MD5) != 0)) - smtp_auth_cram_md5(session); - else if (session->forced_auth_type == SMTPAUTH_PLAIN || - (session->forced_auth_type == 0 && - (session->avail_auth_type & SMTPAUTH_PLAIN) != 0)) - smtp_auth_plain(session); - else if (session->forced_auth_type == SMTPAUTH_LOGIN || - (session->forced_auth_type == 0 && - (session->avail_auth_type & SMTPAUTH_LOGIN) != 0)) - smtp_auth_login(session); - else { - log_warning(_("SMTP AUTH not available\n")); - return SM_AUTHFAIL; - } - - return SM_OK; -} - -static gint smtp_auth_recv(SMTPSession *session, const gchar *msg) -{ - gchar buf[MSGBUFSIZE]; - - switch (session->auth_type) { - case SMTPAUTH_LOGIN: - session->state = SMTP_AUTH_LOGIN_USER; - - if (!strncmp(msg, "334 ", 4)) { - base64_encode(buf, session->user, strlen(session->user)); - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, - buf); - log_print("ESMTP> [USERID]\n"); - } else { - /* Server rejects AUTH */ - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, - "*"); - log_print("ESMTP> *\n"); - } - break; - case SMTPAUTH_CRAM_MD5: - session->state = SMTP_AUTH_CRAM_MD5; - - if (!strncmp(msg, "334 ", 4)) { - gchar *response; - gchar *response64; - gchar *challenge; - gint challengelen; - guchar hexdigest[33]; - - challenge = g_malloc(strlen(msg + 4) + 1); - challengelen = base64_decode(challenge, msg + 4, -1); - challenge[challengelen] = '\0'; - log_print("ESMTP< [Decoded: %s]\n", challenge); - - g_snprintf(buf, sizeof(buf), "%s", session->pass); - md5_hex_hmac(hexdigest, challenge, challengelen, - buf, strlen(session->pass)); - g_free(challenge); - - response = g_strdup_printf - ("%s %s", session->user, hexdigest); - log_print("ESMTP> [Encoded: %s]\n", response); - - response64 = g_malloc((strlen(response) + 3) * 2 + 1); - base64_encode(response64, response, strlen(response)); - g_free(response); - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, - response64); - log_print("ESMTP> %s\n", response64); - g_free(response64); - } else { - /* Server rejects AUTH */ - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, - "*"); - log_print("ESMTP> *\n"); - } - break; - case SMTPAUTH_DIGEST_MD5: - default: - /* stop smtp_auth when no correct authtype */ - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "*"); - log_print("ESMTP> *\n"); - break; - } - - return SM_OK; -} - -static gint smtp_auth_login_user_recv(SMTPSession *session, const gchar *msg) -{ - gchar buf[MSGBUFSIZE]; - - session->state = SMTP_AUTH_LOGIN_PASS; - - if (!strncmp(msg, "334 ", 4)) - base64_encode(buf, session->pass, strlen(session->pass)); - else - /* Server rejects AUTH */ - g_snprintf(buf, sizeof(buf), "*"); - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); - log_print("ESMTP> [PASSWORD]\n"); - - return SM_OK; -} - -static gint smtp_ehlo(SMTPSession *session) -{ - gchar buf[MSGBUFSIZE]; - - session->state = SMTP_EHLO; - - session->avail_auth_type = 0; - - g_snprintf(buf, sizeof(buf), "EHLO %s", - session->hostname ? session->hostname : get_domain_name()); - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); - log_print("ESMTP> %s\n", buf); - - return SM_OK; -} - -static gint smtp_ehlo_recv(SMTPSession *session, const gchar *msg) -{ - if (strncmp(msg, "250", 3) == 0) { - const gchar *p = msg; - p += 3; - if (*p == '-' || *p == ' ') p++; - if (g_ascii_strncasecmp(p, "AUTH", 4) == 0 && p[4] != '\0') { - p += 5; - if (strcasestr(p, "PLAIN")) - session->avail_auth_type |= SMTPAUTH_PLAIN; - if (strcasestr(p, "LOGIN")) - session->avail_auth_type |= SMTPAUTH_LOGIN; - if (strcasestr(p, "CRAM-MD5")) - session->avail_auth_type |= SMTPAUTH_CRAM_MD5; - if (strcasestr(p, "DIGEST-MD5")) - session->avail_auth_type |= SMTPAUTH_DIGEST_MD5; - } - return SM_OK; - } else if ((msg[0] == '1' || msg[0] == '2' || msg[0] == '3') && - (msg[3] == ' ' || msg[3] == '\0')) - return SM_OK; - else if (msg[0] == '5' && msg[1] == '0' && - (msg[2] == '4' || msg[2] == '3' || msg[2] == '1')) - return SM_ERROR; - - return SM_ERROR; -} - -static gint smtp_starttls(SMTPSession *session) -{ - session->state = SMTP_STARTTLS; - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "STARTTLS"); - log_print("ESMTP> STARTTLS\n"); - - return SM_OK; -} - -static gint smtp_auth_cram_md5(SMTPSession *session) -{ - session->state = SMTP_AUTH; - session->auth_type = SMTPAUTH_CRAM_MD5; - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "AUTH CRAM-MD5"); - log_print("ESMTP> AUTH CRAM-MD5\n"); - - return SM_OK; -} - -static gint smtp_auth_plain(SMTPSession *session) -{ - gchar *authstr; - gint authlen; - gchar *outbuf; - gchar *p; - - session->state = SMTP_AUTH_PLAIN; - session->auth_type = SMTPAUTH_PLAIN; - - /* - * construct the string: \0<user>\0<pass> - */ - - authlen = 1 + strlen(session->user) + 1 + strlen(session->pass); - authstr = g_malloc(authlen + 1); - - p = authstr; - - *p++ = '\0'; - strcpy(p, session->user); - p += strlen(p) + 1; - strcpy(p, session->pass); - - outbuf = g_malloc(sizeof("AUTH PLAIN ") + authlen * 2 + 1); - - strcpy(outbuf, "AUTH PLAIN "); - p = outbuf + strlen(outbuf); - base64_encode(p, authstr, authlen); - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, outbuf); - log_print("ESMTP> AUTH PLAIN ********\n"); - - g_free(outbuf); - g_free(authstr); - - return SM_OK; -} - -static gint smtp_auth_login(SMTPSession *session) -{ - session->state = SMTP_AUTH; - session->auth_type = SMTPAUTH_LOGIN; - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "AUTH LOGIN"); - log_print("ESMTP> AUTH LOGIN\n"); - - return SM_OK; -} - -static gint smtp_helo(SMTPSession *session) -{ - gchar buf[MSGBUFSIZE]; - - session->state = SMTP_HELO; - - g_snprintf(buf, sizeof(buf), "HELO %s", - session->hostname ? session->hostname : get_domain_name()); - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); - log_print("SMTP> %s\n", buf); - - return SM_OK; -} - -static gint smtp_rcpt(SMTPSession *session) -{ - gchar buf[MSGBUFSIZE]; - gchar *to; - - g_return_val_if_fail(session->cur_to != NULL, SM_ERROR); - - session->state = SMTP_RCPT; - - to = (gchar *)session->cur_to->data; - - if (strchr(to, '<')) - g_snprintf(buf, sizeof(buf), "RCPT TO:%s", to); - else - g_snprintf(buf, sizeof(buf), "RCPT TO:<%s>", to); - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, buf); - log_print("SMTP> %s\n", buf); - - session->cur_to = session->cur_to->next; - - return SM_OK; -} - -static gint smtp_data(SMTPSession *session) -{ - session->state = SMTP_DATA; - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "DATA"); - log_print("SMTP> DATA\n"); - - return SM_OK; -} - -static gint smtp_send_data(SMTPSession *session) -{ - session->state = SMTP_SEND_DATA; - - session_send_data(SESSION(session), session->send_data, - session->send_data_len); - - return SM_OK; -} - -#if 0 -static gint smtp_rset(SMTPSession *session) -{ - session->state = SMTP_RSET; - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "RSET"); - log_print("SMTP> RSET\n"); - - return SM_OK; -} -#endif - -static gint smtp_quit(SMTPSession *session) -{ - session->state = SMTP_QUIT; - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "QUIT"); - log_print("SMTP> QUIT\n"); - - return SM_OK; -} - -static gint smtp_eom(SMTPSession *session) -{ - session->state = SMTP_EOM; - - session_send_msg(SESSION(session), SESSION_MSG_NORMAL, "."); - log_print("SMTP> . (EOM)\n"); - - return SM_OK; -} - -static gint smtp_session_recv_msg(Session *session, const gchar *msg) -{ - SMTPSession *smtp_session = SMTP_SESSION(session); - gboolean cont = FALSE; - - if (strlen(msg) < 4) { - log_warning(_("bad SMTP response\n")); - return -1; - } - - switch (smtp_session->state) { - case SMTP_EHLO: - case SMTP_STARTTLS: - case SMTP_AUTH: - case SMTP_AUTH_PLAIN: - case SMTP_AUTH_LOGIN_USER: - case SMTP_AUTH_LOGIN_PASS: - case SMTP_AUTH_CRAM_MD5: - log_print("ESMTP< %s\n", msg); - break; - default: - log_print("SMTP< %s\n", msg); - break; - } - - if (msg[0] == '5' && msg[1] == '0' && - (msg[2] == '4' || msg[2] == '3' || msg[2] == '1')) { - log_warning(_("error occurred on SMTP session\n")); - smtp_session->state = SMTP_ERROR; - smtp_session->error_val = SM_ERROR; - g_free(smtp_session->error_msg); - smtp_session->error_msg = g_strdup(msg); - return -1; - } - - if (!strncmp(msg, "535", 3)) { - log_warning(_("error occurred on authentication\n")); - smtp_session->state = SMTP_ERROR; - smtp_session->error_val = SM_AUTHFAIL; - g_free(smtp_session->error_msg); - smtp_session->error_msg = g_strdup(msg); - return -1; - } - - if (msg[0] != '1' && msg[0] != '2' && msg[0] != '3') { - log_warning(_("error occurred on SMTP session\n")); - smtp_session->state = SMTP_ERROR; - smtp_session->error_val = SM_ERROR; - g_free(smtp_session->error_msg); - smtp_session->error_msg = g_strdup(msg); - return -1; - } - - if (msg[3] == '-') - cont = TRUE; - else if (msg[3] != ' ' && msg[3] != '\0') { - log_warning(_("bad SMTP response\n")); - smtp_session->state = SMTP_ERROR; - smtp_session->error_val = SM_UNRECOVERABLE; - return -1; - } - - /* ignore all multiline responses except for EHLO */ - if (cont && smtp_session->state != SMTP_EHLO) - return session_recv_msg(session); - - switch (smtp_session->state) { - case SMTP_READY: - case SMTP_CONNECTED: -#if USE_SSL - if (smtp_session->user || session->ssl_type != SSL_NONE) -#else - if (smtp_session->user) -#endif - smtp_ehlo(smtp_session); - else - smtp_helo(smtp_session); - break; - case SMTP_HELO: - smtp_from(smtp_session); - break; - case SMTP_EHLO: - smtp_ehlo_recv(smtp_session, msg); - if (cont == TRUE) - break; -#if USE_SSL - if (session->ssl_type == SSL_STARTTLS && - smtp_session->tls_init_done == FALSE) { - smtp_starttls(smtp_session); - break; - } -#endif - if (smtp_session->user) { - if (smtp_auth(smtp_session) != SM_OK) - smtp_from(smtp_session); - } else - smtp_from(smtp_session); - break; - case SMTP_STARTTLS: -#if USE_SSL - if (session_start_tls(session) < 0) { - log_warning(_("can't start TLS session\n")); - smtp_session->state = SMTP_ERROR; - smtp_session->error_val = SM_ERROR; - return -1; - } - smtp_session->tls_init_done = TRUE; - smtp_ehlo(smtp_session); -#endif - break; - case SMTP_AUTH: - smtp_auth_recv(smtp_session, msg); - break; - case SMTP_AUTH_LOGIN_USER: - smtp_auth_login_user_recv(smtp_session, msg); - break; - case SMTP_AUTH_PLAIN: - case SMTP_AUTH_LOGIN_PASS: - case SMTP_AUTH_CRAM_MD5: - smtp_from(smtp_session); - break; - case SMTP_FROM: - if (smtp_session->cur_to) - smtp_rcpt(smtp_session); - break; - case SMTP_RCPT: - if (smtp_session->cur_to) - smtp_rcpt(smtp_session); - else - smtp_data(smtp_session); - break; - case SMTP_DATA: - smtp_send_data(smtp_session); - break; - case SMTP_EOM: - smtp_quit(smtp_session); - break; - case SMTP_QUIT: - session_disconnect(session); - break; - case SMTP_ERROR: - default: - log_warning(_("error occurred on SMTP session\n")); - smtp_session->error_val = SM_ERROR; - return -1; - } - - if (cont) - return session_recv_msg(session); - - return 0; -} - -static gint smtp_session_send_data_finished(Session *session, guint len) -{ - smtp_eom(SMTP_SESSION(session)); - return 0; -} diff --git a/src/smtp.h b/src/smtp.h deleted file mode 100644 index 445bba69..00000000 --- a/src/smtp.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999-2005 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. - */ - -#ifndef __SMTP_H__ -#define __SMTP_H__ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <glib.h> - -#include "session.h" - -typedef struct _SMTPSession SMTPSession; - -#define SMTP_SESSION(obj) ((SMTPSession *)obj) - -#define MSGBUFSIZE 8192 - -typedef enum -{ - SM_OK = 0, - SM_ERROR = 128, - SM_UNRECOVERABLE = 129, - SM_AUTHFAIL = 130 -} SMTPErrorValue; - -typedef enum -{ - ESMTP_8BITMIME = 1 << 0, - ESMTP_SIZE = 1 << 1, - ESMTP_ETRN = 1 << 2 -} ESMTPFlag; - -typedef enum -{ - SMTPAUTH_LOGIN = 1 << 0, - SMTPAUTH_CRAM_MD5 = 1 << 1, - SMTPAUTH_DIGEST_MD5 = 1 << 2, - SMTPAUTH_PLAIN = 1 << 3 -} SMTPAuthType; - -typedef enum -{ - SMTP_READY, - SMTP_CONNECTED, - SMTP_HELO, - SMTP_EHLO, - SMTP_STARTTLS, - SMTP_FROM, - SMTP_AUTH, - SMTP_AUTH_PLAIN, - SMTP_AUTH_LOGIN_USER, - SMTP_AUTH_LOGIN_PASS, - SMTP_AUTH_CRAM_MD5, - SMTP_RCPT, - SMTP_DATA, - SMTP_SEND_DATA, - SMTP_EOM, - SMTP_RSET, - SMTP_QUIT, - SMTP_ERROR, - SMTP_DISCONNECTED, - - N_SMTP_PHASE -} SMTPState; - -struct _SMTPSession -{ - Session session; - - SMTPState state; - -#if USE_SSL - gboolean tls_init_done; -#endif - - gchar *hostname; - - gchar *user; - gchar *pass; - - gchar *from; - GSList *to_list; - GSList *cur_to; - - guchar *send_data; - guint send_data_len; - - SMTPAuthType avail_auth_type; - SMTPAuthType forced_auth_type; - SMTPAuthType auth_type; - - SMTPErrorValue error_val; - gchar *error_msg; -}; - -Session *smtp_session_new (void); - -#endif /* __SMTP_H__ */ |