claws-mail/src/filter.c
2001-04-19 12:21:46 +00:00

248 lines
6.3 KiB
C

/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
* Copyright (C) 1999,2000 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 <string.h>
#include <strings.h>
#include <stdlib.h>
#include "intl.h"
#include "procheader.h"
#include "filter.h"
#include "folder.h"
#include "utils.h"
FolderItem *filter_get_dest_folder(GSList *fltlist, const gchar *file)
{
static FolderItem *dummy = NULL;
FolderItem *dest_folder = NULL;
GSList *hlist, *cur;
Filter *filter;
g_return_val_if_fail(file != NULL, NULL);
if (!fltlist) return NULL;
hlist = procheader_get_header_list(file);
if (!hlist) return NULL;
for (cur = fltlist; cur != NULL; cur = cur->next) {
filter = (Filter *)cur->data;
if (filter_match_condition(filter, hlist)) {
if (filter->action == FLT_NOTRECV) {
if (!dummy) {
dummy = folder_item_new(NULL, NULL);
dummy->path = g_strdup(FILTER_NOT_RECEIVE);
}
dest_folder = dummy;
} else
dest_folder = folder_find_item_from_path
(filter->dest);
break;
}
}
procheader_header_list_destroy(hlist);
return dest_folder;
}
static gboolean strfind(const gchar *haystack, const gchar *needle)
{
return strstr(haystack, needle) != NULL ? TRUE : FALSE;
}
static gboolean strnotfind(const gchar *haystack, const gchar *needle)
{
return strstr(haystack, needle) != NULL ? FALSE : TRUE;
}
static gboolean strcasefind(const gchar *haystack, const gchar *needle)
{
return strcasestr(haystack, needle) != NULL ? TRUE : FALSE;
}
static gboolean strcasenotfind(const gchar *haystack, const gchar *needle)
{
return strcasestr(haystack, needle) != NULL ? FALSE : TRUE;
}
gboolean filter_match_condition(Filter *filter, GSList *hlist)
{
Header *header;
gboolean (*StrFind1) (const gchar *hs, const gchar *nd);
gboolean (*StrFind2) (const gchar *hs, const gchar *nd);
g_return_val_if_fail(filter->name1 != NULL, FALSE);
if (FLT_IS_CASE_SENS(filter->flag1))
StrFind1 = FLT_IS_CONTAIN(filter->flag1)
? strfind : strnotfind;
else
StrFind1 = FLT_IS_CONTAIN(filter->flag1)
? strcasefind : strcasenotfind;
if (FLT_IS_CASE_SENS(filter->flag2))
StrFind2 = FLT_IS_CONTAIN(filter->flag2)
? strfind : strnotfind;
else
StrFind2 = FLT_IS_CONTAIN(filter->flag2)
? strcasefind : strcasenotfind;
if (filter->cond == FLT_AND) {
gboolean match1 = FALSE, match2 = FALSE;
/* ignore second condition if not set */
if (!filter->name2) match2 = TRUE;
for (; hlist != NULL; hlist = hlist->next) {
header = hlist->data;
if (!match1 &&
!strcasecmp(header->name, filter->name1)) {
if (!filter->body1 ||
StrFind1(header->body, filter->body1))
match1 = TRUE;
}
if (!match2 &&
!strcasecmp(header->name, filter->name2)) {
if (!filter->body2 ||
StrFind2(header->body, filter->body2))
match2 = TRUE;
}
if (match1 && match2) return TRUE;
}
} else if (filter->cond == FLT_OR) {
for (; hlist != NULL; hlist = hlist->next) {
header = hlist->data;
if (!strcasecmp(header->name, filter->name1))
if (!filter->body1 ||
StrFind1(header->body, filter->body1))
return TRUE;
if (filter->name2 &&
!strcasecmp(header->name, filter->name2))
if (!filter->body2 ||
StrFind2(header->body, filter->body2))
return TRUE;
}
}
return FALSE;
}
gchar *filter_get_str(Filter *filter)
{
gchar *str;
str = g_strdup_printf
("%s\t%s\t%c\t%s\t%s\t%s\t%d\t%d\t%c",
filter->name1, filter->body1 ? filter->body1 : "",
filter->name2 ? (filter->cond == FLT_AND ? '&' : '|') : ' ',
filter->name2 ? filter->name2 : "",
filter->body2 ? filter->body2 : "",
filter->dest ? filter->dest : "",
(guint)filter->flag1, (guint)filter->flag2,
filter->action == FLT_MOVE ? 'm' :
filter->action == FLT_NOTRECV ? 'n' :
filter->action == FLT_DELETE ? 'd' : ' ');
return str;
}
#define PARSE_ONE_PARAM(p, srcp) \
{ \
p = strchr(srcp, '\t'); \
if (!p) return NULL; \
else \
*p++ = '\0'; \
}
Filter *filter_read_str(const gchar *str)
{
Filter *filter;
gchar *tmp;
gchar *name1, *body1, *op, *name2, *body2, *dest;
gchar *flag1 = NULL, *flag2 = NULL, *action = NULL;
Xalloca(tmp, strlen(str) + 1, return NULL);
strcpy(tmp, str);
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(action, flag2);
if ((p = strchr(action, '\t'))) *p = '\0';
}
filter = g_new0(Filter, 1);
filter->name1 = *name1 ? g_strdup(name1) : NULL;
filter->body1 = *body1 ? g_strdup(body1) : NULL;
filter->name2 = *name2 ? g_strdup(name2) : NULL;
filter->body2 = *body2 ? g_strdup(body2) : NULL;
filter->cond = (*op == '|') ? FLT_OR : FLT_AND;
filter->dest = *dest ? g_strdup(dest) : NULL;
filter->flag1 = FLT_CONTAIN;
filter->flag2 = FLT_CONTAIN;
if (flag1) filter->flag1 = (FilterFlag)strtoul(flag1, NULL, 10);
if (flag2) filter->flag2 = (FilterFlag)strtoul(flag2, NULL, 10);
if (!strcmp2(dest, FILTER_NOT_RECEIVE))
filter->action = FLT_NOTRECV;
else
filter->action = FLT_MOVE;
if (action) {
switch (*action) {
case 'm': filter->action = FLT_MOVE; break;
case 'n': filter->action = FLT_NOTRECV; break;
case 'd': filter->action = FLT_DELETE; break;
default: g_warning("Invalid action: `%c'\n", *action);
}
}
return filter;
}
void filter_free(Filter *filter)
{
if (!filter) return;
g_free(filter->name1);
g_free(filter->body1);
g_free(filter->name2);
g_free(filter->body2);
g_free(filter->dest);
g_free(filter);
}