/* * Copyright notice from original mutt: * Copyright (C) 1996-2000 Michael R. Elkins * * This file is part of mutt-ng, see http://www.muttng.org/. * It's licensed under the GNU General Public License, * please see the file GPL in the top level source directory. */ #include #include "mutt.h" #include "sort.h" #include "pattern.h" #include "score.h" @import "lib-lua/base.cpkg" typedef struct score_t { char *str; pattern_t *pat; int val; int exact; /* if this rule matches, don't evaluate any more */ struct score_t *next; } score_t; DO_INIT(score_t, score); static void score_wipe(score_t *sc) { pattern_list_wipe(&sc->pat); p_delete(&sc->str); } DO_NEW(score_t, score); DO_DELETE(score_t, score); DO_SLIST(score_t, score, score_delete); static score_t *Score = NULL; @package mod_score { bool enable = 1; /* ** .pp ** When this variable is \fIunset\fP, scoring is turned off. This can ** be useful to selectively disable scoring for certain folders when the ** ``$$score_threshold_delete'' variable and friends are used. ** */ int threshold_flag = 9999; /* ** .pp ** Messages which have been assigned a score greater than or equal to this ** variable's value are automatically marked ``flagged''. */ int threshold_delete = -1; /* ** .pp ** Messages which have been assigned a score equal to or lower than the value ** of this variable are automatically marked for deletion by Madmutt. Since ** Madmutt scores are always greater than or equal to zero, the default setting ** of this variable will never mark a message for deletion. */ int threshold_read = -1; /* ** .pp ** Messages which have been assigned a score equal to or lower than the value ** of this variable are automatically marked as read by Madmutt. Since ** Madmutt scores are always greater than or equal to zero, the default setting ** of this variable will never mark a message read. */ void score(string_t pattern, int value) { const char *pc; score_t **last; for (last = &Score; *last; last = &(*last)->next) { if (!m_strcmp(pattern, (*last)->str)) break; } if (!*last) { /* FIXME need a buffer for error */ struct pattern_t *pat = mutt_pattern_comp(pattern, 0, NULL); if (!pat) { p_delete(&pattern); RETURN(); } *last = score_new(); (*last)->pat = pat; (*last)->str = pattern; } pc = pattern; pc += (*last)->exact = (*pc == '='); (*last)->val = value; set_option(OPTNEEDRESCORE); RETURN(); }; void unscore(const string_t pattern) { if (!m_strcmp(pattern, "*")) { score_list_wipe(&Score); set_option(OPTNEEDRESCORE); RETURN(); } for (score_t **last = &Score; *last; last = &(*last)->next) { if (!m_strcmp(pattern, (*last)->str)) { score_t *tmp = score_list_pop(last); score_delete(&tmp); set_option(OPTNEEDRESCORE); break; } } RETURN(); }; }; void mutt_score_message (CONTEXT * ctx, HEADER * hdr, int upd_ctx) { hdr->score = 0; /* in case of re-scoring */ for (score_t *tmp = Score; tmp; tmp = tmp->next) { if (mutt_pattern_exec (tmp->pat, M_MATCH_FULL_ADDRESS, NULL, hdr) > 0) { if (tmp->exact || tmp->val == 9999 || tmp->val == -9999) { hdr->score = tmp->val; break; } hdr->score += tmp->val; } } if (hdr->score < 0) hdr->score = 0; if (hdr->score <= mod_score.threshold_delete) _mutt_set_flag(ctx, hdr, M_DELETE, 1, upd_ctx); if (hdr->score <= mod_score.threshold_read) _mutt_set_flag(ctx, hdr, M_READ, 1, upd_ctx); if (hdr->score >= mod_score.threshold_flag) _mutt_set_flag(ctx, hdr, M_FLAG, 1, upd_ctx); } void mutt_check_rescore (CONTEXT * ctx) { if (option(OPTNEEDRESCORE) && mod_score.enable) { if (((Sort | SortAux) & SORT_MASK) == SORT_SCORE) { set_option(OPTNEEDRESORT); if ((Sort & SORT_MASK) == SORT_THREADS) set_option(OPTSORTSUBTHREADS); } /* must redraw the index since the user might have %N in it */ set_option(OPTFORCEREDRAWINDEX); set_option(OPTFORCEREDRAWPAGER); for (int i = 0; ctx && i < ctx->msgcount; i++) { mutt_score_message(ctx, ctx->hdrs[i], 1); ctx->hdrs[i]->pair = 0; } } unset_option(OPTNEEDRESCORE); } /* vim:set ft=c: */