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