1 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
2 /* Balsa E-Mail Client
3  *
4  * Copyright (C) 1997-2013 Stuart Parmenter and others,
5  *                         See the file AUTHORS for a list.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20  * 02111-1307, USA.
21  */
22 /*
23  * filter.h
24  *
25  * Header for libfilter, the mail filtering porting of balsa
26  *
27  * Authors:  Joel Becker - Emmanuel Allaud
28  */
29 
30 #ifndef __FILTER_H__
31 #define __FILTER_H__
32 
33 #include <glib.h>
34 
35 #include <time.h>
36 #include "libbalsa.h"
37 
38 typedef struct _LibBalsaConditionRegex LibBalsaConditionRegex;
39 
40 /* Conditions definition :
41  * a condition is the basic component of a filter
42  * It can be of type (mimic the old filter types) :
43  * - CONDITION_STRING : matches when a string is contained in
44  *   one of the specified fields
45  * - CONDITION_REGEX : matches when one of the reg exs matches on one
46  *   of the specified fields
47  * - CONDITION_EXEC : matches when the execution of the given command
48  *   with parameters (FIXME : what are they???, see proposition for filter command) returns 1
49  *
50  * A condition has attributes :
51  * - fields : a gint specifying on which fields to apply the condition
52  * - negate : a gboolean to negate (logical not) the condition
53  */
54 
55 /* condition match types */
56 
57 typedef enum {
58     CONDITION_NONE,
59     CONDITION_STRING, /*  */
60     CONDITION_REGEX,
61     CONDITION_DATE,
62     CONDITION_FLAG,
63     CONDITION_AND, /* Condition has a list of subconditions and
64                     * matches if all the subconditions match. */
65     CONDITION_OR   /* Condition has a list of subconditions and
66                     * matches if any subcondition matches. */
67 } ConditionMatchType;
68 
69 struct _LibBalsaCondition {
70     gint ref_count;
71     gboolean negate; /* negate the result of the condition. */
72     ConditionMatchType type;
73 
74     /* The match type fields */
75     union _match {
76         /* CONDITION_STRING */
77         struct {
78             unsigned fields;     /* Contains the header list for
79                                   * that this search should look in. */
80             gchar * string;
81             gchar * user_header; /* This is !=NULL and gives the name
82                                   * of the user header against which
83                                   * we make the match if fields
84                                   * includes
85                                   * CONDITION_MATCH_US_HEAD. */
86         } string;
87         /* CONDITION_REGEX */
88         struct {
89             unsigned fields;     /* Contains the header list for
90                                   * that this search should look in. */
91             /* GSList * regexs; */
92         } regex;
93         /* CONDITION_DATE */
94 	struct {
95 	    time_t date_low,date_high; /* for CONDITION_DATE            */
96                                        /* (date_high==0=>no high limit) */
97 	} date;
98         /* CONDITION_FLAG */
99 	LibBalsaMessageFlag flags;
100 
101         /* CONDITION_AND and CONDITION_OR */
102         struct {
103             LibBalsaCondition *left, *right;
104         } andor;
105     } match;
106 };
107 
108 LibBalsaCondition* libbalsa_condition_new_from_string(gchar **string);
109 gchar*             libbalsa_condition_to_string(LibBalsaCondition *cond);
110 gchar*             libbalsa_condition_to_string_user(LibBalsaCondition *cond);
111 
112 LibBalsaCondition* libbalsa_condition_new_flag_enum(gboolean negated,
113                                                     LibBalsaMessageFlag flgs);
114 
115 LibBalsaCondition* libbalsa_condition_new_string(gboolean negated,
116                                                  unsigned headers,
117                                                  gchar *str,
118                                                  gchar *user_header);
119 LibBalsaCondition* libbalsa_condition_new_date(gboolean negated,
120                                                time_t *from, time_t *to);
121 LibBalsaCondition* libbalsa_condition_new_bool_ptr(gboolean negated,
122                                                    ConditionMatchType cmt,
123                                                    LibBalsaCondition *left,
124                                                    LibBalsaCondition *right);
125 LibBalsaCondition* libbalsa_condition_ref(LibBalsaCondition* cnd);
126 void               libbalsa_condition_unref(LibBalsaCondition*);
127 
128 
129 typedef enum {
130     FILTER_NOOP,
131     FILTER_OP_OR,
132     FILTER_OP_AND             /* Must be the last one */
133 } FilterOpType;
134 
135 /* Filter definition :
136  * a filter is defined by
137  * - a list of conditions and a gint conditions_op
138  *   specifying the logical op to apply on the result of the condition match
139  * - an action to perform on match : move, copy, print or trash the
140  *   matching message, emit a sound, popup a text, execute a command
141  */
142 
143 typedef enum {
144     FILTER_NOTHING,
145     FILTER_COPY,
146     FILTER_MOVE,
147     FILTER_PRINT,
148     FILTER_RUN,
149     FILTER_TRASH,
150     FILTER_COLOR,
151     FILTER_N_TYPES
152 } FilterActionType;
153 
154 /*
155  * filter error codes
156  * (not an enum cause they *have* to match filter_errlist)
157  */
158 
159 #define FILTER_NOERR         0
160 #define FILTER_EFILESYN      1
161 #define FILTER_ENOMEM        2
162 #define FILTER_EREGSYN       3
163 #define FILTER_EINVALID      4
164 
165 /*
166  * Filter errors set the variable filter_errno (like errno)
167  * See policy to use it in filter-error.c
168  */
169 extern gint filter_errno;
170 
171 typedef struct _LibBalsaFilter {
172 
173     gchar *name;
174     gint flags;
175 
176     LibBalsaCondition *condition; /* A codition, possibly a composite
177                                    * one. */
178 
179     /* The notification fields : NULL signifies no notification */
180     gchar * sound;
181     gchar * popup_text;
182 
183     /* The action */
184     FilterActionType action;
185     /* action_string depends on action :
186      * - if action is FILTER_MOVE, or FILTER_COPY, action_string is
187      *   the URL (this is mandatory because it determines UNIQUELY
188      *   the mailbox, unlike the name) of the mailbox to move/copy
189      *   the matching message
190      * - if action is FILTER_RUN, action_string is the command to run
191      *   for now this is the way to specify parameters (replaced by
192      *   pieces of the matching message) for the running command,
193      *   proposition : %f,%t,%c,%s are replaced by the corresponding
194      *   header (from,to,cc,subject) field of the matching message on
195      *   the command line with enclosing quotes if necessary, e.g. :
196      *   command_to_run %t %s -----> command_to_run manu@wanadoo.fr
197      *   "about filters" If you want the body, we must find a way to
198      *   pipe it to the std input of the command (FIXME what do we do
199      *   for different parts, attachments and so on?)
200      * - if action is FILTER_TRASH it's NULL
201      * - FIXME if action is FILTER_PRINT it could be the print command ?
202      */
203     gchar * action_string;
204 } LibBalsaFilter;
205 
206 /*
207  * Exported filter functions A lot are, to have a fine-grained API so
208  * we can use filter engine for a lot of different purpose : search
209  * functions, virtual folders..., not only filtering
210  */
211 
212 void libbalsa_condition_regex_set(LibBalsaConditionRegex * reg, gchar *str);
213 /* returns pointer to internal data, treat with caution! */
214 const gchar* libbalsa_condition_regex_get(LibBalsaConditionRegex * reg);
215 
216 void libbalsa_condition_prepend_regex(LibBalsaCondition* cond,
217                                       LibBalsaConditionRegex *new_reg);
218 
219 /** libbalsa_condition_matches() checks whether given message matches the
220  * condition. */
221 gboolean libbalsa_condition_matches(LibBalsaCondition* cond,
222                                     LibBalsaMessage* message);
223 
224 /* Filtering functions */
225 /* FIXME : perhaps I should try to use multithreading -> but we must
226    therefore use lock very well */
227 /* prepare_filters_to_run will test all filters for correctness,
228    compile regexs if needed
229  * Return
230  * - TRUE on success (all filters are valid, ready to be applied)
231  * - FALSE if there are invalid filters
232  */
233 
234 gint filters_prepare_to_run(GSList * filters);
235 
236 /* Apply the filter action to the list of messages.
237  * It returns TRUE if the trash bin has been filled with something
238  * this is used to call enable_empty_trash after
239  */
240 
241 gboolean libbalsa_filter_mailbox_messages(LibBalsaFilter * filt,
242 					  LibBalsaMailbox * mailbox,
243 					  GArray * msgnos);
244 
245 /*
246  * libbalsa_filter_get_by_name()
247  * search in the filter list the filter of name fname or NULL if unfound
248  */
249 
250 LibBalsaFilter* libbalsa_filter_get_by_name(const gchar* fname);
251 
252 /*
253  * Dialog calls
254  */
255 /* filters_edit_dialog launches (guess what :) the filters edit dialog box
256  * to modify the list of all filters
257  */
258 void filters_edit_dialog(void);
259 
260 /* filter_run_dialog edits and runs the list of filters of the mailbox
261  */
262 void filters_run_dialog(LibBalsaMailbox *mbox);
263 
264 /* filter_export_dialog to export filters as sieve scripts
265  */
266 
267 void
268 filters_export_dialog(void);
269 
270 void libbalsa_filters_set_trash(LibBalsaMailbox* new_trash);
271 typedef LibBalsaMailbox* (*UrlToMailboxMapper)(const gchar* url);
272 void libbalsa_filters_set_url_mapper(UrlToMailboxMapper u2mm);
273 void libbalsa_filters_set_filter_list(GSList** list);
274 
275 /*
276  * Error calls
277  */
278 gchar *filter_strerror(gint filter_errnum);
279 void filter_perror(const gchar * s);
280 
281 /* Test */
282 gboolean libbalsa_condition_can_match(LibBalsaCondition * cond,
283 				      LibBalsaMessage * message);
284 gboolean libbalsa_condition_is_flag_only(LibBalsaCondition * cond,
285                                          LibBalsaMailbox * mailbox,
286                                          guint msgno, gboolean * match);
287 
288 /* Compatibility */
289 LibBalsaCondition *libbalsa_condition_new_2_0(const gchar *
290                                               filter_section_name,
291                                               ConditionMatchType cmt);
292 
293 #endif				/* __FILTER_H__ */
294