10 #include "procheader.h"
12 #include "filtering.h"
16 #define PREFSBUFSIZE 1024
18 GSList * prefs_filtering = NULL;
20 FilteringAction * filteringaction_new(int type, int account_id,
23 FilteringAction * action;
25 action = g_new0(FilteringAction, 1);
28 action->account_id = account_id;
30 action->destination = g_strdup(destination);
35 void filteringaction_free(FilteringAction * action)
37 if (action->destination)
38 g_free(action->destination);
42 FilteringAction * filteringaction_parse(gchar ** str)
44 FilteringAction * action;
46 gchar * destination = NULL;
52 key = matcher_parse_keyword(&tmp);
55 case MATCHING_ACTION_MOVE:
56 case MATCHING_ACTION_COPY:
57 case MATCHING_EXECUTE:
58 destination = matcher_parse_str(&tmp);
64 case MATCHING_ACTION_DELETE:
66 case MATCHING_ACTION_MARK:
68 case MATCHING_ACTION_MARK_AS_READ:
70 case MATCHING_ACTION_UNMARK:
72 case MATCHING_ACTION_MARK_AS_UNREAD:
74 case MATCHING_ACTION_FORWARD:
75 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
76 account_id = matcher_parse_number(&tmp);
82 destination = matcher_parse_str(&tmp);
95 action = filteringaction_new(key, account_id, destination);
100 FilteringProp * filteringprop_parse(gchar ** str)
104 FilteringProp * filtering;
105 MatcherList * matchers;
106 FilteringAction * action;
110 matchers = matcherlist_parse(&tmp);
117 matcherlist_free(matchers);
122 action = filteringaction_parse(&tmp);
124 matcherlist_free(matchers);
129 filtering = filteringprop_new(matchers, action);
136 FilteringProp * filteringprop_new(MatcherList * matchers,
137 FilteringAction * action)
139 FilteringProp * filtering;
141 filtering = g_new0(FilteringProp, 1);
142 filtering->matchers = matchers;
143 filtering->action = action;
148 void filteringprop_free(FilteringProp * prop)
150 matcherlist_free(prop->matchers);
151 filteringaction_free(prop->action);
155 static gboolean filteringaction_update_mark(MsgInfo * info)
160 if (info->folder->folder->type == F_MH) {
161 dest_path = folder_item_get_path(info->folder);
162 if (!is_dir_exist(dest_path))
163 make_dir_hier(dest_path);
165 if (dest_path == NULL) {
166 g_warning(_("Can't open mark file.\n"));
170 if ((fp = procmsg_open_mark_file(dest_path, TRUE))
172 g_warning(_("Can't open mark file.\n"));
176 procmsg_write_flags(info, fp);
183 static gchar * filteringaction_execute_command(gchar * cmd, MsgInfo * info)
186 gchar * filename = NULL;
187 gchar * processed_cmd;
191 size = strlen(cmd) + 1;
199 case 's': /* subject */
200 size += strlen(info->subject) - 2;
203 size += strlen(info->from) - 2;
206 size += strlen(info->to) - 2;
209 size += strlen(info->cc) - 2;
212 size += strlen(info->date) - 2;
214 case 'i': /* message-id */
215 size += strlen(info->msgid) - 2;
217 case 'n': /* newsgroups */
218 size += strlen(info->newsgroups) - 2;
220 case 'r': /* references */
221 size += strlen(info->references) - 2;
224 filename = folder_item_fetch_msg(info->folder,
227 if (filename == NULL) {
228 g_warning(_("filename is not set"));
232 size += strlen(filename) - 2;
241 processed_cmd = g_new0(gchar, size);
253 case 's': /* subject */
254 if (info->subject != NULL)
255 strcpy(p, info->subject);
261 if (info->from != NULL)
262 strcpy(p, info->from);
268 if (info->to != NULL)
275 if (info->cc != NULL)
282 if (info->date != NULL)
283 strcpy(p, info->date);
288 case 'i': /* message-id */
289 if (info->msgid != NULL)
290 strcpy(p, info->msgid);
295 case 'n': /* newsgroups */
296 if (info->newsgroups != NULL)
297 strcpy(p, info->newsgroups);
302 case 'r': /* references */
303 if (info->references != NULL)
304 strcpy(p, info->references);
328 return processed_cmd;
332 fitleringaction_apply
333 runs the action on one MsgInfo
334 return value : return TRUE if the action could be applied
337 #define CHANGE_FLAGS(msginfo) \
339 if (msginfo->folder->folder->change_flags != NULL) \
340 msginfo->folder->folder->change_flags(msginfo->folder->folder, \
345 static gboolean filteringaction_apply(FilteringAction * action, MsgInfo * info,
346 GHashTable *folder_table)
348 FolderItem * dest_folder;
351 PrefsAccount * account;
354 switch(action->type) {
355 case MATCHING_ACTION_MOVE:
357 folder_find_item_from_identifier(action->destination);
361 if (folder_item_move_msg(dest_folder, info) == -1)
365 filteringaction_update_mark(info);
368 val = GPOINTER_TO_INT(g_hash_table_lookup
369 (folder_table, dest_folder));
371 folder_item_scan(dest_folder);
372 g_hash_table_insert(folder_table, dest_folder,
375 val = GPOINTER_TO_INT(g_hash_table_lookup
376 (folder_table, info->folder));
378 folder_item_scan(info->folder);
379 g_hash_table_insert(folder_table, info->folder,
386 case MATCHING_ACTION_COPY:
388 folder_find_item_from_identifier(action->destination);
392 if (folder_item_copy_msg(dest_folder, info) == -1)
396 val = GPOINTER_TO_INT(g_hash_table_lookup
397 (folder_table, dest_folder));
399 folder_item_scan(dest_folder);
400 g_hash_table_insert(folder_table, dest_folder,
407 case MATCHING_ACTION_DELETE:
408 if (folder_item_remove_msg(info->folder, info->msgnum) == -1)
412 filteringaction_update_mark(info);
416 case MATCHING_ACTION_MARK:
417 MSG_SET_FLAGS(info->flags, MSG_MARKED);
418 filteringaction_update_mark(info);
424 case MATCHING_ACTION_UNMARK:
425 MSG_UNSET_FLAGS(info->flags, MSG_MARKED);
426 filteringaction_update_mark(info);
432 case MATCHING_ACTION_MARK_AS_READ:
433 MSG_UNSET_FLAGS(info->flags, MSG_UNREAD | MSG_NEW);
434 filteringaction_update_mark(info);
440 case MATCHING_ACTION_MARK_AS_UNREAD:
441 MSG_SET_FLAGS(info->flags, MSG_UNREAD | MSG_NEW);
442 filteringaction_update_mark(info);
448 case MATCHING_ACTION_FORWARD:
450 account = account_find_from_id(action->account_id);
451 compose = compose_forward(account, info, FALSE);
452 if (compose->account->protocol == A_NNTP)
453 compose_entry_append(compose, action->destination,
456 compose_entry_append(compose, action->destination,
459 val = compose_send(compose);
461 gtk_widget_destroy(compose->window);
465 gtk_widget_destroy(compose->window);
468 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
470 account = account_find_from_id(action->account_id);
471 compose = compose_forward(account, info, TRUE);
472 if (compose->account->protocol == A_NNTP)
473 compose_entry_append(compose, action->destination,
476 compose_entry_append(compose, action->destination,
479 val = compose_send(compose);
481 gtk_widget_destroy(compose->window);
485 gtk_widget_destroy(compose->window);
488 case MATCHING_EXECUTE:
490 cmd = matching_build_command(action->destination, info);
507 runs the action on one MsgInfo if it matches the criterium
508 return value : return TRUE if the action doesn't allow more actions
511 static gboolean filteringprop_apply(FilteringProp * filtering, MsgInfo * info,
512 GHashTable *folder_table)
514 if (matcherlist_match(filtering->matchers, info)) {
520 result = filteringaction_apply(filtering->action, info,
523 filteringaction_to_string(filtering->action);
525 g_warning(_("action %s could not be applied"),
529 debug_print(_("message %i %s..."),
530 info->msgnum, action_str);
535 switch(filtering->action->type) {
536 case MATCHING_ACTION_MOVE:
537 case MATCHING_ACTION_DELETE:
539 case MATCHING_EXECUTE:
540 case MATCHING_ACTION_COPY:
541 case MATCHING_ACTION_MARK:
542 case MATCHING_ACTION_MARK_AS_READ:
543 case MATCHING_ACTION_UNMARK:
544 case MATCHING_ACTION_MARK_AS_UNREAD:
545 case MATCHING_ACTION_FORWARD:
546 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
556 void filter_msginfo(GSList * filtering_list, MsgInfo * info,
557 GHashTable *folder_table)
562 g_warning(_("msginfo is not set"));
566 for(l = filtering_list ; l != NULL ; l = g_slist_next(l)) {
567 FilteringProp * filtering = (FilteringProp *) l->data;
569 if (filteringprop_apply(filtering, info, folder_table))
574 void filter_msginfo_move_or_delete(GSList * filtering_list, MsgInfo * info,
575 GHashTable *folder_table)
580 g_warning(_("msginfo is not set"));
584 for(l = filtering_list ; l != NULL ; l = g_slist_next(l)) {
585 FilteringProp * filtering = (FilteringProp *) l->data;
587 switch (filtering->action->type) {
588 case MATCHING_ACTION_MOVE:
589 case MATCHING_ACTION_DELETE:
590 if (filteringprop_apply(filtering, info, folder_table))
596 void filter_message(GSList * filtering_list, FolderItem * item,
597 gint msgnum, GHashTable *folder_table)
603 g_warning(_("folderitem not set"));
607 filename = folder_item_fetch_msg(item, msgnum);
609 if (filename == NULL) {
610 g_warning(_("filename is not set"));
614 msginfo = procheader_parse(filename, 0, TRUE);
618 if (msginfo == NULL) {
619 g_warning(_("could not get info for %s"), filename);
623 msginfo->folder = item;
624 msginfo->msgnum = msgnum;
626 filter_msginfo(filtering_list, msginfo, folder_table);
629 void prefs_filtering_read_config(void)
633 gchar buf[PREFSBUFSIZE];
635 debug_print(_("Reading filtering configuration...\n"));
637 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
639 if ((fp = fopen(rcpath, "r")) == NULL) {
640 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
642 prefs_filtering = NULL;
647 /* remove all filtering */
648 while (prefs_filtering != NULL) {
649 FilteringProp * filtering =
650 (FilteringProp *) prefs_filtering->data;
651 filteringprop_free(filtering);
652 prefs_filtering = g_slist_remove(prefs_filtering, filtering);
655 while (fgets(buf, sizeof(buf), fp) != NULL) {
656 FilteringProp * filtering;
661 if ((*buf != '#') && (*buf != '\0')) {
663 filtering = filteringprop_parse(&tmp);
666 g_slist_append(prefs_filtering,
671 g_warning(_("syntax error : %s\n"), buf);
679 gchar * filteringaction_to_string(FilteringAction * action)
683 gchar * account_id_str;
686 command_str = get_matchparser_tab_str(action->type);
688 if (command_str == NULL)
691 switch(action->type) {
692 case MATCHING_ACTION_MOVE:
693 case MATCHING_ACTION_COPY:
694 case MATCHING_EXECUTE:
695 return g_strconcat(command_str, " \"", action->destination,
698 case MATCHING_ACTION_DELETE:
699 case MATCHING_ACTION_MARK:
700 case MATCHING_ACTION_UNMARK:
701 case MATCHING_ACTION_MARK_AS_READ:
702 case MATCHING_ACTION_MARK_AS_UNREAD:
703 return g_strdup(command_str);
706 case MATCHING_ACTION_FORWARD:
707 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
708 account_id_str = itos(action->account_id);
709 return g_strconcat(command_str, " ", account_id_str,
710 " \"", action->destination, "\"", NULL);
717 gchar * filteringprop_to_string(FilteringProp * prop)
721 gchar * filtering_str;
723 action_str = filteringaction_to_string(prop->action);
725 if (action_str == NULL)
728 list_str = matcherlist_to_string(prop->matchers);
730 if (list_str == NULL) {
735 filtering_str = g_strconcat(list_str, " ", action_str, NULL);
739 return filtering_str;
742 void prefs_filtering_write_config(void)
747 FilteringProp * prop;
749 debug_print(_("Writing filtering configuration...\n"));
751 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTERING_RC, NULL);
753 if ((pfile = prefs_write_open(rcpath)) == NULL) {
754 g_warning(_("failed to write configuration to file\n"));
759 for (cur = prefs_filtering; cur != NULL; cur = cur->next) {
760 gchar *filtering_str;
762 prop = (FilteringProp *) cur->data;
763 filtering_str = filteringprop_to_string(prop);
764 if (fputs(filtering_str, pfile->fp) == EOF ||
765 fputc('\n', pfile->fp) == EOF) {
766 FILE_OP_ERROR(rcpath, "fputs || fputc");
767 prefs_write_close_revert(pfile);
769 g_free(filtering_str);
772 g_free(filtering_str);
777 if (prefs_write_close(pfile) < 0) {
778 g_warning(_("failed to write configuration to file\n"));