NeoMutt  2025-12-11-694-ga89709
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
commands.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <stdio.h>
32#include "mutt/lib.h"
33#include "address/lib.h"
34#include "config/lib.h"
35#include "email/lib.h"
36#include "core/lib.h"
37#include "lib.h"
38#include "parse/lib.h"
39#include "alias.h"
40#include "alternates.h"
41#include "module_data.h"
42#include "reverse.h"
43
49void alias_tags_to_buffer(struct TagList *tl, struct Buffer *buf)
50{
51 struct Tag *tag = NULL;
52 STAILQ_FOREACH(tag, tl, entries)
53 {
54 buf_addstr(buf, tag->name);
55 if (STAILQ_NEXT(tag, entries))
56 buf_addch(buf, ',');
57 }
58}
59
65void parse_alias_tags(const char *tags, struct TagList *tl)
66{
67 if (!tags || !tl)
68 return;
69
70 struct Slist *sl = slist_parse(tags, D_SLIST_SEP_COMMA);
71 if (slist_is_empty(sl))
72 {
73 slist_free(&sl);
74 return;
75 }
76
77 struct ListNode *np = NULL;
78 STAILQ_FOREACH(np, &sl->head, entries)
79 {
80 struct Tag *tag = tag_new();
81 tag->name = np->data; // Transfer string
82 np->data = NULL;
83 STAILQ_INSERT_TAIL(tl, tag, entries);
84 }
85 slist_free(&sl);
86}
87
95void parse_alias_comments(struct Alias *alias, const char *com)
96{
97 if (!com || (com[0] == '\0'))
98 return;
99
100 const regmatch_t *match = mutt_prex_capture(PREX_ALIAS_TAGS, com);
101 if (match)
102 {
103 const regmatch_t *pre = &match[PREX_ALIAS_TAGS_MATCH_PRE];
104 const regmatch_t *tags = &match[PREX_ALIAS_TAGS_MATCH_TAGS];
105 const regmatch_t *post = &match[PREX_ALIAS_TAGS_MATCH_POST];
106
107 struct Buffer *tmp = buf_pool_get();
108
109 // Extract the tags
110 buf_addstr_n(tmp, com + mutt_regmatch_start(tags),
112 parse_alias_tags(buf_string(tmp), &alias->tags);
113 buf_reset(tmp);
114
115 // Collect all the other text as "comments"
116 buf_addstr_n(tmp, com + mutt_regmatch_start(pre),
118 buf_addstr_n(tmp, com + mutt_regmatch_start(post),
120 alias->comment = buf_strdup(tmp);
121
122 buf_pool_release(&tmp);
123 }
124 else
125 {
126 alias->comment = mutt_str_dup(com);
127 }
128}
129
138enum CommandResult parse_alias(const struct Command *cmd, struct Buffer *line,
139 const struct ParseContext *pc, struct ParseError *pe)
140{
141 struct Buffer *err = pe->message;
142
143 if (!MoreArgs(line))
144 {
145 buf_printf(err, _("%s: too few arguments"), cmd->name);
146 return MUTT_CMD_WARNING;
147 }
148
149 struct Alias *a = NULL;
150 enum NotifyAlias event;
151 struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
152 struct Buffer *token = buf_pool_get();
154
155 /* name */
157 mutt_debug(LL_DEBUG5, "First token is '%s'\n", buf_string(token));
158 if (parse_grouplist(&gl, token, line, err, NeoMutt->groups) == -1)
159 goto done;
160
161 char *name = mutt_str_dup(buf_string(token));
162
163 /* address list */
165 mutt_debug(LL_DEBUG5, "Second token is '%s'\n", buf_string(token));
166 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
167 int parsed = mutt_addrlist_parse2(&al, buf_string(token));
168 if (parsed == 0)
169 {
170 buf_printf(err, _("Warning: Bad address '%s' in alias '%s'"), buf_string(token), name);
171 FREE(&name);
172 goto done;
173 }
174
175 /* IDN */
176 char *estr = NULL;
177 if (mutt_addrlist_to_intl(&al, &estr))
178 {
179 buf_printf(err, _("Warning: Bad IDN '%s' in alias '%s'"), estr, name);
180 FREE(&name);
181 FREE(&estr);
182 goto done;
183 }
184
186 ASSERT(md);
187
188 /* check to see if an alias with this name already exists */
189 struct Alias **ap = NULL;
190 ARRAY_FOREACH(ap, &md->aliases)
191 {
192 if (mutt_istr_equal((*ap)->name, name))
193 {
194 a = *ap;
195 break;
196 }
197 }
198
199 if (a)
200 {
201 FREE(&name);
203 /* override the previous value */
205 FREE(&a->comment);
206 event = NT_ALIAS_CHANGE;
207 }
208 else
209 {
210 /* create a new alias */
211 a = alias_new();
212 a->name = name;
213 ARRAY_ADD(&md->aliases, a);
214 event = NT_ALIAS_ADD;
215 }
216 a->addr = al;
217
219
220 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
221 if (c_debug_level > LL_DEBUG4)
222 {
223 /* A group is terminated with an empty address, so check addr->mailbox */
224 struct Address *addr = NULL;
225 TAILQ_FOREACH(addr, &a->addr, entries)
226 {
227 if (!addr->mailbox)
228 break;
229
230 if (addr->group)
231 mutt_debug(LL_DEBUG5, " Group %s\n", buf_string(addr->mailbox));
232 else
233 mutt_debug(LL_DEBUG5, " %s\n", buf_string(addr->mailbox));
234 }
235 }
236
237 if (!MoreArgs(line) && (line->dptr[0] == '#'))
238 {
239 line->dptr++; // skip over the "# "
240 if (*line->dptr == ' ')
241 line->dptr++;
242
243 parse_alias_comments(a, line->dptr);
244 *line->dptr = '\0'; // We're done parsing
245 }
246
248
249 mutt_debug(LL_NOTIFY, "%s: %s\n",
250 (event == NT_ALIAS_ADD) ? "NT_ALIAS_ADD" : "NT_ALIAS_CHANGE", a->name);
251 struct EventAlias ev_a = { a };
252 notify_send(NeoMutt->notify, NT_ALIAS, event, &ev_a);
253
254 rc = MUTT_CMD_SUCCESS;
255
256done:
257 buf_pool_release(&token);
259 return rc;
260}
261
268enum CommandResult parse_unalias(const struct Command *cmd, struct Buffer *line,
269 const struct ParseContext *pc, struct ParseError *pe)
270{
271 struct Buffer *err = pe->message;
272
273 if (!MoreArgs(line))
274 {
275 buf_printf(err, _("%s: too few arguments"), cmd->name);
276 return MUTT_CMD_WARNING;
277 }
278
279 struct Buffer *token = buf_pool_get();
280
282 ASSERT(md);
283
284 do
285 {
287
288 struct Alias **ap = NULL;
289 if (mutt_str_equal("*", buf_string(token)))
290 {
291 ARRAY_FOREACH(ap, &md->aliases)
292 {
294 }
295
297 goto done;
298 }
299
300 ARRAY_FOREACH(ap, &md->aliases)
301 {
302 if (!mutt_istr_equal(buf_string(token), (*ap)->name))
303 continue;
304
305 struct Alias *a = *ap;
306 ARRAY_REMOVE(&md->aliases, ap);
308 alias_free(&a);
309 break;
310 }
311 } while (MoreArgs(line));
312
313done:
314 buf_pool_release(&token);
315 return MUTT_CMD_SUCCESS;
316}
317
321const struct Command AliasCommands[] = {
322 // clang-format off
323 { "alias", CMD_ALIAS, parse_alias,
324 N_("Define an alias (name to email address)"),
325 N_("alias [ -group <name> ... ] <key> <address> [,...] [ # <comments> ]"),
326 "configuration.html#alias" },
327 { "alternates", CMD_ALTERNATES, parse_alternates,
328 N_("Define a list of alternate email addresses for the user"),
329 N_("alternates [ -group <name> ... ] <regex> [ <regex> ... ]"),
330 "configuration.html#alternates" },
331 { "unalias", CMD_UNALIAS, parse_unalias,
332 N_("Remove an alias definition"),
333 N_("unalias { * | <key> ... }"),
334 "configuration.html#alias" },
335 { "unalternates", CMD_UNALTERNATES, parse_unalternates,
336 N_("Remove addresses from `alternates` list"),
337 N_("unalternates { * | <regex> ... }"),
338 "configuration.html#alternates" },
339
340 { NULL, CMD_NONE, NULL, NULL, NULL, NULL, CF_NO_FLAGS },
341 // clang-format on
342};
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1469
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:649
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition address.c:1302
void grouplist_add_addrlist(struct GroupList *gl, struct AddressList *al)
Add Address list to a GroupList.
Definition group.c:224
void grouplist_destroy(struct GroupList *gl)
Free a GroupList.
Definition group.c:203
Email Address Handling.
void parse_alias_comments(struct Alias *alias, const char *com)
Parse the alias/query comment field.
Definition commands.c:95
void parse_alias_tags(const char *tags, struct TagList *tl)
Parse a comma-separated list of tags.
Definition commands.c:65
const struct Command AliasCommands[]
Alias Commands.
Definition commands.c:321
void alias_tags_to_buffer(struct TagList *tl, struct Buffer *buf)
Write a comma-separated list of tags to a Buffer.
Definition commands.c:49
Email Aliases.
Alias private Module data.
void alias_free(struct Alias **ptr)
Free an Alias.
Definition alias.c:673
void aliaslist_clear(struct AliasArray *aa)
Empty a List of Aliases.
Definition alias.c:698
struct Alias * alias_new(void)
Create a new Alias.
Definition alias.c:661
Representation of a single alias to an email address.
NotifyAlias
Alias notification types.
Definition alias.h:54
@ NT_ALIAS_ADD
Alias has been added.
Definition alias.h:55
@ NT_ALIAS_CHANGE
Alias has been changed.
Definition alias.h:58
Parse Alternate Commands.
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_REMOVE(head, elem)
Remove an entry from the array, shifting down the subsequent entries.
Definition array.h:355
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition buffer.c:96
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:76
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
#define CF_NO_FLAGS
No flags are set.
Definition command.h:48
@ CMD_UNALIAS
:unalias
Definition command.h:123
@ CMD_ALIAS
:alias
Definition command.h:61
@ CMD_NONE
No Command.
Definition command.h:59
@ CMD_ALTERNATES
:alternates
Definition command.h:62
@ CMD_UNALTERNATES
:unalternates
Definition command.h:124
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
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
int parse_grouplist(struct GroupList *gl, struct Buffer *token, struct Buffer *line, struct Buffer *err, struct HashTable *groups)
Parse a group context.
Definition group.c:56
Structs that make up 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 TOKEN_SPACE
Don't treat whitespace as a term.
Definition extract.h:48
#define TOKEN_QUOTE
Don't interpret quotes.
Definition extract.h:49
#define MoreArgs(buf)
Definition extract.h:31
#define TOKEN_SEMICOLON
Don't treat ; as special.
Definition extract.h:52
#define TOKEN_NO_FLAGS
No flags are set.
Definition extract.h:45
enum CommandResult parse_unalias(const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
Parse the 'unalias' command - Implements Command::parse() -.
Definition commands.c:268
enum CommandResult parse_alternates(const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
Parse the 'alternates' command - Implements Command::parse() -.
Definition alternates.c:67
enum CommandResult parse_unalternates(const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
Parse the 'unalternates' command - Implements Command::parse() -.
Definition alternates.c:118
enum CommandResult parse_alias(const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
Parse the 'alias' command - Implements Command::parse() -.
Definition commands.c:138
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
@ LL_DEBUG4
Log at debug level 4.
Definition logging2.h:48
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:49
@ LL_NOTIFY
Log of notifications.
Definition logging2.h:50
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
@ MODULE_ID_ALIAS
ModuleAlias, Alias
Definition module_api.h:48
Convenience wrapper for the library headers.
#define N_(a)
Definition message.h:32
#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
struct Slist * slist_parse(const char *str, uint32_t flags)
Parse a list of strings into a list.
Definition slist.c:177
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition slist.c:140
void slist_free(struct Slist **ptr)
Free an Slist object.
Definition slist.c:124
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:677
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:585
@ NT_ALIAS
Alias has changed, NotifyAlias, EventAlias.
Definition notify_type.h:37
Text parsing functions.
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
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
Match a precompiled regex against a string.
Definition prex.c:301
@ PREX_ALIAS_TAGS
tags:a,b,c
Definition prex.h:43
@ PREX_ALIAS_TAGS_MATCH_POST
... tags:a,b,c[ ...]
Definition prex.h:240
@ PREX_ALIAS_TAGS_MATCH_PRE
[... ]tags:a,b,c ...
Definition prex.h:237
@ PREX_ALIAS_TAGS_MATCH_TAGS
... tags:[a,b,c] ...
Definition prex.h:239
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
#define STAILQ_HEAD_INITIALIZER(head)
Definition queue.h:324
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition queue.h:427
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
static regoff_t mutt_regmatch_end(const regmatch_t *match)
Return the end of a match.
Definition regex3.h:66
static regoff_t mutt_regmatch_start(const regmatch_t *match)
Return the start of a match.
Definition regex3.h:56
void alias_reverse_add(struct Alias *alias)
Add an email address lookup for an Alias.
Definition reverse.c:62
void alias_reverse_delete(struct Alias *alias)
Remove an email address lookup for an Alias.
Definition reverse.c:87
Manage alias reverse lookups.
#define ASSERT(COND)
Definition signal2.h:59
An email address.
Definition address.h:35
bool group
Group mailbox?
Definition address.h:38
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
Alias private Module data.
Definition module_data.h:33
struct AliasArray aliases
User's email aliases.
Definition module_data.h:34
A shortcut for an email address or addresses.
Definition alias.h:35
struct TagList tags
Tags.
Definition alias.h:39
char * comment
Free-form comment string.
Definition alias.h:38
char * name
Short name.
Definition alias.h:36
struct AddressList addr
List of Addresses the Alias expands to.
Definition alias.h:37
String manipulation buffer.
Definition buffer.h:36
char * dptr
Current read/write position.
Definition buffer.h:38
const char * name
Name of the Command.
Definition command.h:159
An alias-change event.
Definition alias.h:65
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
Container for Accounts, Notifications.
Definition neomutt.h:41
struct Notify * notify
Notifications handler.
Definition neomutt.h:45
struct HashTable * groups
Hash Table: "group-name" -> Group.
Definition neomutt.h:54
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
String list.
Definition slist.h:37
struct ListHead head
List containing values.
Definition slist.h:38
LinkedList Tag Element.
Definition tags.h:41
char * name
Tag name.
Definition tags.h:42
struct Tag * tag_new(void)
Create a new Tag.
Definition tags.c:62
#define D_SLIST_SEP_COMMA
Slist items are comma-separated.
Definition types.h:111