1 /**
2 * @file
3 * Subject Regex handling
4 *
5 * @authors
6 * Copyright (C) 2021 Richard Russon <rich@flatcap.org>
7 *
8 * @copyright
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 2 of the License, or (at your option) any later
12 * version.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /**
24 * @page neo_subjrx Subject Regex handling
25 *
26 * Subject Regex handling
27 */
28
29 #include "config.h"
30 #include <stddef.h>
31 #include <stdint.h>
32 #include "mutt/lib.h"
33 #include "email/lib.h"
34 #include "core/lib.h"
35 #include "mutt.h"
36 #include "subjectrx.h"
37 #include "init.h"
38
39 static struct ReplaceList SubjectRegexList = STAILQ_HEAD_INITIALIZER(SubjectRegexList);
40 static struct Notify *SubjRxNotify = NULL;
41
42 /**
43 * subjrx_free - Free the Subject Regex List
44 */
subjrx_free(void)45 void subjrx_free(void)
46 {
47 notify_free(&SubjRxNotify);
48 mutt_replacelist_free(&SubjectRegexList);
49 }
50
51 /**
52 * subjrx_init - Create new Subject Regex List
53 */
subjrx_init(void)54 void subjrx_init(void)
55 {
56 if (SubjRxNotify)
57 return;
58
59 SubjRxNotify = notify_new();
60 notify_set_parent(SubjRxNotify, NeoMutt->notify);
61 }
62
63 /**
64 * parse_unreplace_list - Remove a string replacement rule - Implements Command::parse() - @ingroup command_parse
65 */
parse_unreplace_list(struct Buffer * buf,struct Buffer * s,struct ReplaceList * list,struct Buffer * err)66 static enum CommandResult parse_unreplace_list(struct Buffer *buf, struct Buffer *s,
67 struct ReplaceList *list, struct Buffer *err)
68 {
69 /* First token is a regex. */
70 if (!MoreArgs(s))
71 {
72 mutt_buffer_printf(err, _("%s: too few arguments"), "unsubjectrx");
73 return MUTT_CMD_WARNING;
74 }
75
76 mutt_extract_token(buf, s, MUTT_TOKEN_NO_FLAGS);
77
78 /* "*" is a special case. */
79 if (mutt_str_equal(buf->data, "*"))
80 {
81 mutt_replacelist_free(list);
82 return MUTT_CMD_SUCCESS;
83 }
84
85 mutt_replacelist_remove(list, buf->data);
86 return MUTT_CMD_SUCCESS;
87 }
88
89 /**
90 * parse_replace_list - Parse a string replacement rule - Implements Command::parse() - @ingroup command_parse
91 */
parse_replace_list(struct Buffer * buf,struct Buffer * s,struct ReplaceList * list,struct Buffer * err)92 static enum CommandResult parse_replace_list(struct Buffer *buf, struct Buffer *s,
93 struct ReplaceList *list, struct Buffer *err)
94 {
95 struct Buffer templ = mutt_buffer_make(0);
96
97 /* First token is a regex. */
98 if (!MoreArgs(s))
99 {
100 mutt_buffer_printf(err, _("%s: too few arguments"), "subjectrx");
101 return MUTT_CMD_WARNING;
102 }
103 mutt_extract_token(buf, s, MUTT_TOKEN_NO_FLAGS);
104
105 /* Second token is a replacement template */
106 if (!MoreArgs(s))
107 {
108 mutt_buffer_printf(err, _("%s: too few arguments"), "subjectrx");
109 return MUTT_CMD_WARNING;
110 }
111 mutt_extract_token(&templ, s, MUTT_TOKEN_NO_FLAGS);
112
113 if (mutt_replacelist_add(list, buf->data, templ.data, err) != 0)
114 {
115 FREE(&templ.data);
116 return MUTT_CMD_ERROR;
117 }
118 FREE(&templ.data);
119
120 return MUTT_CMD_SUCCESS;
121 }
122
123 /**
124 * subjrx_apply_mods - Apply regex modifications to the subject
125 * @param env Envelope of Email
126 * @retval true Subject modified
127 */
subjrx_apply_mods(struct Envelope * env)128 bool subjrx_apply_mods(struct Envelope *env)
129 {
130 if (!env || !env->subject || (*env->subject == '\0'))
131 return false;
132
133 if (env->disp_subj)
134 return true;
135
136 if (STAILQ_EMPTY(&SubjectRegexList))
137 return false;
138
139 env->disp_subj = mutt_replacelist_apply(&SubjectRegexList, NULL, 0, env->subject);
140 return true;
141 }
142
143 /**
144 * subjrx_clear_mods - Clear out all modified email subjects
145 */
subjrx_clear_mods(struct Mailbox * m)146 void subjrx_clear_mods(struct Mailbox *m)
147 {
148 if (!m)
149 return;
150
151 for (int i = 0; i < m->msg_count; i++)
152 {
153 struct Email *e = m->emails[i];
154 if (!e || !e->env)
155 continue;
156 FREE(&e->env->disp_subj);
157 }
158 }
159
160 /**
161 * parse_subjectrx_list - Parse the 'subjectrx' command - Implements Command::parse() - @ingroup command_parse
162 */
parse_subjectrx_list(struct Buffer * buf,struct Buffer * s,intptr_t data,struct Buffer * err)163 enum CommandResult parse_subjectrx_list(struct Buffer *buf, struct Buffer *s,
164 intptr_t data, struct Buffer *err)
165 {
166 enum CommandResult rc;
167
168 rc = parse_replace_list(buf, s, &SubjectRegexList, err);
169 if (rc == MUTT_CMD_SUCCESS)
170 {
171 mutt_debug(LL_NOTIFY, "NT_SUBJRX_ADD: %s\n", buf->data);
172 notify_send(SubjRxNotify, NT_SUBJRX, NT_SUBJRX_ADD, NULL);
173 }
174 return rc;
175 }
176
177 /**
178 * parse_unsubjectrx_list - Parse the 'unsubjectrx' command - Implements Command::parse() - @ingroup command_parse
179 */
parse_unsubjectrx_list(struct Buffer * buf,struct Buffer * s,intptr_t data,struct Buffer * err)180 enum CommandResult parse_unsubjectrx_list(struct Buffer *buf, struct Buffer *s,
181 intptr_t data, struct Buffer *err)
182 {
183 enum CommandResult rc;
184
185 rc = parse_unreplace_list(buf, s, &SubjectRegexList, err);
186 if (rc == MUTT_CMD_SUCCESS)
187 {
188 mutt_debug(LL_NOTIFY, "NT_SUBJRX_DELETE: %s\n", buf->data);
189 notify_send(SubjRxNotify, NT_SUBJRX, NT_SUBJRX_DELETE, NULL);
190 }
191 return rc;
192 }
193