added 'recieve at get all' to 'Edit accounts' window
[claws.git] / src / filter.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999,2000 Hiroyuki Yamamoto
4  *
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.
9  *
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.
14  *
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.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <glib.h>
25 #include <string.h>
26 #include <strings.h>
27 #include <stdlib.h>
28
29 #include "intl.h"
30 #include "procheader.h"
31 #include "filter.h"
32 #include "folder.h"
33 #include "utils.h"
34
35 FolderItem *filter_get_dest_folder(GSList *fltlist, const gchar *file)
36 {
37         static FolderItem *dummy = NULL;
38         FolderItem *dest_folder = NULL;
39         GSList *hlist, *cur;
40         Filter *filter;
41
42         g_return_val_if_fail(file != NULL, NULL);
43         if (!fltlist) return NULL;
44
45         hlist = procheader_get_header_list_from_file(file);
46         if (!hlist) return NULL;
47
48         for (cur = fltlist; cur != NULL; cur = cur->next) {
49                 filter = (Filter *)cur->data;
50                 if (filter_match_condition(filter, hlist)) {
51                         if (filter->action == FLT_NOTRECV) {
52                                 if (!dummy) {
53                                         dummy = folder_item_new(NULL, NULL);
54                                         dummy->path = g_strdup(FILTER_NOT_RECEIVE);
55                                 }
56                                 dest_folder = dummy;
57                         } else
58                                 dest_folder = folder_find_item_from_path
59                                         (filter->dest);
60                         break;
61                 }
62         }
63
64         procheader_header_list_destroy(hlist);
65
66         return dest_folder;
67 }
68
69 static gboolean strfind(const gchar *haystack, const gchar *needle)
70 {
71         return strstr(haystack, needle) != NULL ? TRUE : FALSE;
72 }
73
74 static gboolean strnotfind(const gchar *haystack, const gchar *needle)
75 {
76         return strstr(haystack, needle) != NULL ? FALSE : TRUE;
77 }
78
79 static gboolean strcasefind(const gchar *haystack, const gchar *needle)
80 {
81         return strcasestr(haystack, needle) != NULL ? TRUE : FALSE;
82 }
83
84 static gboolean strcasenotfind(const gchar *haystack, const gchar *needle)
85 {
86         return strcasestr(haystack, needle) != NULL ? FALSE : TRUE;
87 }
88
89 gboolean filter_match_condition(Filter *filter, GSList *hlist)
90 {
91         Header *header;
92         gboolean (*StrFind1)    (const gchar *hs, const gchar *nd);
93         gboolean (*StrFind2)    (const gchar *hs, const gchar *nd);
94
95         g_return_val_if_fail(filter->name1 != NULL, FALSE);
96
97         if (FLT_IS_CASE_SENS(filter->flag1))
98                 StrFind1 = FLT_IS_CONTAIN(filter->flag1)
99                         ? strfind : strnotfind;
100         else
101                 StrFind1 = FLT_IS_CONTAIN(filter->flag1)
102                         ? strcasefind : strcasenotfind;
103
104         if (FLT_IS_CASE_SENS(filter->flag2))
105                 StrFind2 = FLT_IS_CONTAIN(filter->flag2)
106                         ? strfind : strnotfind;
107         else
108                 StrFind2 = FLT_IS_CONTAIN(filter->flag2)
109                         ? strcasefind : strcasenotfind;
110
111         if (filter->cond == FLT_AND) {
112                 gboolean match1 = FALSE, match2 = FALSE;
113
114                 /* ignore second condition if not set */
115                 if (!filter->name2) match2 = TRUE;
116
117                 for (; hlist != NULL; hlist = hlist->next) {
118                         header = hlist->data;
119
120                         if (!match1 &&
121                             procheader_headername_equal(header->name,
122                                                         filter->name1)) {
123                                 if (!filter->body1 ||
124                                     StrFind1(header->body, filter->body1))
125                                         match1 = TRUE;
126                         }
127                         if (!match2 &&
128                             procheader_headername_equal(header->name,
129                                                          filter->name2)) {
130                                 if (!filter->body2 ||
131                                     StrFind2(header->body, filter->body2))
132                                         match2 = TRUE;
133                         }
134
135                         if (match1 && match2) return TRUE;
136                 }
137         } else if (filter->cond == FLT_OR) {
138                 for (; hlist != NULL; hlist = hlist->next) {
139                         header = hlist->data;
140
141                         if (procheader_headername_equal(header->name,
142                                                         filter->name1))
143                                 if (!filter->body1 ||
144                                     StrFind1(header->body, filter->body1))
145                                         return TRUE;
146                         if (filter->name2 &&
147                             procheader_headername_equal(header->name,
148                                                         filter->name2))
149                                 if (!filter->body2 ||
150                                     StrFind2(header->body, filter->body2))
151                                         return TRUE;
152                 }
153         }
154
155         return FALSE;
156 }
157
158 gchar *filter_get_str(Filter *filter)
159 {
160         gchar *str;
161
162         str = g_strdup_printf
163                 ("%s\t%s\t%c\t%s\t%s\t%s\t%d\t%d\t%c",
164                  filter->name1, filter->body1 ? filter->body1 : "",
165                  filter->name2 ? (filter->cond == FLT_AND ? '&' : '|') : ' ',
166                  filter->name2 ? filter->name2 : "",
167                  filter->body2 ? filter->body2 : "",
168                  filter->dest ? filter->dest : "",
169                  (guint)filter->flag1, (guint)filter->flag2,
170                  filter->action == FLT_MOVE    ? 'm' :
171                  filter->action == FLT_NOTRECV ? 'n' :
172                  filter->action == FLT_DELETE  ? 'd' : ' ');
173
174         return str;
175 }
176
177 #define PARSE_ONE_PARAM(p, srcp) \
178 { \
179         p = strchr(srcp, '\t'); \
180         if (!p) return NULL; \
181         else \
182                 *p++ = '\0'; \
183 }
184
185 Filter *filter_read_str(const gchar *str)
186 {
187         Filter *filter;
188         gchar *tmp;
189         gchar *name1, *body1, *op, *name2, *body2, *dest;
190         gchar *flag1 = NULL, *flag2 = NULL, *action = NULL;
191
192         Xalloca(tmp, strlen(str) + 1, return NULL);
193         strcpy(tmp, str);
194
195         name1 = tmp;
196         PARSE_ONE_PARAM(body1, name1);
197         PARSE_ONE_PARAM(op, body1);
198         PARSE_ONE_PARAM(name2, op);
199         PARSE_ONE_PARAM(body2, name2);
200         PARSE_ONE_PARAM(dest, body2);
201         if (strchr(dest, '\t')) {
202                 gchar *p;
203
204                 PARSE_ONE_PARAM(flag1, dest);
205                 PARSE_ONE_PARAM(flag2, flag1);
206                 PARSE_ONE_PARAM(action, flag2);
207                 if ((p = strchr(action, '\t'))) *p = '\0';
208         }
209
210         filter = g_new0(Filter, 1);
211         filter->name1 = *name1 ? g_strdup(name1) : NULL;
212         filter->body1 = *body1 ? g_strdup(body1) : NULL;
213         filter->name2 = *name2 ? g_strdup(name2) : NULL;
214         filter->body2 = *body2 ? g_strdup(body2) : NULL;
215         filter->cond = (*op == '|') ? FLT_OR : FLT_AND;
216         filter->dest = *dest ? g_strdup(dest) : NULL;
217
218         filter->flag1 = FLT_CONTAIN;
219         filter->flag2 = FLT_CONTAIN;
220         if (flag1) filter->flag1 = (FilterFlag)strtoul(flag1, NULL, 10);
221         if (flag2) filter->flag2 = (FilterFlag)strtoul(flag2, NULL, 10);
222
223         if (!strcmp2(dest, FILTER_NOT_RECEIVE))
224                 filter->action = FLT_NOTRECV;
225         else
226                 filter->action = FLT_MOVE;
227         if (action) {
228                 switch (*action) {
229                 case 'm': filter->action = FLT_MOVE;    break;
230                 case 'n': filter->action = FLT_NOTRECV; break;
231                 case 'd': filter->action = FLT_DELETE;  break;
232                 default:  g_warning("Invalid action: `%c'\n", *action);
233                 }
234         }
235
236         return filter;
237 }
238
239 void filter_free(Filter *filter)
240 {
241         if (!filter) return;
242
243         g_free(filter->name1);
244         g_free(filter->body1);
245
246         g_free(filter->name2);
247         g_free(filter->body2);
248
249         g_free(filter->dest);
250
251         g_free(filter);
252 }