diff options
author | hiro <hiro@ee746299-78ed-0310-b773-934348b2243d> | 2005-09-05 10:00:53 +0000 |
---|---|---|
committer | hiro <hiro@ee746299-78ed-0310-b773-934348b2243d> | 2005-09-05 10:00:53 +0000 |
commit | 3bf24b9336184fe9e28f7e09b9c5200a5f82b7d2 (patch) | |
tree | 51ccac6f26dcdf9fcfac1a7879477bfde2759b80 /src/filter.c | |
parent | 11776e5a524745b01ac145439ac2892a29bd0826 (diff) |
moved more modules to libsylph.
git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@548 ee746299-78ed-0310-b773-934348b2243d
Diffstat (limited to 'src/filter.c')
-rw-r--r-- | src/filter.c | 1421 |
1 files changed, 0 insertions, 1421 deletions
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); -} |