061d84c4bb48677eea0f8ffb539b37f1fcbcb7f0
[apps/madmutt.git] / score.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #include <lib-lib/lib-lib.h>
15
16 #include "mutt.h"
17 #include "sort.h"
18
19 #include <string.h>
20 #include <stdlib.h>
21
22 typedef struct score_t {
23   char *str;
24   pattern_t *pat;
25   int val;
26   int exact;                    /* if this rule matches, don't evaluate any more */
27   struct score_t *next;
28 } SCORE;
29
30 SCORE *Score = NULL;
31
32 void mutt_check_rescore (CONTEXT * ctx)
33 {
34   int i;
35
36   if (option (OPTNEEDRESCORE) && option (OPTSCORE)) {
37     if ((Sort & SORT_MASK) == SORT_SCORE ||
38         (SortAux & SORT_MASK) == SORT_SCORE) {
39       set_option (OPTNEEDRESORT);
40       if ((Sort & SORT_MASK) == SORT_THREADS)
41         set_option (OPTSORTSUBTHREADS);
42     }
43
44     /* must redraw the index since the user might have %N in it */
45     set_option (OPTFORCEREDRAWINDEX);
46     set_option (OPTFORCEREDRAWPAGER);
47
48     for (i = 0; ctx && i < ctx->msgcount; i++) {
49       mutt_score_message (ctx, ctx->hdrs[i], 1);
50       ctx->hdrs[i]->pair = 0;
51     }
52   }
53   unset_option (OPTNEEDRESCORE);
54 }
55
56 int mutt_parse_score (BUFFER * buf, BUFFER * s, unsigned long data,
57                       BUFFER * err)
58 {
59   SCORE *ptr, *last;
60   char *pattern, *pc;
61   struct pattern_t *pat;
62
63   mutt_extract_token (buf, s, 0);
64   if (!MoreArgs (s)) {
65     m_strcpy(err->data, err->dsize, _("score: too few arguments"));
66     return (-1);
67   }
68   pattern = buf->data;
69   p_clear(buf, 1);
70   mutt_extract_token (buf, s, 0);
71   if (MoreArgs (s)) {
72     p_delete(&pattern);
73     m_strcpy(err->data, err->dsize, _("score: too many arguments"));
74     return (-1);
75   }
76
77   /* look for an existing entry and update the value, else add it to the end
78      of the list */
79   for (ptr = Score, last = NULL; ptr; last = ptr, ptr = ptr->next)
80     if (m_strcmp(pattern, ptr->str) == 0)
81       break;
82   if (!ptr) {
83     if ((pat = mutt_pattern_comp (pattern, 0, err)) == NULL) {
84       p_delete(&pattern);
85       return (-1);
86     }
87     ptr = p_new(SCORE, 1);
88     if (last)
89       last->next = ptr;
90     else
91       Score = ptr;
92     ptr->pat = pat;
93     ptr->str = pattern;
94   }
95   pc = buf->data;
96   if (*pc == '=') {
97     ptr->exact = 1;
98     pc++;
99   }
100   ptr->val = atoi (pc);
101   set_option (OPTNEEDRESCORE);
102   return 0;
103 }
104
105 void mutt_score_message (CONTEXT * ctx, HEADER * hdr, int upd_ctx)
106 {
107   SCORE *tmp;
108
109   hdr->score = 0;               /* in case of re-scoring */
110   for (tmp = Score; tmp; tmp = tmp->next) {
111     if (mutt_pattern_exec (tmp->pat, M_MATCH_FULL_ADDRESS, NULL, hdr) > 0) {
112       if (tmp->exact || tmp->val == 9999 || tmp->val == -9999) {
113         hdr->score = tmp->val;
114         break;
115       }
116       hdr->score += tmp->val;
117     }
118   }
119   if (hdr->score < 0)
120     hdr->score = 0;
121
122   if (hdr->score <= ScoreThresholdDelete)
123     _mutt_set_flag (ctx, hdr, M_DELETE, 1, upd_ctx);
124   if (hdr->score <= ScoreThresholdRead)
125     _mutt_set_flag (ctx, hdr, M_READ, 1, upd_ctx);
126   if (hdr->score >= ScoreThresholdFlag)
127     _mutt_set_flag (ctx, hdr, M_FLAG, 1, upd_ctx);
128 }
129
130 int mutt_parse_unscore (BUFFER * buf, BUFFER * s, unsigned long data,
131                         BUFFER * err)
132 {
133   SCORE *tmp, *last = NULL;
134
135   while (MoreArgs (s)) {
136     mutt_extract_token (buf, s, 0);
137     if (!m_strcmp("*", buf->data)) {
138       for (tmp = Score; tmp;) {
139         last = tmp;
140         tmp = tmp->next;
141         mutt_pattern_free (&last->pat);
142         p_delete(&last);
143       }
144       Score = NULL;
145     }
146     else {
147       for (tmp = Score; tmp; last = tmp, tmp = tmp->next) {
148         if (!m_strcmp(buf->data, tmp->str)) {
149           if (last)
150             last->next = tmp->next;
151           else
152             Score = tmp->next;
153           mutt_pattern_free (&tmp->pat);
154           p_delete(&tmp);
155           /* there should only be one score per pattern, so we can stop here */
156           break;
157         }
158       }
159     }
160   }
161   set_option (OPTNEEDRESCORE);
162   return 0;
163 }