1 /**
2 * @file
3 * Alternate address 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_alternates Alternate address handling
25 *
26 * Alternate address handling
27 */
28
29 #include "config.h"
30 #include <stdbool.h>
31 #include <stdint.h>
32 #include <stdio.h>
33 #include "mutt/lib.h"
34 #include "address/lib.h"
35 #include "email/lib.h"
36 #include "core/lib.h"
37 #include "mutt.h"
38 #include "alternates.h"
39 #include "command_parse.h"
40 #include "init.h"
41
42 struct RegexList Alternates = STAILQ_HEAD_INITIALIZER(Alternates); ///< List of regexes to match the user's alternate email addresses
43 struct RegexList UnAlternates = STAILQ_HEAD_INITIALIZER(UnAlternates); ///< List of regexes to blacklist false matches in Alternates
44 static struct Notify *AlternatesNotify = NULL;
45
46 /**
47 * alternates_free - Free the alternates lists
48 */
alternates_free(void)49 void alternates_free(void)
50 {
51 notify_free(&AlternatesNotify);
52
53 mutt_regexlist_free(&Alternates);
54 mutt_regexlist_free(&UnAlternates);
55 }
56
57 /**
58 * alternates_init - Set up the alternates lists
59 */
alternates_init(void)60 void alternates_init(void)
61 {
62 if (AlternatesNotify)
63 return;
64
65 AlternatesNotify = notify_new();
66 notify_set_parent(AlternatesNotify, NeoMutt->notify);
67 }
68
69 /**
70 * mutt_alternates_reset - Clear the recipient valid flag of all emails
71 */
mutt_alternates_reset(struct Mailbox * m)72 void mutt_alternates_reset(struct Mailbox *m)
73 {
74 if (!m)
75 return;
76
77 for (int i = 0; i < m->msg_count; i++)
78 {
79 struct Email *e = m->emails[i];
80 if (!e)
81 break;
82 e->recip_valid = false;
83 }
84 }
85
86 /**
87 * parse_alternates - Parse the 'alternates' command - Implements Command::parse() - @ingroup command_parse
88 */
parse_alternates(struct Buffer * buf,struct Buffer * s,intptr_t data,struct Buffer * err)89 enum CommandResult parse_alternates(struct Buffer *buf, struct Buffer *s,
90 intptr_t data, struct Buffer *err)
91 {
92 struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
93
94 do
95 {
96 mutt_extract_token(buf, s, MUTT_TOKEN_NO_FLAGS);
97
98 if (parse_grouplist(&gl, buf, s, err) == -1)
99 goto bail;
100
101 mutt_regexlist_remove(&UnAlternates, buf->data);
102
103 if (mutt_regexlist_add(&Alternates, buf->data, REG_ICASE, err) != 0)
104 goto bail;
105
106 if (mutt_grouplist_add_regex(&gl, buf->data, REG_ICASE, err) != 0)
107 goto bail;
108 } while (MoreArgs(s));
109
110 mutt_grouplist_destroy(&gl);
111
112 mutt_debug(LL_NOTIFY, "NT_ALTERN_ADD: %s\n", buf->data);
113 notify_send(AlternatesNotify, NT_ALTERN, NT_ALTERN_ADD, NULL);
114
115 return MUTT_CMD_SUCCESS;
116
117 bail:
118 mutt_grouplist_destroy(&gl);
119 return MUTT_CMD_ERROR;
120 }
121
122 /**
123 * parse_unalternates - Parse the 'unalternates' command - Implements Command::parse() - @ingroup command_parse
124 */
parse_unalternates(struct Buffer * buf,struct Buffer * s,intptr_t data,struct Buffer * err)125 enum CommandResult parse_unalternates(struct Buffer *buf, struct Buffer *s,
126 intptr_t data, struct Buffer *err)
127 {
128 do
129 {
130 mutt_extract_token(buf, s, MUTT_TOKEN_NO_FLAGS);
131 mutt_regexlist_remove(&Alternates, buf->data);
132
133 if (!mutt_str_equal(buf->data, "*") &&
134 (mutt_regexlist_add(&UnAlternates, buf->data, REG_ICASE, err) != 0))
135 {
136 return MUTT_CMD_ERROR;
137 }
138
139 } while (MoreArgs(s));
140
141 mutt_debug(LL_NOTIFY, "NT_ALTERN_DELETE: %s\n", buf->data);
142 notify_send(AlternatesNotify, NT_ALTERN, NT_ALTERN_DELETE, NULL);
143
144 return MUTT_CMD_SUCCESS;
145 }
146
147 /**
148 * mutt_alternates_match - Compare an Address to the Un/Alternates lists
149 * @param addr Address to check
150 * @retval true Address matches
151 */
mutt_alternates_match(const char * addr)152 bool mutt_alternates_match(const char *addr)
153 {
154 if (!addr)
155 return false;
156
157 if (mutt_regexlist_match(&Alternates, addr))
158 {
159 mutt_debug(LL_DEBUG5, "yes, %s matched by alternates\n", addr);
160 if (mutt_regexlist_match(&UnAlternates, addr))
161 mutt_debug(LL_DEBUG5, "but, %s matched by unalternates\n", addr);
162 else
163 return true;
164 }
165
166 return false;
167 }
168