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);
236 val = GPOINTER_TO_INT(g_hash_table_lookup
237 (folder_table, dest_folder));
239 folder_item_scan(dest_folder);
240 g_hash_table_insert(folder_table, dest_folder,
243 val = GPOINTER_TO_INT(g_hash_table_lookup
244 (folder_table, info->folder));
246 folder_item_scan(info->folder);
247 g_hash_table_insert(folder_table, info->folder,
253 case MATCHING_ACTION_COPY:
255 folder_find_item_from_identifier(action->destination);
259 if (folder_item_copy_msg(dest_folder, info) == -1)
262 val = GPOINTER_TO_INT(g_hash_table_lookup
263 (folder_table, dest_folder));
265 folder_item_scan(dest_folder);
266 g_hash_table_insert(folder_table, dest_folder,
272 case MATCHING_ACTION_DELETE:
273 if (folder_item_remove_msg(info->folder, info->msgnum) == -1)
277 filteringaction_update_mark(info);
281 case MATCHING_ACTION_MARK:
282 MSG_SET_FLAGS(info->flags, MSG_MARKED);
283 filteringaction_update_mark(info);
289 case MATCHING_ACTION_UNMARK:
290 MSG_UNSET_FLAGS(info->flags, MSG_MARKED);
291 filteringaction_update_mark(info);
297 case MATCHING_ACTION_MARK_AS_READ:
298 MSG_UNSET_FLAGS(info->flags, MSG_UNREAD | MSG_NEW);
299 filteringaction_update_mark(info);
305 case MATCHING_ACTION_MARK_AS_UNREAD:
306 MSG_SET_FLAGS(info->flags, MSG_UNREAD | MSG_NEW);
307 filteringaction_update_mark(info);
313 case MATCHING_ACTION_FORWARD:
315 account = account_find_from_id(action->account_id);
316 compose = compose_forward(account, info, FALSE);
317 if (compose->account->protocol == A_NNTP)
318 compose_entry_append(compose, action->destination,
321 compose_entry_append(compose, action->destination,
324 val = compose_send(compose);
326 gtk_widget_destroy(compose->window);
330 gtk_widget_destroy(compose->window);
333 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
335 account = account_find_from_id(action->account_id);
336 compose = compose_forward(account, info, TRUE);
337 if (compose->account->protocol == A_NNTP)
338 compose_entry_append(compose, action->destination,
341 compose_entry_append(compose, action->destination,
344 val = compose_send(compose);
346 gtk_widget_destroy(compose->window);
350 gtk_widget_destroy(compose->window);
360 runs the action on one MsgInfo if it matches the criterium
361 return value : return TRUE if the action doesn't allow more actions
364 static gboolean filteringprop_apply(FilteringProp * filtering, MsgInfo * info,
365 GHashTable *folder_table)
367 if (matcherlist_match(filtering->matchers, info)) {
373 result = filteringaction_apply(filtering->action, info,
376 filteringaction_to_string(filtering->action);
378 g_warning(_("action %s could not be applied"),
382 debug_print(_("message %i %s..."),
383 info->msgnum, action_str);
388 switch(filtering->action->type) {
389 case MATCHING_ACTION_MOVE:
390 case MATCHING_ACTION_DELETE:
392 case MATCHING_ACTION_COPY:
393 case MATCHING_ACTION_MARK:
394 case MATCHING_ACTION_MARK_AS_READ:
395 case MATCHING_ACTION_UNMARK:
396 case MATCHING_ACTION_MARK_AS_UNREAD:
397 case MATCHING_ACTION_FORWARD:
398 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
408 void filter_msginfo(GSList * filtering_list, MsgInfo * info,
409 GHashTable *folder_table)
414 g_warning(_("msginfo is not set"));
418 for(l = filtering_list ; l != NULL ; l = g_slist_next(l)) {
419 FilteringProp * filtering = (FilteringProp *) l->data;
421 if (filteringprop_apply(filtering, info, folder_table))
426 void filter_message(GSList * filtering_list, FolderItem * item,
427 gint msgnum, GHashTable *folder_table)
433 g_warning(_("folderitem not set"));
437 filename = folder_item_fetch_msg(item, msgnum);
439 if (filename == NULL) {
440 g_warning(_("filename is not set"));
444 msginfo = procheader_parse(filename, 0, TRUE);
448 if (msginfo == NULL) {
449 g_warning(_("could not get info for %s"), filename);
453 msginfo->folder = item;
454 msginfo->msgnum = msgnum;
456 filter_msginfo(filtering_list, msginfo, folder_table);
459 void prefs_filtering_read_config(void)
463 gchar buf[PREFSBUFSIZE];
465 debug_print(_("Reading filtering configuration...\n"));
467 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
469 if ((fp = fopen(rcpath, "r")) == NULL) {
470 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
472 prefs_filtering = NULL;
477 /* remove all filtering */
478 while (prefs_filtering != NULL) {
479 FilteringProp * filtering =
480 (FilteringProp *) prefs_filtering->data;
481 filteringprop_free(filtering);
482 prefs_filtering = g_slist_remove(prefs_filtering, filtering);
485 while (fgets(buf, sizeof(buf), fp) != NULL) {
486 FilteringProp * filtering;
491 if ((*buf != '#') && (*buf != '\0')) {
493 filtering = filteringprop_parse(&tmp);
496 g_slist_append(prefs_filtering,
501 g_warning(_("syntax error : %s\n"), buf);
509 gchar * filteringaction_to_string(FilteringAction * action)
513 gchar * account_id_str;
516 command_str = get_matchparser_tab_str(action->type);
518 if (command_str == NULL)
521 switch(action->type) {
522 case MATCHING_ACTION_MOVE:
523 case MATCHING_ACTION_COPY:
524 return g_strconcat(command_str, " \"", action->destination,
527 case MATCHING_ACTION_DELETE:
528 case MATCHING_ACTION_MARK:
529 case MATCHING_ACTION_UNMARK:
530 case MATCHING_ACTION_MARK_AS_READ:
531 case MATCHING_ACTION_MARK_AS_UNREAD:
532 return g_strdup(command_str);
535 case MATCHING_ACTION_FORWARD:
536 case MATCHING_ACTION_FORWARD_AS_ATTACHMENT:
537 account_id_str = itos(action->account_id);
538 return g_strconcat(command_str, " ", account_id_str,
539 " \"", action->destination, "\"", NULL);
546 gchar * filteringprop_to_string(FilteringProp * prop)
550 gchar * filtering_str;
552 action_str = filteringaction_to_string(prop->action);
554 if (action_str == NULL)
557 list_str = matcherlist_to_string(prop->matchers);
559 if (list_str == NULL) {
564 filtering_str = g_strconcat(list_str, " ", action_str, NULL);
568 return filtering_str;
571 void prefs_filtering_write_config(void)
576 FilteringProp * prop;
578 debug_print(_("Writing filtering configuration...\n"));
580 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, FILTERING_RC, NULL);
582 if ((pfile = prefs_write_open(rcpath)) == NULL) {
583 g_warning(_("failed to write configuration to file\n"));
588 for (cur = prefs_filtering; cur != NULL; cur = cur->next) {
589 gchar *filtering_str;
591 prop = (FilteringProp *) cur->data;
592 filtering_str = filteringprop_to_string(prop);
593 if (fputs(filtering_str, pfile->fp) == EOF ||
594 fputc('\n', pfile->fp) == EOF) {
595 FILE_OP_ERROR(rcpath, "fputs || fputc");
596 prefs_write_close_revert(pfile);
598 g_free(filtering_str);
601 g_free(filtering_str);
606 if (prefs_write_close(pfile) < 0) {
607 g_warning(_("failed to write configuration to file\n"));