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