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 destination = matcher_parse_str(&tmp);
62 case MATCHING_ACTION_COPY:
63 destination = matcher_parse_str(&tmp);
69 case MATCHING_ACTION_DELETE:
71 case MATCHING_ACTION_MARK:
73 case MATCHING_ACTION_MARK_AS_READ:
75 case MATCHING_ACTION_UNMARK:
77 case MATCHING_ACTION_MARK_AS_UNREAD:
79 case MATCHING_ACTION_FORWARD:
80 account_id = matcher_parse_number(&tmp);
86 destination = matcher_parse_str(&tmp);
93 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
94 account_id = matcher_parse_number(&tmp);
100 destination = matcher_parse_str(&tmp);
113 action = filteringaction_new(key, account_id, destination);
118 FilteringProp * filteringprop_parse(gchar ** str)
122 FilteringProp * filtering;
123 MatcherList * matchers;
124 FilteringAction * action;
128 matchers = matcherlist_parse(&tmp);
135 matcherlist_free(matchers);
140 action = filteringaction_parse(&tmp);
142 matcherlist_free(matchers);
147 filtering = filteringprop_new(matchers, action);
154 FilteringProp * filteringprop_new(MatcherList * matchers,
155 FilteringAction * action)
157 FilteringProp * filtering;
159 filtering = g_new0(FilteringProp, 1);
160 filtering->matchers = matchers;
161 filtering->action = action;
166 void filteringprop_free(FilteringProp * prop)
168 matcherlist_free(prop->matchers);
169 filteringaction_free(prop->action);
173 static gboolean filteringaction_update_mark(MsgInfo * info)
178 if (info->folder->folder->type == F_MH) {
179 dest_path = folder_item_get_path(info->folder);
180 if (!is_dir_exist(dest_path))
181 make_dir_hier(dest_path);
183 if (dest_path == NULL) {
184 g_warning(_("Can't open mark file.\n"));
188 if ((fp = procmsg_open_mark_file(dest_path, TRUE))
190 g_warning(_("Can't open mark file.\n"));
194 procmsg_write_flags(info, fp);
202 fitleringaction_apply
203 runs the action on one MsgInfo
204 return value : return TRUE if the action could be applied
207 #define CHANGE_FLAGS(msginfo) \
209 if (msginfo->folder->folder->change_flags != NULL) \
210 msginfo->folder->folder->change_flags(msginfo->folder->folder, \
215 static gboolean filteringaction_apply(FilteringAction * action, MsgInfo * info,
216 GHashTable *folder_table)
218 FolderItem * dest_folder;
221 PrefsAccount * account;
223 switch(action->type) {
224 case MATCHING_ACTION_MOVE:
226 folder_find_item_from_identifier(action->destination);
230 if (folder_item_move_msg(dest_folder, info) == -1)
234 filteringaction_update_mark(info);
237 val = GPOINTER_TO_INT(g_hash_table_lookup
238 (folder_table, dest_folder));
240 folder_item_scan(dest_folder);
241 g_hash_table_insert(folder_table, dest_folder,
244 val = GPOINTER_TO_INT(g_hash_table_lookup
245 (folder_table, info->folder));
247 folder_item_scan(info->folder);
248 g_hash_table_insert(folder_table, info->folder,
255 case MATCHING_ACTION_COPY:
257 folder_find_item_from_identifier(action->destination);
261 if (folder_item_copy_msg(dest_folder, info) == -1)
265 val = GPOINTER_TO_INT(g_hash_table_lookup
266 (folder_table, dest_folder));
268 folder_item_scan(dest_folder);
269 g_hash_table_insert(folder_table, dest_folder,
276 case MATCHING_ACTION_DELETE:
277 if (folder_item_remove_msg(info->folder, info->msgnum) == -1)
281 filteringaction_update_mark(info);
285 case MATCHING_ACTION_MARK:
286 MSG_SET_FLAGS(info->flags, MSG_MARKED);
287 filteringaction_update_mark(info);
293 case MATCHING_ACTION_UNMARK:
294 MSG_UNSET_FLAGS(info->flags, MSG_MARKED);
295 filteringaction_update_mark(info);
301 case MATCHING_ACTION_MARK_AS_READ:
302 MSG_UNSET_FLAGS(info->flags, MSG_UNREAD | MSG_NEW);
303 filteringaction_update_mark(info);
309 case MATCHING_ACTION_MARK_AS_UNREAD:
310 MSG_SET_FLAGS(info->flags, MSG_UNREAD | MSG_NEW);
311 filteringaction_update_mark(info);
317 case MATCHING_ACTION_FORWARD:
319 account = account_find_from_id(action->account_id);
320 compose = compose_forward(account, info, FALSE);
321 if (compose->account->protocol == A_NNTP)
322 compose_entry_append(compose, action->destination,
325 compose_entry_append(compose, action->destination,
328 val = compose_send(compose);
330 gtk_widget_destroy(compose->window);
334 gtk_widget_destroy(compose->window);
337 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
339 account = account_find_from_id(action->account_id);
340 compose = compose_forward(account, info, TRUE);
341 if (compose->account->protocol == A_NNTP)
342 compose_entry_append(compose, action->destination,
345 compose_entry_append(compose, action->destination,
348 val = compose_send(compose);
350 gtk_widget_destroy(compose->window);
354 gtk_widget_destroy(compose->window);
364 runs the action on one MsgInfo if it matches the criterium
365 return value : return TRUE if the action doesn't allow more actions
368 static gboolean filteringprop_apply(FilteringProp * filtering, MsgInfo * info,
369 GHashTable *folder_table)
371 if (matcherlist_match(filtering->matchers, info)) {
377 result = filteringaction_apply(filtering->action, info,
380 filteringaction_to_string(filtering->action);
382 g_warning(_("action %s could not be applied"),
386 debug_print(_("message %i %s..."),
387 info->msgnum, action_str);
392 switch(filtering->action->type) {
393 case MATCHING_ACTION_MOVE:
394 case MATCHING_ACTION_DELETE:
396 case MATCHING_ACTION_COPY:
397 case MATCHING_ACTION_MARK:
398 case MATCHING_ACTION_MARK_AS_READ:
399 case MATCHING_ACTION_UNMARK:
400 case MATCHING_ACTION_MARK_AS_UNREAD:
401 case MATCHING_ACTION_FORWARD:
402 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
412 void filter_msginfo(GSList * filtering_list, MsgInfo * info,
413 GHashTable *folder_table)
418 g_warning(_("msginfo is not set"));
422 for(l = filtering_list ; l != NULL ; l = g_slist_next(l)) {
423 FilteringProp * filtering = (FilteringProp *) l->data;
425 if (filteringprop_apply(filtering, info, folder_table))
430 void filter_msginfo_move_or_delete(GSList * filtering_list, MsgInfo * info,
431 GHashTable *folder_table)
436 g_warning(_("msginfo is not set"));
440 for(l = filtering_list ; l != NULL ; l = g_slist_next(l)) {
441 FilteringProp * filtering = (FilteringProp *) l->data;
443 switch (filtering->action->type) {
444 case MATCHING_ACTION_MOVE:
445 case MATCHING_ACTION_DELETE:
446 if (filteringprop_apply(filtering, info, folder_table))
452 void filter_message(GSList * filtering_list, FolderItem * item,
453 gint msgnum, GHashTable *folder_table)
459 g_warning(_("folderitem not set"));
463 filename = folder_item_fetch_msg(item, msgnum);
465 if (filename == NULL) {
466 g_warning(_("filename is not set"));
470 msginfo = procheader_parse(filename, 0, TRUE);
474 if (msginfo == NULL) {
475 g_warning(_("could not get info for %s"), filename);
479 msginfo->folder = item;
480 msginfo->msgnum = msgnum;
482 filter_msginfo(filtering_list, msginfo, folder_table);
485 void prefs_filtering_read_config(void)
489 gchar buf[PREFSBUFSIZE];
491 debug_print(_("Reading filtering configuration...\n"));
493 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
495 if ((fp = fopen(rcpath, "r")) == NULL) {
496 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
498 prefs_filtering = NULL;
503 /* remove all filtering */
504 while (prefs_filtering != NULL) {
505 FilteringProp * filtering =
506 (FilteringProp *) prefs_filtering->data;
507 filteringprop_free(filtering);
508 prefs_filtering = g_slist_remove(prefs_filtering, filtering);
511 while (fgets(buf, sizeof(buf), fp) != NULL) {
512 FilteringProp * filtering;
517 if ((*buf != '#') && (*buf != '\0')) {
519 filtering = filteringprop_parse(&tmp);
522 g_slist_append(prefs_filtering,
527 g_warning(_("syntax error : %s\n"), buf);
535 gchar * filteringaction_to_string(FilteringAction * action)
539 gchar * account_id_str;
542 command_str = get_matchparser_tab_str(action->type);
544 if (command_str == NULL)
547 switch(action->type) {
548 case MATCHING_ACTION_MOVE:
549 case MATCHING_ACTION_COPY:
550 return g_strconcat(command_str, " \"", action->destination,
553 case MATCHING_ACTION_DELETE:
554 case MATCHING_ACTION_MARK:
555 case MATCHING_ACTION_UNMARK:
556 case MATCHING_ACTION_MARK_AS_READ:
557 case MATCHING_ACTION_MARK_AS_UNREAD:
558 return g_strdup(command_str);
561 case MATCHING_ACTION_FORWARD:
562 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
563 account_id_str = itos(action->account_id);
564 return g_strconcat(command_str, " ", account_id_str,
565 " \"", action->destination, "\"", NULL);
572 gchar * filteringprop_to_string(FilteringProp * prop)
576 gchar * filtering_str;
578 action_str = filteringaction_to_string(prop->action);
580 if (action_str == NULL)
583 list_str = matcherlist_to_string(prop->matchers);
585 if (list_str == NULL) {
590 filtering_str = g_strconcat(list_str, " ", action_str, NULL);
594 return filtering_str;
597 void prefs_filtering_write_config(void)
602 FilteringProp * prop;
604 debug_print(_("Writing filtering configuration...\n"));
606 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTERING_RC, NULL);
608 if ((pfile = prefs_write_open(rcpath)) == NULL) {
609 g_warning(_("failed to write configuration to file\n"));
614 for (cur = prefs_filtering; cur != NULL; cur = cur->next) {
615 gchar *filtering_str;
617 prop = (FilteringProp *) cur->data;
618 filtering_str = filteringprop_to_string(prop);
619 if (fputs(filtering_str, pfile->fp) == EOF ||
620 fputc('\n', pfile->fp) == EOF) {
621 FILE_OP_ERROR(rcpath, "fputs || fputc");
622 prefs_write_close_revert(pfile);
624 g_free(filtering_str);
627 g_free(filtering_str);
632 if (prefs_write_close(pfile) < 0) {
633 g_warning(_("failed to write configuration to file\n"));