9 #include "procheader.h"
11 #include "filtering.h"
14 #define PREFSBUFSIZE 1024
16 GSList * prefs_filtering = NULL;
18 FilteringAction * filteringaction_new(int type, gchar * dest_folder,
19 int account_id, gchar * address,
22 FilteringAction * action;
24 action = g_new0(FilteringAction, 1);
28 action->dest_folder = g_strdup(dest_folder);
30 action->address = address;
35 void filteringaction_free(FilteringAction * action)
37 if (action->dest_folder)
38 g_free(action->dest_folder);
40 g_free(action->address);
41 if (action->newsgroups)
42 g_free(action->newsgroups);
46 FilteringAction * filteringaction_parse(gchar ** str)
48 FilteringAction * action;
50 gchar * dest_folder = NULL;
51 gchar * address = NULL;
52 gchar * newsgroups = NULL;
58 key = matcher_parse_keyword(&tmp);
61 case MATCHING_ACTION_MOVE:
62 dest_folder = matcher_parse_str(&tmp);
67 case MATCHING_ACTION_COPY:
68 dest_folder = matcher_parse_str(&tmp);
70 case MATCHING_ACTION_DELETE:
72 case MATCHING_ACTION_MARK:
74 case MATCHING_ACTION_MARK_AS_READ:
76 case MATCHING_ACTION_UNMARK:
78 case MATCHING_ACTION_MARK_AS_UNREAD:
80 case MATCHING_ACTION_FORWARD:
81 account_id = matcher_parse_number(&tmp);
85 address = matcher_parse_str(&tmp);
90 case MATCHING_ACTION_FORWARD_AS_ATTACHEMENT:
91 account_id = matcher_parse_number(&tmp);
95 address = matcher_parse_str(&tmp);
100 case MATCHING_ACTION_FORWARD_NEWS:
101 account_id = matcher_parse_number(&tmp);
105 newsgroups = matcher_parse_str(&tmp);
110 case MATCHING_ACTION_FORWARD_NEWS_AS_ATTACHEMENT:
111 account_id = matcher_parse_number(&tmp);
115 newsgroups = matcher_parse_str(&tmp);
126 action = filteringaction_new(key, dest_folder,
127 account_id, address, newsgroups);
132 FilteringProp * filteringprop_parse(gchar ** str)
136 FilteringProp * filtering;
137 MatcherList * matchers;
138 FilteringAction * action;
142 matchers = matcherlist_parse(&tmp);
149 matcherlist_free(matchers);
154 action = filteringaction_parse(&tmp);
156 matcherlist_free(matchers);
161 filtering = filteringprop_new(matchers, action);
168 FilteringProp * filteringprop_new(MatcherList * matchers,
169 FilteringAction * action)
171 FilteringProp * filtering;
173 filtering = g_new0(FilteringProp, 1);
174 filtering->matchers = matchers;
175 filtering->action = action;
180 void filteringprop_free(FilteringProp * prop)
182 matcherlist_free(prop->matchers);
183 filteringaction_free(prop->action);
187 static gboolean filteringaction_update_mark(MsgInfo * info)
192 dest_path = folder_item_get_path(info->folder);
193 if (dest_path == NULL) {
194 g_warning(_("Can't open mark file.\n"));
198 if ((fp = procmsg_open_mark_file(dest_path, TRUE))
200 g_warning(_("Can't open mark file.\n"));
204 procmsg_write_flags(info, fp);
210 fitleringaction_apply
211 runs the action on one MsgInfo
212 return value : return TRUE if the action could be applied
215 static gboolean filteringaction_apply(FilteringAction * action, MsgInfo * info,
216 GHashTable *folder_table)
218 FolderItem * dest_folder;
221 switch(action->type) {
222 case MATCHING_ACTION_MOVE:
223 dest_folder = folder_find_item_from_path(action->dest_folder);
227 if (folder_item_move_msg(dest_folder, info) == -1)
231 filteringaction_update_mark(info);
233 val = GPOINTER_TO_INT(g_hash_table_lookup
234 (folder_table, dest_folder));
236 folder_item_scan(dest_folder);
237 g_hash_table_insert(folder_table, dest_folder,
240 val = GPOINTER_TO_INT(g_hash_table_lookup
241 (folder_table, info->folder));
243 folder_item_scan(info->folder);
244 g_hash_table_insert(folder_table, info->folder,
250 case MATCHING_ACTION_COPY:
251 dest_folder = folder_find_item_from_path(action->dest_folder);
255 if (folder_item_copy_msg(dest_folder, info) == -1)
258 val = GPOINTER_TO_INT(g_hash_table_lookup
259 (folder_table, dest_folder));
261 folder_item_scan(dest_folder);
262 g_hash_table_insert(folder_table, dest_folder,
268 case MATCHING_ACTION_DELETE:
269 if (folder_item_remove_msg(dest_folder, info->msgnum) == -1)
273 filteringaction_update_mark(info);
277 case MATCHING_ACTION_MARK:
278 MSG_SET_FLAGS(info->flags, MSG_MARKED);
279 filteringaction_update_mark(info);
283 case MATCHING_ACTION_UNMARK:
284 MSG_UNSET_FLAGS(info->flags, MSG_MARKED);
285 filteringaction_update_mark(info);
289 case MATCHING_ACTION_MARK_AS_READ:
290 MSG_UNSET_FLAGS(info->flags, MSG_UNREAD | MSG_NEW);
291 filteringaction_update_mark(info);
295 case MATCHING_ACTION_MARK_AS_UNREAD:
296 MSG_SET_FLAGS(info->flags, MSG_UNREAD | MSG_NEW);
297 filteringaction_update_mark(info);
301 case MATCHING_ACTION_FORWARD:
305 case MATCHING_ACTION_FORWARD_AS_ATTACHEMENT:
309 case MATCHING_ACTION_FORWARD_NEWS:
313 case MATCHING_ACTION_FORWARD_NEWS_AS_ATTACHEMENT:
324 runs the action on one MsgInfo if it matches the criterium
325 return value : return TRUE if the action doesn't allow more actions
328 static gboolean filteringprop_apply(FilteringProp * filtering, MsgInfo * info,
329 GHashTable *folder_table)
331 if (matcherlist_match(filtering->matchers, info)) {
337 result = filteringaction_apply(filtering->action, info,
340 filteringaction_to_string(filtering->action);
342 g_warning(_("action %s could not be applied"),
346 debug_print(_("message %i %s..."),
347 info->msgnum, action_str);
352 switch(filtering->action->type) {
353 case MATCHING_ACTION_MOVE:
354 case MATCHING_ACTION_DELETE:
356 case MATCHING_ACTION_COPY:
357 case MATCHING_ACTION_MARK:
358 case MATCHING_ACTION_MARK_AS_READ:
359 case MATCHING_ACTION_UNMARK:
360 case MATCHING_ACTION_MARK_AS_UNREAD:
361 case MATCHING_ACTION_FORWARD:
362 case MATCHING_ACTION_FORWARD_AS_ATTACHEMENT:
363 case MATCHING_ACTION_FORWARD_NEWS:
364 case MATCHING_ACTION_FORWARD_NEWS_AS_ATTACHEMENT:
374 void filter_msginfo(GSList * filtering_list, MsgInfo * info,
375 GHashTable *folder_table)
380 g_warning(_("msginfo is not set"));
384 for(l = filtering_list ; l != NULL ; l = g_slist_next(l)) {
385 FilteringProp * filtering = (FilteringProp *) l->data;
387 if (filteringprop_apply(filtering, info, folder_table))
392 void filter_message(GSList * filtering_list, FolderItem * item,
393 gint msgnum, GHashTable *folder_table)
399 g_warning(_("folderitem not set"));
403 filename = folder_item_fetch_msg(item, msgnum);
405 if (filename == NULL) {
406 g_warning(_("filename is not set"));
410 msginfo = procheader_parse(filename, 0, TRUE);
414 if (msginfo == NULL) {
415 g_warning(_("could not get info for %s"), filename);
419 msginfo->folder = item;
420 msginfo->msgnum = msgnum;
422 filter_msginfo(filtering_list, msginfo, folder_table);
425 void prefs_filtering_read_config(void)
429 gchar buf[PREFSBUFSIZE];
431 debug_print(_("Reading filtering configuration...\n"));
433 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
435 if ((fp = fopen(rcpath, "r")) == NULL) {
436 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
438 prefs_filtering = NULL;
443 /* remove all filtering */
444 while (prefs_filtering != NULL) {
445 FilteringProp * filtering =
446 (FilteringProp *) prefs_filtering->data;
447 filteringprop_free(filtering);
448 prefs_filtering = g_slist_remove(prefs_filtering, filtering);
451 while (fgets(buf, sizeof(buf), fp) != NULL) {
452 FilteringProp * filtering;
457 if ((*buf != '#') && (*buf != '\0')) {
459 filtering = filteringprop_parse(&tmp);
462 g_slist_append(prefs_filtering,
467 g_warning(_("syntax error : %s\n"), buf);
476 struct _FilteringAction {
483 MATCHING_ACTION_MOVE,
484 MATCHING_ACTION_COPY,
485 MATCHING_ACTION_DELETE,
486 MATCHING_ACTION_MARK,
487 MATCHING_ACTION_MARK_AS_READ,
488 MATCHING_ACTION_FORWARD,
489 MATCHING_ACTION_FORWARD_AS_ATTACHEMENT,
490 MATCHING_ACTION_FORWARD_NEWS,
491 MATCHING_ACTION_FORWARD_NEWS_AS_ATTACHEMENT,
494 gchar * filteringaction_to_string(FilteringAction * action)
498 gchar * account_id_str;
501 command_str = get_matchparser_tab_str(action->type);
503 if (command_str == NULL)
506 switch(action->type) {
507 case MATCHING_ACTION_MOVE:
508 case MATCHING_ACTION_COPY:
509 return g_strconcat(command_str, " ", action->dest_folder,
512 case MATCHING_ACTION_DELETE:
513 case MATCHING_ACTION_MARK:
514 case MATCHING_ACTION_UNMARK:
515 case MATCHING_ACTION_MARK_AS_READ:
516 case MATCHING_ACTION_MARK_AS_UNREAD:
517 return g_strdup(command_str);
520 case MATCHING_ACTION_FORWARD:
521 case MATCHING_ACTION_FORWARD_AS_ATTACHEMENT:
522 account_id_str = itos(action->account_id);
523 return g_strconcat(command_str, " ", account_id_str,
524 " \"", action->address, "\"", NULL);
526 case MATCHING_ACTION_FORWARD_NEWS:
527 case MATCHING_ACTION_FORWARD_NEWS_AS_ATTACHEMENT:
528 account_id_str = itos(action->account_id);
529 return g_strconcat(command_str, " ", account_id_str,
530 " \"", action->newsgroups, "\"", NULL);
537 gchar * filteringprop_to_string(FilteringProp * prop)
541 gchar * filtering_str;
543 action_str = filteringaction_to_string(prop->action);
545 if (action_str == NULL)
548 list_str = matcherlist_to_string(prop->matchers);
550 if (list_str == NULL) {
555 filtering_str = g_strconcat(list_str, " ", action_str, NULL);
559 return filtering_str;
562 void prefs_filtering_write_config(void)
567 FilteringProp * prop;
569 debug_print(_("Writing filtering configuration...\n"));
571 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTERING_RC, NULL);
573 if ((pfile = prefs_write_open(rcpath)) == NULL) {
574 g_warning(_("failed to write configuration to file\n"));
579 for (cur = prefs_filtering; cur != NULL; cur = cur->next) {
580 gchar *filtering_str;
582 prop = (FilteringProp *) cur->data;
583 filtering_str = filteringprop_to_string(prop);
584 if (fputs(filtering_str, pfile->fp) == EOF ||
585 fputc('\n', pfile->fp) == EOF) {
586 FILE_OP_ERROR(rcpath, "fputs || fputc");
587 prefs_write_close_revert(pfile);
589 g_free(filtering_str);
592 g_free(filtering_str);
597 if (prefs_write_close(pfile) < 0) {
598 g_warning(_("failed to write configuration to file\n"));