/* * 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" @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. */ }; 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; void mutt_check_rescore (CONTEXT * ctx) { int i; if (option (OPTNEEDRESCORE) && mod_score.enable) { if ((Sort & SORT_MASK) == SORT_SCORE || (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 (i = 0; ctx && i < ctx->msgcount; i++) { mutt_score_message (ctx, ctx->hdrs[i], 1); ctx->hdrs[i]->pair = 0; } } unset_option (OPTNEEDRESCORE); } int mutt_parse_score (BUFFER * buf, BUFFER * s, unsigned long data __attribute__ ((unused)), BUFFER * err) { char *pattern, *pc; struct pattern_t *pat; score_t **last; mutt_extract_token (buf, s, 0); if (!MoreArgs (s)) { m_strcpy(err->data, err->dsize, _("score: too few arguments")); return (-1); } pattern = buf->data; p_clear(buf, 1); mutt_extract_token (buf, s, 0); if (MoreArgs (s)) { p_delete(&pattern); m_strcpy(err->data, err->dsize, _("score: too many arguments")); return (-1); } /* look for an existing entry and update the value, else add it to the end of the list */ for (last = &Score; *last; last = &(*last)->next) { if (m_strcmp(pattern, (*last)->str) == 0) break; } if (!*last) { if (!(pat = mutt_pattern_comp(pattern, 0, err))) { p_delete(&pattern); return (-1); } *last = score_new(); (*last)->pat = pat; (*last)->str = pattern; } pc = buf->data; pc += (*last)->exact = (*pc == '='); (*last)->val = atoi(pc); set_option(OPTNEEDRESCORE); return 0; } void mutt_score_message (CONTEXT * ctx, HEADER * hdr, int upd_ctx) { score_t *tmp; hdr->score = 0; /* in case of re-scoring */ for (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_flag) _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); } int mutt_parse_unscore(BUFFER * buf, BUFFER * s, unsigned long data __attribute__ ((unused)), BUFFER * err __attribute__ ((unused))) { while (MoreArgs(s)) { mutt_extract_token(buf, s, 0); if (!m_strcmp("*", buf->data)) { score_list_wipe(&Score); } else { score_t **last; for (last = &Score; *last; last = &(*last)->next) { if (!m_strcmp(buf->data, (*last)->str)) { score_t *tmp = score_list_pop(last); score_delete(&tmp); break; } } } } set_option (OPTNEEDRESCORE); return 0; } /* vim:set ft=c: */