9 #include "procheader.h"
11 #include "filtering.h"
14 #define PREFSBUFSIZE 1024
16 GSList * prefs_filtering = NULL;
18 FilteringAction * filteringaction_new(int type, int account_id,
21 FilteringAction * action;
23 action = g_new0(FilteringAction, 1);
26 action->account_id = account_id;
28 action->destination = g_strdup(destination);
33 void filteringaction_free(FilteringAction * action)
35 if (action->destination)
36 g_free(action->destination);
40 FilteringAction * filteringaction_parse(gchar ** str)
42 FilteringAction * action;
44 gchar * destination = NULL;
50 key = matcher_parse_keyword(&tmp);
53 case MATCHING_ACTION_MOVE:
54 destination = matcher_parse_str(&tmp);
60 case MATCHING_ACTION_COPY:
61 destination = matcher_parse_str(&tmp);
67 case MATCHING_ACTION_DELETE:
69 case MATCHING_ACTION_MARK:
71 case MATCHING_ACTION_MARK_AS_READ:
73 case MATCHING_ACTION_UNMARK:
75 case MATCHING_ACTION_MARK_AS_UNREAD:
77 case MATCHING_ACTION_FORWARD:
78 account_id = matcher_parse_number(&tmp);
84 destination = matcher_parse_str(&tmp);
91 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
92 account_id = matcher_parse_number(&tmp);
98 destination = matcher_parse_str(&tmp);
111 action = filteringaction_new(key, account_id, destination);
116 FilteringProp * filteringprop_parse(gchar ** str)
120 FilteringProp * filtering;
121 MatcherList * matchers;
122 FilteringAction * action;
126 matchers = matcherlist_parse(&tmp);
133 matcherlist_free(matchers);
138 action = filteringaction_parse(&tmp);
140 matcherlist_free(matchers);
145 filtering = filteringprop_new(matchers, action);
152 FilteringProp * filteringprop_new(MatcherList * matchers,
153 FilteringAction * action)
155 FilteringProp * filtering;
157 filtering = g_new0(FilteringProp, 1);
158 filtering->matchers = matchers;
159 filtering->action = action;
164 void filteringprop_free(FilteringProp * prop)
166 matcherlist_free(prop->matchers);
167 filteringaction_free(prop->action);
171 static gboolean filteringaction_update_mark(MsgInfo * info)
176 dest_path = folder_item_get_path(info->folder);
177 if (dest_path == NULL) {
178 g_warning(_("Can't open mark file.\n"));
182 if ((fp = procmsg_open_mark_file(dest_path, TRUE))
184 g_warning(_("Can't open mark file.\n"));
188 procmsg_write_flags(info, fp);
194 fitleringaction_apply
195 runs the action on one MsgInfo
196 return value : return TRUE if the action could be applied
199 static gboolean filteringaction_apply(FilteringAction * action, MsgInfo * info,
200 GHashTable *folder_table)
202 FolderItem * dest_folder;
205 switch(action->type) {
206 case MATCHING_ACTION_MOVE:
207 dest_folder = folder_find_item_from_path(action->destination);
211 if (folder_item_move_msg(dest_folder, info) == -1)
215 filteringaction_update_mark(info);
217 val = GPOINTER_TO_INT(g_hash_table_lookup
218 (folder_table, dest_folder));
220 folder_item_scan(dest_folder);
221 g_hash_table_insert(folder_table, dest_folder,
224 val = GPOINTER_TO_INT(g_hash_table_lookup
225 (folder_table, info->folder));
227 folder_item_scan(info->folder);
228 g_hash_table_insert(folder_table, info->folder,
234 case MATCHING_ACTION_COPY:
235 dest_folder = folder_find_item_from_path(action->destination);
239 if (folder_item_copy_msg(dest_folder, info) == -1)
242 val = GPOINTER_TO_INT(g_hash_table_lookup
243 (folder_table, dest_folder));
245 folder_item_scan(dest_folder);
246 g_hash_table_insert(folder_table, dest_folder,
252 case MATCHING_ACTION_DELETE:
253 if (folder_item_remove_msg(info->folder, info->msgnum) == -1)
257 filteringaction_update_mark(info);
261 case MATCHING_ACTION_MARK:
262 MSG_SET_FLAGS(info->flags, MSG_MARKED);
263 filteringaction_update_mark(info);
267 case MATCHING_ACTION_UNMARK:
268 MSG_UNSET_FLAGS(info->flags, MSG_MARKED);
269 filteringaction_update_mark(info);
273 case MATCHING_ACTION_MARK_AS_READ:
274 MSG_UNSET_FLAGS(info->flags, MSG_UNREAD | MSG_NEW);
275 filteringaction_update_mark(info);
279 case MATCHING_ACTION_MARK_AS_UNREAD:
280 MSG_SET_FLAGS(info->flags, MSG_UNREAD | MSG_NEW);
281 filteringaction_update_mark(info);
285 case MATCHING_ACTION_FORWARD:
289 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
300 runs the action on one MsgInfo if it matches the criterium
301 return value : return TRUE if the action doesn't allow more actions
304 static gboolean filteringprop_apply(FilteringProp * filtering, MsgInfo * info,
305 GHashTable *folder_table)
307 if (matcherlist_match(filtering->matchers, info)) {
313 result = filteringaction_apply(filtering->action, info,
316 filteringaction_to_string(filtering->action);
318 g_warning(_("action %s could not be applied"),
322 debug_print(_("message %i %s..."),
323 info->msgnum, action_str);
328 switch(filtering->action->type) {
329 case MATCHING_ACTION_MOVE:
330 case MATCHING_ACTION_DELETE:
332 case MATCHING_ACTION_COPY:
333 case MATCHING_ACTION_MARK:
334 case MATCHING_ACTION_MARK_AS_READ:
335 case MATCHING_ACTION_UNMARK:
336 case MATCHING_ACTION_MARK_AS_UNREAD:
337 case MATCHING_ACTION_FORWARD:
338 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
348 void filter_msginfo(GSList * filtering_list, MsgInfo * info,
349 GHashTable *folder_table)
354 g_warning(_("msginfo is not set"));
358 for(l = filtering_list ; l != NULL ; l = g_slist_next(l)) {
359 FilteringProp * filtering = (FilteringProp *) l->data;
361 if (filteringprop_apply(filtering, info, folder_table))
366 void filter_message(GSList * filtering_list, FolderItem * item,
367 gint msgnum, GHashTable *folder_table)
373 g_warning(_("folderitem not set"));
377 filename = folder_item_fetch_msg(item, msgnum);
379 if (filename == NULL) {
380 g_warning(_("filename is not set"));
384 msginfo = procheader_parse(filename, 0, TRUE);
388 if (msginfo == NULL) {
389 g_warning(_("could not get info for %s"), filename);
393 msginfo->folder = item;
394 msginfo->msgnum = msgnum;
396 filter_msginfo(filtering_list, msginfo, folder_table);
399 void prefs_filtering_read_config(void)
403 gchar buf[PREFSBUFSIZE];
405 debug_print(_("Reading filtering configuration...\n"));
407 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
409 if ((fp = fopen(rcpath, "r")) == NULL) {
410 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
412 prefs_filtering = NULL;
417 /* remove all filtering */
418 while (prefs_filtering != NULL) {
419 FilteringProp * filtering =
420 (FilteringProp *) prefs_filtering->data;
421 filteringprop_free(filtering);
422 prefs_filtering = g_slist_remove(prefs_filtering, filtering);
425 while (fgets(buf, sizeof(buf), fp) != NULL) {
426 FilteringProp * filtering;
431 if ((*buf != '#') && (*buf != '\0')) {
433 filtering = filteringprop_parse(&tmp);
436 g_slist_append(prefs_filtering,
441 g_warning(_("syntax error : %s\n"), buf);
449 gchar * filteringaction_to_string(FilteringAction * action)
453 gchar * account_id_str;
456 command_str = get_matchparser_tab_str(action->type);
458 if (command_str == NULL)
461 switch(action->type) {
462 case MATCHING_ACTION_MOVE:
463 case MATCHING_ACTION_COPY:
464 return g_strconcat(command_str, " \"", action->destination,
467 case MATCHING_ACTION_DELETE:
468 case MATCHING_ACTION_MARK:
469 case MATCHING_ACTION_UNMARK:
470 case MATCHING_ACTION_MARK_AS_READ:
471 case MATCHING_ACTION_MARK_AS_UNREAD:
472 return g_strdup(command_str);
475 case MATCHING_ACTION_FORWARD:
476 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
477 account_id_str = itos(action->account_id);
478 return g_strconcat(command_str, " ", account_id_str,
479 " \"", action->destination, "\"", NULL);
486 gchar * filteringprop_to_string(FilteringProp * prop)
490 gchar * filtering_str;
492 action_str = filteringaction_to_string(prop->action);
494 if (action_str == NULL)
497 list_str = matcherlist_to_string(prop->matchers);
499 if (list_str == NULL) {
504 filtering_str = g_strconcat(list_str, " ", action_str, NULL);
508 return filtering_str;
511 void prefs_filtering_write_config(void)
516 FilteringProp * prop;
518 debug_print(_("Writing filtering configuration...\n"));
520 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTERING_RC, NULL);
522 if ((pfile = prefs_write_open(rcpath)) == NULL) {
523 g_warning(_("failed to write configuration to file\n"));
528 for (cur = prefs_filtering; cur != NULL; cur = cur->next) {
529 gchar *filtering_str;
531 prop = (FilteringProp *) cur->data;
532 filtering_str = filteringprop_to_string(prop);
533 if (fputs(filtering_str, pfile->fp) == EOF ||
534 fputc('\n', pfile->fp) == EOF) {
535 FILE_OP_ERROR(rcpath, "fputs || fputc");
536 prefs_write_close_revert(pfile);
538 g_free(filtering_str);
541 g_free(filtering_str);
546 if (prefs_write_close(pfile) < 0) {
547 g_warning(_("failed to write configuration to file\n"));