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