NeoMutt  2024-11-14-34-g5aaf0d
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
commands.c
Go to the documentation of this file.
1
30#include "config.h"
31#include <stdint.h>
32#include <stdio.h>
33#include "mutt/lib.h"
34#include "address/lib.h"
35#include "config/lib.h"
36#include "email/lib.h"
37#include "core/lib.h"
38#include "commands.h"
39#include "lib.h"
40#include "parse/lib.h"
41#include "alias.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
135enum CommandResult parse_alias(struct Buffer *buf, struct Buffer *s,
136 intptr_t data, struct Buffer *err)
137{
138 struct Alias *tmp = NULL;
139 struct GroupList gl = STAILQ_HEAD_INITIALIZER(gl);
140 enum NotifyAlias event;
141
142 if (!MoreArgs(s))
143 {
144 buf_strcpy(err, _("alias: no address"));
145 return MUTT_CMD_WARNING;
146 }
147
148 /* name */
150 mutt_debug(LL_DEBUG5, "First token is '%s'\n", buf->data);
151 if (parse_grouplist(&gl, buf, s, err) == -1)
152 {
153 return MUTT_CMD_ERROR;
154 }
155 char *name = mutt_str_dup(buf->data);
156
157 /* address list */
159 mutt_debug(LL_DEBUG5, "Second token is '%s'\n", buf->data);
160 struct AddressList al = TAILQ_HEAD_INITIALIZER(al);
161 int parsed = mutt_addrlist_parse2(&al, buf->data);
162 if (parsed == 0)
163 {
164 buf_printf(err, _("Warning: Bad address '%s' in alias '%s'"), buf->data, name);
165 FREE(&name);
166 goto bail;
167 }
168
169 /* IDN */
170 char *estr = NULL;
171 if (mutt_addrlist_to_intl(&al, &estr))
172 {
173 buf_printf(err, _("Warning: Bad IDN '%s' in alias '%s'"), estr, name);
174 FREE(&name);
175 FREE(&estr);
176 goto bail;
177 }
178
179 /* check to see if an alias with this name already exists */
180 TAILQ_FOREACH(tmp, &Aliases, entries)
181 {
182 if (mutt_istr_equal(tmp->name, name))
183 break;
184 }
185
186 if (tmp)
187 {
188 FREE(&name);
190 /* override the previous value */
192 FREE(&tmp->comment);
193 event = NT_ALIAS_CHANGE;
194 }
195 else
196 {
197 /* create a new alias */
198 tmp = alias_new();
199 tmp->name = name;
200 TAILQ_INSERT_TAIL(&Aliases, tmp, entries);
201 event = NT_ALIAS_ADD;
202 }
203 tmp->addr = al;
204
206
207 const short c_debug_level = cs_subset_number(NeoMutt->sub, "debug_level");
208 if (c_debug_level > LL_DEBUG4)
209 {
210 /* A group is terminated with an empty address, so check a->mailbox */
211 struct Address *a = NULL;
212 TAILQ_FOREACH(a, &tmp->addr, entries)
213 {
214 if (!a->mailbox)
215 break;
216
217 if (a->group)
218 mutt_debug(LL_DEBUG5, " Group %s\n", buf_string(a->mailbox));
219 else
220 mutt_debug(LL_DEBUG5, " %s\n", buf_string(a->mailbox));
221 }
222 }
224 if (!MoreArgs(s) && (s->dptr[0] == '#'))
225 {
226 s->dptr++; // skip over the "# "
227 if (*s->dptr == ' ')
228 s->dptr++;
229
230 parse_alias_comments(tmp, s->dptr);
231 *s->dptr = '\0'; // We're done parsing
232 }
233
235
236 mutt_debug(LL_NOTIFY, "%s: %s\n",
237 (event == NT_ALIAS_ADD) ? "NT_ALIAS_ADD" : "NT_ALIAS_CHANGE", tmp->name);
238 struct EventAlias ev_a = { tmp };
239 notify_send(NeoMutt->notify, NT_ALIAS, event, &ev_a);
240
241 return MUTT_CMD_SUCCESS;
242
243bail:
245 return MUTT_CMD_ERROR;
246}
247
251enum CommandResult parse_unalias(struct Buffer *buf, struct Buffer *s,
252 intptr_t data, struct Buffer *err)
253{
254 do
255 {
257
258 struct Alias *np = NULL;
259 if (mutt_str_equal("*", buf->data))
260 {
261 TAILQ_FOREACH(np, &Aliases, entries)
262 {
264 }
265
267 return MUTT_CMD_SUCCESS;
268 }
269
270 TAILQ_FOREACH(np, &Aliases, entries)
271 {
272 if (!mutt_istr_equal(buf->data, np->name))
273 continue;
274
275 TAILQ_REMOVE(&Aliases, np, entries);
277 alias_free(&np);
278 break;
279 }
280 } while (MoreArgs(s));
281 return MUTT_CMD_SUCCESS;
282}
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:95
void parse_alias_tags(const char *tags, struct TagList *tl)
Parse a comma-separated list of tags.
Definition: commands.c:65
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
void alias_free(struct Alias **ptr)
Free an Alias.
Definition: alias.c:672
struct AliasList Aliases
List of all the user's email aliases.
Definition: alias.c:62
struct Alias * alias_new(void)
Create a new Alias.
Definition: alias.c:660
void aliaslist_clear(struct AliasList *al)
Empty a List of Aliases.
Definition: alias.c:697
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
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
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:36
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition: command.h:39
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition: command.h:37
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition: command.h:38
int parse_grouplist(struct GroupList *gl, struct Buffer *buf, struct Buffer *s, struct Buffer *err)
Parse a group context.
Definition: commands.c:131
Functions to parse commands in a config file.
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 *tok, TokenFlags flags)
Extract one token from a string.
Definition: extract.c:50
#define TOKEN_SPACE
Don't treat whitespace as a term.
Definition: extract.h:49
#define TOKEN_QUOTE
Don't interpret quotes.
Definition: extract.h:50
#define MoreArgs(buf)
Definition: extract.h:32
#define TOKEN_SEMICOLON
Don't treat ; as special.
Definition: extract.h:53
#define TOKEN_NO_FLAGS
No flags are set.
Definition: extract.h:46
void mutt_grouplist_destroy(struct GroupList *gl)
Free a GroupList.
Definition: group.c:202
void mutt_grouplist_add_addrlist(struct GroupList *gl, struct AddressList *al)
Add Address list to a GroupList.
Definition: group.c:271
enum CommandResult parse_alias(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'alias' command - Implements Command::parse() -.
Definition: commands.c:135
enum CommandResult parse_unalias(struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
Parse the 'unalias' command - Implements Command::parse() -.
Definition: commands.c:251
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG4
Log at debug level 4.
Definition: logging2.h:46
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_NOTIFY
Log of notifications.
Definition: logging2.h:48
#define FREE(x)
Definition: memory.h:55
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:175
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition: slist.c:138
void slist_free(struct Slist **ptr)
Free an Slist object.
Definition: slist.c:122
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:253
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:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
Match a precompiled regex against a string.
Definition: prex.c:298
@ 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:725
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:389
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
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.
Key value store.
An email address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:39
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
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
char * data
Pointer to data.
Definition: buffer.h:37
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:42
struct Notify * notify
Notifications handler.
Definition: neomutt.h:43
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
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:111