This commit was manufactured by cvs2svn to create tag 'LAST_STABLE'.
[claws.git] / src / filter.c
blobb6043b1e41950ca299de918140267db4315b8d43
1 /*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2001 Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
24 #include <glib.h>
25 #include <string.h>
26 #include <strings.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <regex.h>
31 #include "intl.h"
32 #include "procheader.h"
33 #include "filter.h"
34 #include "folder.h"
35 #include "utils.h"
37 FolderItem *filter_get_dest_folder(GSList *fltlist, const gchar *file)
39 static FolderItem *dummy = NULL;
40 FolderItem *dest_folder = NULL;
41 GSList *hlist, *cur;
42 Filter *filter;
44 g_return_val_if_fail(file != NULL, NULL);
45 if (!fltlist) return NULL;
47 hlist = procheader_get_header_list_from_file(file);
48 if (!hlist) return NULL;
50 for (cur = fltlist; cur != NULL; cur = cur->next) {
51 filter = (Filter *)cur->data;
52 if (filter_match_condition(filter, hlist)) {
53 if (filter->action == FLT_NOTRECV) {
54 if (!dummy) {
55 dummy = folder_item_new(NULL, NULL);
56 dummy->path = g_strdup(FILTER_NOT_RECEIVE);
58 dest_folder = dummy;
59 } else
60 dest_folder = folder_find_item_from_identifier
61 (filter->dest);
62 break;
66 procheader_header_list_destroy(hlist);
68 return dest_folder;
71 static gboolean strfind(const gchar *haystack, const gchar *needle)
73 return strstr(haystack, needle) != NULL ? TRUE : FALSE;
76 static gboolean strnotfind(const gchar *haystack, const gchar *needle)
78 return strstr(haystack, needle) != NULL ? FALSE : TRUE;
81 static gboolean strcasefind(const gchar *haystack, const gchar *needle)
83 return strcasestr(haystack, needle) != NULL ? TRUE : FALSE;
86 static gboolean strcasenotfind(const gchar *haystack, const gchar *needle)
88 return strcasestr(haystack, needle) != NULL ? FALSE : TRUE;
91 static gboolean strmatch_regex(const gchar *haystack, const gchar *needle)
93 gint ret = 0;
94 regex_t preg;
95 regmatch_t pmatch[1];
97 ret = regcomp(&preg, needle, 0);
98 if (ret != 0) return FALSE;
100 ret = regexec(&preg, haystack, 1, pmatch, 0);
101 regfree(&preg);
103 if (ret == REG_NOMATCH) return FALSE;
105 if (pmatch[0].rm_so != -1)
106 return TRUE;
107 else
108 return FALSE;
111 gboolean filter_match_condition(Filter *filter, GSList *hlist)
113 Header *header;
114 gboolean (*StrFind1) (const gchar *hs, const gchar *nd);
115 gboolean (*StrFind2) (const gchar *hs, const gchar *nd);
117 g_return_val_if_fail(filter->name1 != NULL, FALSE);
119 if (FLT_IS_REGEX(filter->flag1))
120 StrFind1 = strmatch_regex;
121 else if (FLT_IS_CASE_SENS(filter->flag1))
122 StrFind1 = FLT_IS_CONTAIN(filter->flag1)
123 ? strfind : strnotfind;
124 else
125 StrFind1 = FLT_IS_CONTAIN(filter->flag1)
126 ? strcasefind : strcasenotfind;
128 if (FLT_IS_REGEX(filter->flag2))
129 StrFind2 = strmatch_regex;
130 if (FLT_IS_CASE_SENS(filter->flag2))
131 StrFind2 = FLT_IS_CONTAIN(filter->flag2)
132 ? strfind : strnotfind;
133 else
134 StrFind2 = FLT_IS_CONTAIN(filter->flag2)
135 ? strcasefind : strcasenotfind;
137 if (filter->cond == FLT_AND) {
138 gboolean match1 = FALSE, match2 = FALSE;
140 /* ignore second condition if not set */
141 if (!filter->name2) match2 = TRUE;
143 for (; hlist != NULL; hlist = hlist->next) {
144 header = hlist->data;
146 if (!match1 &&
147 procheader_headername_equal(header->name,
148 filter->name1)) {
149 if (!filter->body1 ||
150 StrFind1(header->body, filter->body1))
151 match1 = TRUE;
153 if (!match2 &&
154 procheader_headername_equal(header->name,
155 filter->name2)) {
156 if (!filter->body2 ||
157 StrFind2(header->body, filter->body2))
158 match2 = TRUE;
161 if (match1 && match2) return TRUE;
163 } else if (filter->cond == FLT_OR) {
164 for (; hlist != NULL; hlist = hlist->next) {
165 header = hlist->data;
167 if (procheader_headername_equal(header->name,
168 filter->name1))
169 if (!filter->body1 ||
170 StrFind1(header->body, filter->body1))
171 return TRUE;
172 if (filter->name2 &&
173 procheader_headername_equal(header->name,
174 filter->name2))
175 if (!filter->body2 ||
176 StrFind2(header->body, filter->body2))
177 return TRUE;
181 return FALSE;
184 gchar *filter_get_str(Filter *filter)
186 gchar *str;
188 str = g_strdup_printf
189 ("%s\t%s\t%c\t%s\t%s\t%s\t%d\t%d\t%c",
190 filter->name1, filter->body1 ? filter->body1 : "",
191 filter->name2 ? (filter->cond == FLT_AND ? '&' : '|') : ' ',
192 filter->name2 ? filter->name2 : "",
193 filter->body2 ? filter->body2 : "",
194 filter->dest ? filter->dest : "",
195 (guint)filter->flag1, (guint)filter->flag2,
196 filter->action == FLT_MOVE ? 'm' :
197 filter->action == FLT_NOTRECV ? 'n' :
198 filter->action == FLT_DELETE ? 'd' : ' ');
200 return str;
203 #define PARSE_ONE_PARAM(p, srcp) \
205 p = strchr(srcp, '\t'); \
206 if (!p) return NULL; \
207 else \
208 *p++ = '\0'; \
211 Filter *filter_read_str(const gchar *str)
213 Filter *filter;
214 gchar *tmp;
215 gchar *name1, *body1, *op, *name2, *body2, *dest;
216 gchar *flag1 = NULL, *flag2 = NULL, *action = NULL;
218 Xstrdup_a(tmp, str, return NULL);
220 name1 = tmp;
221 PARSE_ONE_PARAM(body1, name1);
222 PARSE_ONE_PARAM(op, body1);
223 PARSE_ONE_PARAM(name2, op);
224 PARSE_ONE_PARAM(body2, name2);
225 PARSE_ONE_PARAM(dest, body2);
226 if (strchr(dest, '\t')) {
227 gchar *p;
229 PARSE_ONE_PARAM(flag1, dest);
230 PARSE_ONE_PARAM(flag2, flag1);
231 PARSE_ONE_PARAM(action, flag2);
232 if ((p = strchr(action, '\t'))) *p = '\0';
235 filter = g_new0(Filter, 1);
236 filter->name1 = *name1 ? g_strdup(name1) : NULL;
237 filter->body1 = *body1 ? g_strdup(body1) : NULL;
238 filter->name2 = *name2 ? g_strdup(name2) : NULL;
239 filter->body2 = *body2 ? g_strdup(body2) : NULL;
240 filter->cond = (*op == '|') ? FLT_OR : FLT_AND;
241 filter->dest = *dest ? g_strdup(dest) : NULL;
243 filter->flag1 = FLT_CONTAIN;
244 filter->flag2 = FLT_CONTAIN;
245 if (flag1) filter->flag1 = (FilterFlag)strtoul(flag1, NULL, 10);
246 if (flag2) filter->flag2 = (FilterFlag)strtoul(flag2, NULL, 10);
248 if (!strcmp2(dest, FILTER_NOT_RECEIVE))
249 filter->action = FLT_NOTRECV;
250 else
251 filter->action = FLT_MOVE;
252 if (action) {
253 switch (*action) {
254 case 'm': filter->action = FLT_MOVE; break;
255 case 'n': filter->action = FLT_NOTRECV; break;
256 case 'd': filter->action = FLT_DELETE; break;
257 default: g_warning("Invalid action: `%c'\n", *action);
261 return filter;
264 void filter_free(Filter *filter)
266 if (!filter) return;
268 g_free(filter->name1);
269 g_free(filter->body1);
271 g_free(filter->name2);
272 g_free(filter->body2);
274 g_free(filter->dest);
276 g_free(filter);