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