Andreas Krennmair:
[apps/madmutt.git] / score.c
1 /*
2  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
3  * 
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  * 
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  * 
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
17  */
18
19 #if HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include "mutt.h"
24 #include "sort.h"
25 #include <string.h>
26 #include <stdlib.h>
27
28 typedef struct score_t {
29   char *str;
30   pattern_t *pat;
31   int val;
32   int exact;                    /* if this rule matches, don't evaluate any more */
33   struct score_t *next;
34 } SCORE;
35
36 SCORE *Score = NULL;
37
38 void mutt_check_rescore (CONTEXT * ctx)
39 {
40   int i;
41
42   if (option (OPTNEEDRESCORE) && option (OPTSCORE)) {
43     if ((Sort & SORT_MASK) == SORT_SCORE ||
44         (SortAux & SORT_MASK) == SORT_SCORE) {
45       set_option (OPTNEEDRESORT);
46       if ((Sort & SORT_MASK) == SORT_THREADS)
47         set_option (OPTSORTSUBTHREADS);
48     }
49
50     /* must redraw the index since the user might have %N in it */
51     set_option (OPTFORCEREDRAWINDEX);
52     set_option (OPTFORCEREDRAWPAGER);
53
54     for (i = 0; ctx && i < ctx->msgcount; i++) {
55       mutt_score_message (ctx, ctx->hdrs[i], 1);
56       ctx->hdrs[i]->pair = 0;
57     }
58   }
59   unset_option (OPTNEEDRESCORE);
60 }
61
62 int mutt_parse_score (BUFFER * buf, BUFFER * s, unsigned long data,
63                       BUFFER * err)
64 {
65   SCORE *ptr, *last;
66   char *pattern, *pc;
67   struct pattern_t *pat;
68
69   mutt_extract_token (buf, s, 0);
70   if (!MoreArgs (s)) {
71     strfcpy (err->data, _("score: too few arguments"), err->dsize);
72     return (-1);
73   }
74   pattern = buf->data;
75   memset (buf, 0, sizeof (BUFFER));
76   mutt_extract_token (buf, s, 0);
77   if (MoreArgs (s)) {
78     FREE (&pattern);
79     strfcpy (err->data, _("score: too many arguments"), err->dsize);
80     return (-1);
81   }
82
83   /* look for an existing entry and update the value, else add it to the end
84      of the list */
85   for (ptr = Score, last = NULL; ptr; last = ptr, ptr = ptr->next)
86     if (mutt_strcmp (pattern, ptr->str) == 0)
87       break;
88   if (!ptr) {
89     if ((pat = mutt_pattern_comp (pattern, 0, err)) == NULL) {
90       FREE (&pattern);
91       return (-1);
92     }
93     ptr = safe_calloc (1, sizeof (SCORE));
94     if (last)
95       last->next = ptr;
96     else
97       Score = ptr;
98     ptr->pat = pat;
99     ptr->str = pattern;
100   }
101   pc = buf->data;
102   if (*pc == '=') {
103     ptr->exact = 1;
104     pc++;
105   }
106   ptr->val = atoi (pc);
107   set_option (OPTNEEDRESCORE);
108   return 0;
109 }
110
111 void mutt_score_message (CONTEXT * ctx, HEADER * hdr, int upd_ctx)
112 {
113   SCORE *tmp;
114
115   hdr->score = 0;               /* in case of re-scoring */
116   for (tmp = Score; tmp; tmp = tmp->next) {
117     if (mutt_pattern_exec (tmp->pat, 0, NULL, hdr) > 0) {
118       if (tmp->exact || tmp->val == 9999 || tmp->val == -9999) {
119         hdr->score = tmp->val;
120         break;
121       }
122       hdr->score += tmp->val;
123     }
124   }
125   if (hdr->score < 0)
126     hdr->score = 0;
127
128   if (hdr->score <= ScoreThresholdDelete)
129     _mutt_set_flag (ctx, hdr, M_DELETE, 1, upd_ctx);
130   if (hdr->score <= ScoreThresholdRead)
131     _mutt_set_flag (ctx, hdr, M_READ, 1, upd_ctx);
132   if (hdr->score >= ScoreThresholdFlag)
133     _mutt_set_flag (ctx, hdr, M_FLAG, 1, upd_ctx);
134 }
135
136 int mutt_parse_unscore (BUFFER * buf, BUFFER * s, unsigned long data,
137                         BUFFER * err)
138 {
139   SCORE *tmp, *last = NULL;
140
141   while (MoreArgs (s)) {
142     mutt_extract_token (buf, s, 0);
143     if (!mutt_strcmp ("*", buf->data)) {
144       for (tmp = Score; tmp;) {
145         last = tmp;
146         tmp = tmp->next;
147         mutt_pattern_free (&last->pat);
148         FREE (&last);
149       }
150       Score = NULL;
151     }
152     else {
153       for (tmp = Score; tmp; last = tmp, tmp = tmp->next) {
154         if (!mutt_strcmp (buf->data, tmp->str)) {
155           if (last)
156             last->next = tmp->next;
157           else
158             Score = tmp->next;
159           mutt_pattern_free (&tmp->pat);
160           FREE (&tmp);
161           /* there should only be one score per pattern, so we can stop here */
162           break;
163         }
164       }
165     }
166   }
167   set_option (OPTNEEDRESCORE);
168   return 0;
169 }