Nico Golde:
[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 {
30   char *str;
31   pattern_t *pat;
32   int val;
33   int exact;            /* if this rule matches, don't evaluate any more */
34   struct score_t *next;
35 } SCORE;
36
37 SCORE *Score = NULL;
38
39 void mutt_check_rescore (CONTEXT *ctx)
40 {
41   int i;
42
43   if (option (OPTNEEDRESCORE) && option (OPTSCORE))
44   {
45     if ((Sort & SORT_MASK) == SORT_SCORE ||
46         (SortAux & SORT_MASK) == SORT_SCORE)
47     {
48       set_option (OPTNEEDRESORT);
49       if ((Sort & SORT_MASK) == SORT_THREADS)
50         set_option (OPTSORTSUBTHREADS);
51     }
52
53     /* must redraw the index since the user might have %N in it */
54     set_option (OPTFORCEREDRAWINDEX);
55     set_option (OPTFORCEREDRAWPAGER);
56
57     for (i = 0; ctx && i < ctx->msgcount; i++)
58     {
59       mutt_score_message (ctx, ctx->hdrs[i], 1);
60       ctx->hdrs[i]->pair = 0;
61     }
62   }
63   unset_option (OPTNEEDRESCORE);
64 }
65
66 int mutt_parse_score (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
67 {
68   SCORE *ptr, *last;
69   char *pattern, *pc;
70   struct pattern_t *pat;
71
72   mutt_extract_token (buf, s, 0);
73   if (!MoreArgs (s))
74   {
75     strfcpy (err->data, _("score: too few arguments"), err->dsize);
76     return (-1);
77   }
78   pattern = buf->data;
79   memset (buf, 0, sizeof (BUFFER));
80   mutt_extract_token (buf, s, 0);
81   if (MoreArgs (s))
82   {
83     FREE (&pattern);
84     strfcpy (err->data, _("score: too many arguments"), err->dsize);
85     return (-1);
86   }
87
88   /* look for an existing entry and update the value, else add it to the end
89      of the list */
90   for (ptr = Score, last = NULL; ptr; last = ptr, ptr = ptr->next)
91     if (mutt_strcmp (pattern, ptr->str) == 0)
92       break;
93   if (!ptr)
94   {
95     if ((pat = mutt_pattern_comp (pattern, 0, err)) == NULL)
96     {
97       FREE (&pattern);
98       return (-1);
99     }
100     ptr = safe_calloc (1, sizeof (SCORE));
101     if (last)
102       last->next = ptr;
103     else
104       Score = ptr;
105     ptr->pat = pat;
106     ptr->str = pattern;
107   }
108   pc = buf->data;
109   if (*pc == '=')
110   {
111     ptr->exact = 1;
112     pc++;
113   }
114   ptr->val = atoi (pc);
115   set_option (OPTNEEDRESCORE);
116   return 0;
117 }
118
119 void mutt_score_message (CONTEXT *ctx, HEADER *hdr, int upd_ctx)
120 {
121   SCORE *tmp;
122
123   hdr->score = 0; /* in case of re-scoring */
124   for (tmp = Score; tmp; tmp = tmp->next)
125   {
126     if (mutt_pattern_exec (tmp->pat, 0, NULL, hdr) > 0)
127     {
128       if (tmp->exact || tmp->val == 9999 || tmp->val == -9999)
129       {
130         hdr->score = tmp->val;
131         break;
132       }
133       hdr->score += tmp->val;
134     }
135   }
136   if (hdr->score < 0)
137     hdr->score = 0;
138   
139   if (hdr->score <= ScoreThresholdDelete)
140     _mutt_set_flag (ctx, hdr, M_DELETE, 1, upd_ctx);
141   if (hdr->score <= ScoreThresholdRead)
142     _mutt_set_flag (ctx, hdr, M_READ, 1, upd_ctx);
143   if (hdr->score >= ScoreThresholdFlag)
144     _mutt_set_flag (ctx, hdr, M_FLAG, 1, upd_ctx);
145 }
146
147 int mutt_parse_unscore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
148 {
149   SCORE *tmp, *last = NULL;
150
151   while (MoreArgs (s))
152   {
153     mutt_extract_token (buf, s, 0);
154     if (!mutt_strcmp ("*", buf->data))
155     {
156       for (tmp = Score; tmp; )
157       {
158         last = tmp;
159         tmp = tmp->next;
160         mutt_pattern_free (&last->pat);
161         FREE (&last);
162       }
163       Score = NULL;
164     }
165     else
166     {
167       for (tmp = Score; tmp; last = tmp, tmp = tmp->next)
168       {
169         if (!mutt_strcmp (buf->data, tmp->str))
170         {
171           if (last)
172             last->next = tmp->next;
173           else
174             Score = tmp->next;
175           mutt_pattern_free (&tmp->pat);
176           FREE (&tmp);
177           /* there should only be one score per pattern, so we can stop here */
178           break;
179         }
180       }
181     }
182   }
183   set_option (OPTNEEDRESCORE);
184   return 0;
185 }