NeoMutt  2025-12-11-1009-ga75d9e
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
score.c
Go to the documentation of this file.
1
25
31
32#include "config.h"
33#include <stdbool.h>
34#include <stdlib.h>
35#include "mutt/lib.h"
36#include "config/lib.h"
37#include "core/lib.h"
38#include "gui/lib.h"
39#include "mutt.h"
40#include "score.h"
41#include "index/lib.h"
42#include "parse/lib.h"
43#include "pattern/lib.h"
44#include "email.h"
45#include "globals.h"
46#include "module_data.h"
47#include "sort.h"
48
53void score_list_free(struct Score **sp)
54{
55 if (!sp)
56 return;
57
58 struct Score *sc = *sp;
59 while (sc)
60 {
61 struct Score *next = sc->next;
63 FREE(&sc->str);
64 FREE(&sc);
65 sc = next;
66 }
67 *sp = NULL;
68}
69
76enum CommandResult parse_score(const struct Command *cmd, struct Buffer *line,
77 const struct ParseContext *pc, struct ParseError *pe)
78{
79 struct Buffer *err = pe->message;
81
82 if (!MoreArgs(line))
83 {
84 buf_printf(err, _("%s: too few arguments"), cmd->name);
85 return MUTT_CMD_WARNING;
86 }
87
88 struct Score *ptr = NULL;
89 struct Score *last = NULL;
90 char *pattern = NULL;
91 char *patchar = NULL;
92 struct Buffer *token = buf_pool_get();
94
95 parse_extract_token(token, line, TOKEN_NONE);
96 if (!MoreArgs(line))
97 {
98 buf_printf(err, _("%s: too few arguments"), cmd->name);
99 goto done;
100 }
101 pattern = buf_strdup(token);
102 parse_extract_token(token, line, TOKEN_NONE);
103 if (MoreArgs(line))
104 {
105 buf_printf(err, _("%s: too many arguments"), cmd->name);
106 goto done;
107 }
108
109 /* look for an existing entry and update the value, else add it to the end
110 * of the list */
111 for (ptr = mod_data->score_list, last = NULL; ptr; last = ptr, ptr = ptr->next)
112 if (mutt_str_equal(pattern, ptr->str))
113 break;
114
115 if (ptr)
116 {
117 /* 'token' arg was cleared and 'pattern' holds the only reference;
118 * as here 'ptr' != NULL -> update the value only in which case
119 * ptr->str already has the string, so pattern should be freed. */
120 FREE(&pattern);
121 }
122 else
123 {
124 struct MailboxView *mv_cur = get_current_mailbox_view();
125 struct PatternList *pat = mutt_pattern_comp(mv_cur, pattern, MUTT_PC_NONE, err);
126 if (!pat)
127 {
128 goto done;
129 }
130 ptr = MUTT_MEM_CALLOC(1, struct Score);
131 if (last)
132 last->next = ptr;
133 else
134 mod_data->score_list = ptr;
135 ptr->pat = pat;
136 ptr->str = pattern;
137 pattern = NULL;
138 }
139
140 patchar = token->data;
141 if (*patchar == '=')
142 {
143 ptr->exact = true;
144 patchar++;
145 }
146
147 if (!mutt_str_atoi_full(patchar, &ptr->val))
148 {
149 buf_strcpy(err, _("Error: score: invalid number"));
150 goto done;
151 }
152 OptNeedRescore = true;
153
154 rc = MUTT_CMD_SUCCESS;
155
156done:
157 buf_pool_release(&token);
158 FREE(&pattern);
159 return rc;
160}
161
168enum CommandResult parse_unscore(const struct Command *cmd, struct Buffer *line,
169 const struct ParseContext *pc, struct ParseError *pe)
170{
171 struct Buffer *err = pe->message;
173
174 if (!MoreArgs(line))
175 {
176 buf_printf(err, _("%s: too few arguments"), cmd->name);
177 return MUTT_CMD_WARNING;
178 }
179
180 struct Score *tmp = NULL;
181 struct Score *last = NULL;
182 struct Buffer *token = buf_pool_get();
183
184 while (MoreArgs(line))
185 {
186 parse_extract_token(token, line, TOKEN_NONE);
187 if (mutt_str_equal("*", buf_string(token)))
188 {
189 score_list_free(&mod_data->score_list);
190 }
191 else
192 {
193 for (tmp = mod_data->score_list; tmp; last = tmp, tmp = tmp->next)
194 {
195 if (mutt_str_equal(buf_string(token), tmp->str))
196 {
197 if (last)
198 last->next = tmp->next;
199 else
200 mod_data->score_list = tmp->next;
201 mutt_pattern_free(&tmp->pat);
202 FREE(&tmp);
203 /* there should only be one score per pattern, so we can stop here */
204 break;
205 }
206 }
207 }
208 }
209
210 OptNeedRescore = true;
211 buf_pool_release(&token);
212 return MUTT_CMD_SUCCESS;
213}
214
220{
221 const bool c_score = cs_subset_bool(NeoMutt->sub, "score");
222 if (OptNeedRescore && c_score)
223 {
224 const enum EmailSortType c_sort = cs_subset_sort(NeoMutt->sub, "sort");
225 const enum EmailSortType c_sort_aux = cs_subset_sort(NeoMutt->sub, "sort_aux");
226 if (((c_sort & SORT_MASK) == EMAIL_SORT_SCORE) ||
227 ((c_sort_aux & SORT_MASK) == EMAIL_SORT_SCORE))
228 {
229 OptNeedResort = true;
230 if (mutt_using_threads())
231 OptSortSubthreads = true;
232 }
233
234 mutt_debug(LL_NOTIFY, "NT_SCORE: %p\n", (void *) m);
235 notify_send(m->notify, NT_SCORE, 0, NULL);
236 }
237 OptNeedRescore = false;
238}
239
246void mutt_score_message(struct Mailbox *m, struct Email *e, bool upd_mbox)
247{
249 struct Score *tmp = NULL;
250 struct PatternCache cache = { 0 };
251
252 e->score = 0; /* in case of re-scoring */
253 for (tmp = mod_data->score_list; tmp; tmp = tmp->next)
254 {
255 if (mutt_pattern_exec(SLIST_FIRST(tmp->pat), MUTT_MATCH_FULL_ADDRESS, NULL, e, &cache) > 0)
256 {
257 if (tmp->exact || (tmp->val == 9999) || (tmp->val == -9999))
258 {
259 e->score = tmp->val;
260 break;
261 }
262 e->score += tmp->val;
263 }
264 }
265 if (e->score < 0)
266 e->score = 0;
267
268 const short c_score_threshold_delete = cs_subset_number(NeoMutt->sub, "score_threshold_delete");
269 const short c_score_threshold_flag = cs_subset_number(NeoMutt->sub, "score_threshold_flag");
270 const short c_score_threshold_read = cs_subset_number(NeoMutt->sub, "score_threshold_read");
271
272 if (e->score <= c_score_threshold_delete)
273 mutt_set_flag(m, e, MUTT_DELETE, true, upd_mbox);
274 if (e->score <= c_score_threshold_read)
275 mutt_set_flag(m, e, MUTT_READ, true, upd_mbox);
276 if (e->score >= c_score_threshold_flag)
277 mutt_set_flag(m, e, MUTT_FLAG, true, upd_mbox);
278}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:401
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
CommandResult
Error codes for command_t parse functions.
Definition command.h:37
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition command.h:40
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition command.h:38
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition command.h:39
struct PatternList * mutt_pattern_comp(struct MailboxView *mv, const char *s, PatternCompFlags flags, struct Buffer *err)
Create a Pattern.
Definition compile.c:964
void mutt_pattern_free(struct PatternList **pat)
Free a Pattern.
Definition compile.c:836
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
short cs_subset_sort(const struct ConfigSubset *sub, const char *name)
Get a sort config item by name.
Definition helpers.c:266
Convenience wrapper for the config headers.
#define SORT_MASK
Mask for the sort id.
Definition sort.h:39
Convenience wrapper for the core headers.
Email private Module data.
bool OptNeedRescore
(pseudo) set when the 'score' command is used
Definition globals.c:51
bool OptNeedResort
(pseudo) used to force a re-sort
Definition globals.c:52
Assorted sorting methods.
EmailSortType
Methods for sorting Emails.
Definition sort.h:53
@ EMAIL_SORT_SCORE
Sort by the email's score.
Definition sort.h:58
Representation of an email.
int parse_extract_token(struct Buffer *dest, struct Buffer *line, TokenFlags flags)
Extract one token from a string.
Definition extract.c:49
#define MoreArgs(buf)
Definition extract.h:32
@ TOKEN_NONE
No flags are set.
Definition extract.h:50
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition flags.c:54
bool OptSortSubthreads
(pseudo) used when $sort_aux changes
Definition globals.c:57
Global variables.
enum CommandResult parse_unscore(const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
Parse the 'unscore' command - Implements Command::parse() -.
Definition score.c:168
enum CommandResult parse_score(const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
Parse the 'score' command - Implements Command::parse() -.
Definition score.c:76
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
Convenience wrapper for the gui headers.
#define mutt_using_threads()
Definition thread.h:119
GUI manage the main index (list of emails).
struct MailboxView * get_current_mailbox_view(void)
Get the current Mailbox view.
Definition index.c:692
@ LL_NOTIFY
Log of notifications.
Definition logging2.h:50
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
@ MODULE_ID_EMAIL
ModuleEmail, Email code
Definition module_api.h:64
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition notify.c:173
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
Many unsorted constants and some structs.
@ MUTT_READ
Messages that have been read.
Definition mutt.h:92
@ MUTT_FLAG
Flagged messages.
Definition mutt.h:98
@ MUTT_DELETE
Messages to be deleted.
Definition mutt.h:94
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
@ NT_SCORE
Email scoring has changed.
Definition notify_type.h:55
Text parsing functions.
bool mutt_pattern_exec(struct Pattern *pat, PatternExecFlags flags, struct Mailbox *m, struct Email *e, struct PatternCache *cache)
Match a pattern against an email header.
Definition exec.c:1151
Match patterns to emails.
@ MUTT_MATCH_FULL_ADDRESS
Match the full address.
Definition lib.h:117
@ MUTT_PC_NONE
No flags are set.
Definition lib.h:73
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define SLIST_FIRST(head)
Definition queue.h:227
void mutt_check_rescore(struct Mailbox *m)
Do the emails need to have their scores recalculated?
Definition score.c:219
void mutt_score_message(struct Mailbox *m, struct Email *e, bool upd_mbox)
Apply scoring to an email.
Definition score.c:246
void score_list_free(struct Score **sp)
Free a list of scoring rules.
Definition score.c:53
Routines for adding user scores to emails.
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
const char * name
Name of the Command.
Definition command.h:162
Email private Module data.
Definition module_data.h:32
struct Score * score_list
Linked list of email scoring rules.
Definition module_data.h:44
The envelope/body of an email.
Definition email.h:39
int score
Message score.
Definition email.h:113
View of a Mailbox.
Definition mview.h:40
A mailbox.
Definition mailbox.h:81
Container for Accounts, Notifications.
Definition neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Context for config parsing (history/backtrace).
Definition pcontext.h:34
Detailed error information from config parsing.
Definition perror.h:34
struct Buffer * message
Error message.
Definition perror.h:35
Cache commonly-used patterns.
Definition lib.h:130
Scoring rule for email.
Definition score.h:38
bool exact
If this rule matches, don't evaluate any more.
Definition score.h:42
char * str
String to match.
Definition score.h:39
struct PatternList * pat
Pattern to match.
Definition score.h:40
int val
Score to add.
Definition score.h:41
struct Score * next
Linked list.
Definition score.h:43