NeoMutt  2025-12-11-58-g09398d
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 "commands.h"
38#include "lib.h"
39#include "parse/lib.h"
40#include "alias.h"
41#include "reverse.h"
42
48void alias_tags_to_buffer(struct TagList *tl, struct Buffer *buf)
49{
50 struct Tag *tag = NULL;
51 STAILQ_FOREACH(tag, tl, entries)
52 {
53 buf_addstr(buf, tag->name);
54 if (STAILQ_NEXT(tag, entries))
55 buf_addch(buf, ',');
56 }
57}
58
64void parse_alias_tags(const char *tags, struct TagList *tl)
65{
66 if (!tags || !tl)
67 return;
68
69 struct Slist *sl = slist_parse(tags, D_SLIST_SEP_COMMA);
70 if (slist_is_empty(sl))
71 {
72 slist_free(&sl);
73 return;
74 }
75
76 struct ListNode *np = NULL;
77 STAILQ_FOREACH(np, &sl->head, entries)
78 {
79 struct Tag *tag = tag_new();
80 tag->name = np->data; // Transfer string
81 np->data = NULL;
82 STAILQ_INSERT_TAIL(tl, tag, entries);
83 }
84 slist_free(&sl);
85}
86
94void parse_alias_comments(struct Alias *alias, const char *com)
95{
96 if (!com || (com[0] == '\0'))
97 return;
98
99 const regmatch_t *match = mutt_prex_capture(PREX_ALIAS_TAGS, com);
100 if (match)
101 {
102 const regmatch_t *pre = &match[PREX_ALIAS_TAGS_MATCH_PRE];
103 const regmatch_t *tags = &match[PREX_ALIAS_TAGS_MATCH_TAGS];
104 const regmatch_t *post = &match[PREX_ALIAS_TAGS_MATCH_POST];
105
106 struct Buffer *tmp = buf_pool_get();
107
108 // Extract the tags
109 buf_addstr_n(tmp, com + mutt_regmatch_start(tags),
111 parse_alias_tags(buf_string(tmp), &alias->tags);
112 buf_reset(tmp);
113
114 // Collect all the other text as "comments"
115 buf_addstr_n(tmp, com + mutt_regmatch_start(pre),
117 buf_addstr_n(tmp, com + mutt_regmatch_start(post),
119 alias->comment = buf_strdup(tmp);
120
121 buf_pool_release(&tmp);
122 }
123 else
124 {
125 alias->comment = mutt_str_dup(com);
126 }
127}
128
137enum CommandResult parse_alias(const struct Command *cmd, struct Buffer *line,
138 struct Buffer *err)
139{
140 if (!MoreArgs(line))
141 {
142 buf_printf(err, _("%s: too few arguments"), cmd->name);
143 return MUTT_CMD_WARNING;
144 }
145
146 struct Alias *tmp = NULL;
147 enum NotifyAlias event;
148 struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
149 struct Buffer *token = buf_pool_get();
151
152 /* name */
154 mutt_debug(LL_DEBUG5, "First token is '%s'\n", buf_string(token));
155 if (parse_grouplist(&gl, token, line, err, NeoMutt->groups) == -1)
156 goto done;
157
158 char *name = mutt_str_dup(buf_string(token));
159
160 /* address list */
162 mutt_debug(LL_DEBUG5, "Second token is '%s'\n", buf_string(token));
163 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
164 int parsed = mutt_addrlist_parse2(&al, buf_string(token));
165 if (parsed == 0)
166 {
167 buf_printf(err, _("Warning: Bad address '%s' in alias '%s'"), buf_string(token), name);
168 FREE(&name);
169 goto done;
170 }
171
172 /* IDN */
173 char *estr = NULL;
174 if (mutt_addrlist_to_intl(&al, &estr))
175 {
176 buf_printf(err, _("Warning: Bad IDN '%s' in alias '%s'"), estr, name);
177 FREE(&name);
178 FREE(&estr);
179 goto done;
180 }
181
182 /* check to see if an alias with this name already exists */
183 TAILQ_FOREACH(tmp, &Aliases, entries)
184 {
185 if (mutt_istr_equal(tmp->name, name))
186 break;
187 }
188
189 if (tmp)
190 {
191 FREE(&name);
193 /* override the previous value */
195 FREE(&tmp->comment);
196 event = NT_ALIAS_CHANGE;
197 }
198 else
199 {
200 /* create a new alias */
201 tmp = alias_new();
202 tmp->name = name;
203 TAILQ_INSERT_TAIL(&Aliases, tmp, entries);
204 event = NT_ALIAS_ADD;
205 }
206 tmp->addr = al;
207
208 grouplist_add_addrlist(&gl, &tmp->addr);
209
210 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
211 if (c_debug_level > LL_DEBUG4)
212 {
213 /* A group is terminated with an empty address, so check a->mailbox */
214 struct Address *a = NULL;
215 TAILQ_FOREACH(a, &tmp->addr, entries)
216 {
217 if (!a->mailbox)
218 break;
219
220 if (a->group)
221 mutt_debug(LL_DEBUG5, " Group %s\n", buf_string(a->mailbox));
222 else
223 mutt_debug(LL_DEBUG5, " %s\n", buf_string(a->mailbox));
224 }
225 }
226
227 if (!MoreArgs(line) && (line->dptr[0] == '#'))
228 {
229 line->dptr++; // skip over the "# "
230 if (*line->dptr == ' ')
231 line->dptr++;
232
233 parse_alias_comments(tmp, line->dptr);
234 *line->dptr = '\0'; // We're done parsing
235 }
236
238
239 mutt_debug(LL_NOTIFY, "%s: %s\n",
240 (event == NT_ALIAS_ADD) ? "NT_ALIAS_ADD" : "NT_ALIAS_CHANGE", tmp->name);
241 struct EventAlias ev_a = { tmp };
242 notify_send(NeoMutt->notify, NT_ALIAS, event, &ev_a);
243
244 rc = MUTT_CMD_SUCCESS;
245
246done:
247 buf_pool_release(&token);
249 return rc;
250}
251
258enum CommandResult parse_unalias(const struct Command *cmd, struct Buffer *line,
259 struct Buffer *err)
260{
261 if (!MoreArgs(line))
262 {
263 buf_printf(err, _("%s: too few arguments"), cmd->name);
264 return MUTT_CMD_WARNING;
265 }
266
267 struct Buffer *token = buf_pool_get();
268
269 do
270 {
272
273 struct Alias *np = NULL;
274 if (mutt_str_equal("*", buf_string(token)))
275 {
276 TAILQ_FOREACH(np, &Aliases, entries)
277 {
279 }
280
282 goto done;
283 }
284
285 TAILQ_FOREACH(np, &Aliases, entries)
286 {
287 if (!mutt_istr_equal(buf_string(token), np->name))
288 continue;
289
290 TAILQ_REMOVE(&Aliases, np, entries);
292 alias_free(&np);
293 break;
294 }
295 } while (MoreArgs(line));
296
297done:
298 buf_pool_release(&token);
299 return MUTT_CMD_SUCCESS;
300}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1460
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:644
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition address.c:1293
Email Address Handling.
void parse_alias_comments(struct Alias *alias, const char *com)
Parse the alias/query comment field.
Definition commands.c:94
void parse_alias_tags(const char *tags, struct TagList *tl)
Parse a comma-separated list of tags.
Definition commands.c:64
void alias_tags_to_buffer(struct TagList *tl, struct Buffer *buf)
Write a comma-separated list of tags to a Buffer.
Definition commands.c:48
Email Aliases.
void alias_free(struct Alias **ptr)
Free an Alias.
Definition alias.c:668
struct AliasList Aliases
List of all the user's email aliases.
Definition alias.c:61
struct Alias * alias_new(void)
Create a new Alias.
Definition alias.c:656
void aliaslist_clear(struct AliasList *al)
Empty a List of Aliases.
Definition alias.c:693
Representation of a single alias to an email address.
NotifyAlias
Alias notification types.
Definition alias.h:55
@ NT_ALIAS_ADD
Alias has been added.
Definition alias.h:56
@ NT_ALIAS_CHANGE
Alias has been changed.
Definition alias.h:59
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
CommandResult
Error codes for command_t parse functions.
Definition command.h:35
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition command.h:38
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition command.h:36
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition command.h:37
int parse_grouplist(struct GroupList *gl, struct Buffer *token, struct Buffer *line, struct Buffer *err, struct HashTable *groups)
Parse a group context.
Definition commands.c:145
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.
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:48
#define TOKEN_SPACE
Don't treat whitespace as a term.
Definition extract.h:47
#define TOKEN_QUOTE
Don't interpret quotes.
Definition extract.h:48
#define MoreArgs(buf)
Definition extract.h:30
#define TOKEN_SEMICOLON
Don't treat ; as special.
Definition extract.h:51
#define TOKEN_NO_FLAGS
No flags are set.
Definition extract.h:44
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
enum CommandResult parse_alias(const struct Command *cmd, struct Buffer *line, struct Buffer *err)
Parse the 'alias' command - Implements Command::parse() -.
Definition commands.c:137
enum CommandResult parse_unalias(const struct Command *cmd, struct Buffer *line, struct Buffer *err)
Parse the 'unalias' command - Implements Command::parse() -.
Definition commands.c:258
#define mutt_debug(LEVEL,...)
Definition logging2.h:90
@ LL_DEBUG4
Log at debug level 4.
Definition logging2.h:47
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:48
@ LL_NOTIFY
Log of notifications.
Definition logging2.h:49
#define FREE(x)
Definition memory.h:62
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
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:672
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:255
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:660
@ 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:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:96
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
Match a precompiled regex against a string.
Definition prex.c:297
@ 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 TAILQ_INSERT_TAIL(head, elm, field)
Definition queue.h:866
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition queue.h:427
#define TAILQ_REMOVE(head, elm, field)
Definition queue.h:901
#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:67
static regoff_t mutt_regmatch_start(const regmatch_t *match)
Return the start of a match.
Definition regex3.h:57
void alias_reverse_add(struct Alias *alias)
Add an email address lookup for an Alias.
Definition reverse.c:61
void alias_reverse_delete(struct Alias *alias)
Remove an email address lookup for an Alias.
Definition reverse.c:83
Manage alias reverse lookups.
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
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:59
An alias-change event.
Definition alias.h:66
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
Container for Accounts, Notifications.
Definition neomutt.h:43
struct Notify * notify
Notifications handler.
Definition neomutt.h:44
struct HashTable * groups
Hash Table: "group-name" -> Group.
Definition neomutt.h:52
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:47
String list.
Definition slist.h:37
struct ListHead head
List containing values.
Definition slist.h:38
LinkedList Tag Element.
Definition tags.h:42
char * name
Tag name.
Definition tags.h:43
struct Tag * tag_new(void)
Create a new Tag.
Definition tags.c:64
#define D_SLIST_SEP_COMMA
Slist items are comma-separated.
Definition types.h:110