NeoMutt  2025-12-11-177-g48e272
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
alias.c File Reference

Representation of a single alias to an email address. More...

#include "config.h"
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "alias.h"
#include "lib.h"
#include "browser/lib.h"
#include "commands/lib.h"
#include "editor/lib.h"
#include "history/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "globals.h"
#include "muttlib.h"
#include "reverse.h"
+ Include dependency graph for alias.c:

Go to the source code of this file.

Functions

static void write_safe_address (FILE *fp, const char *s)
 Defang malicious email addresses.
 
static void expand_aliases_r (struct AddressList *al, struct ListHead *expn)
 Expand aliases, recursively.
 
static void recode_buf (struct Buffer *buf)
 Convert some text between two character sets.
 
static int check_alias_name (const char *s, struct Buffer *dest)
 Sanity-check an alias name.
 
static bool string_is_address (const char *str, const char *user, const char *domain)
 Does an email address match a user and domain?
 
struct AddressList * alias_lookup (const char *name)
 Find an Alias.
 
void mutt_expand_aliases (struct AddressList *al)
 Expand aliases in a List of Addresses.
 
void mutt_expand_aliases_env (struct Envelope *env)
 Expand aliases in all the fields of an Envelope.
 
struct AddressList * mutt_get_address (struct Envelope *env, const char **prefix)
 Get an Address from an Envelope.
 
void alias_create (struct AddressList *al, const struct ConfigSubset *sub)
 Create a new Alias from an Address.
 
bool mutt_addr_is_user (const struct Address *addr)
 Does the address belong to the user.
 
struct Aliasalias_new (void)
 Create a new Alias.
 
void alias_free (struct Alias **ptr)
 Free an Alias.
 
void aliaslist_clear (struct AliasList *al)
 Empty a List of Aliases.
 
void alias_init (void)
 Set up the Alias globals.
 
void alias_cleanup (void)
 Clean up the Alias globals.
 

Variables

struct AliasList Aliases = TAILQ_HEAD_INITIALIZER(Aliases)
 List of all the user's email aliases.
 

Detailed Description

Representation of a single alias to an email address.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Federico Kircheis
  • Anna Figueiredo Gomes
  • Dennis Schön

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file alias.c.

Function Documentation

◆ write_safe_address()

static void write_safe_address ( FILE * fp,
const char * s )
static

Defang malicious email addresses.

Parameters
fpFile to write to
sEmail address to defang

if someone has an address like From: John /bin/rm -f ~ Doe john..nosp@m.doe@.nosp@m.examp.nosp@m.le.c.nosp@m.om and the user creates an alias for this, NeoMutt could wind up executing the backticks because it writes aliases like alias me John /bin/rm -f ~ Doe john..nosp@m.doe@.nosp@m.examp.nosp@m.le.c.nosp@m.om To avoid this problem, use a backslash () to quote any backticks. We also need to quote backslashes as well, since you could defeat the above by doing From: John `/bin/rm -f ~` Doe john..nosp@m.doe@.nosp@m.examp.nosp@m.le.c.nosp@m.om since that would get aliased as alias me John \/bin/rm -f ~\\ Doe john..nosp@m.doe@.nosp@m.examp.nosp@m.le.c.nosp@m.om which still gets evaluated because the double backslash is not a quote.

Additionally, we need to quote ' and " characters, otherwise neomutt will interpret them on the wrong parsing step.

$ wants to be quoted since it may indicate the start of an environment variable.

Definition at line 86 of file alias.c.

87{
88 while (*s)
89 {
90 if ((*s == '\\') || (*s == '`') || (*s == '\'') || (*s == '"') || (*s == '$'))
91 fputc('\\', fp);
92 fputc(*s, fp);
93 s++;
94 }
95}
+ Here is the caller graph for this function:

◆ expand_aliases_r()

static void expand_aliases_r ( struct AddressList * al,
struct ListHead * expn )
static

Expand aliases, recursively.

Parameters
[in]alAddress List
[out]expnAlias List

ListHead expn is used as temporary storage for already-expanded aliases.

Definition at line 104 of file alias.c.

105{
106 struct Address *a = TAILQ_FIRST(al);
107 while (a)
108 {
109 if (!a->group && !a->personal && a->mailbox && !buf_find_char(a->mailbox, '@'))
110 {
111 struct AddressList *alias = alias_lookup(buf_string(a->mailbox));
112 if (alias)
113 {
114 bool duplicate = false;
115 struct ListNode *np = NULL;
116 STAILQ_FOREACH(np, expn, entries)
117 {
118 if (mutt_str_equal(buf_string(a->mailbox), np->data)) /* alias already found */
119 {
120 mutt_debug(LL_DEBUG1, "loop in alias found for '%s'\n", buf_string(a->mailbox));
121 duplicate = true;
122 break;
123 }
124 }
125
126 if (duplicate)
127 {
128 // We've already seen this alias, so drop it
129 struct Address *next = TAILQ_NEXT(a, entries);
130 TAILQ_REMOVE(al, a, entries);
131 mutt_addr_free(&a);
132 a = next;
133 continue;
134 }
135
136 // Keep a list of aliases that we've already seen
138
139 /* The alias may expand to several addresses,
140 * some of which may themselves be aliases.
141 * Create a copy and recursively expand any aliases within. */
142 struct AddressList copy = TAILQ_HEAD_INITIALIZER(copy);
143 mutt_addrlist_copy(&copy, alias, false);
144 expand_aliases_r(&copy, expn);
145
146 /* Next, move the expanded addresses
147 * from the copy into the original list (before the alias) */
148 struct Address *a2 = NULL, *tmp = NULL;
149 TAILQ_FOREACH_SAFE(a2, &copy, entries, tmp)
150 {
151 TAILQ_INSERT_BEFORE(a, a2, entries);
152 }
153 a = TAILQ_PREV(a, AddressList, entries);
154 // Finally, remove the alias itself
155 struct Address *next = TAILQ_NEXT(a, entries);
156 TAILQ_REMOVE(al, next, entries);
157 mutt_addr_free(&next);
158 }
159 else
160 {
161 struct passwd *pw = getpwnam(buf_string(a->mailbox));
162 if (pw)
163 {
164 char namebuf[256] = { 0 };
165
166 mutt_gecos_name(namebuf, sizeof(namebuf), pw);
167 a->personal = buf_new(namebuf);
168 }
169 }
170 }
171 a = TAILQ_NEXT(a, entries);
172 }
173
174 const char *fqdn = NULL;
175 const bool c_use_domain = cs_subset_bool(NeoMutt->sub, "use_domain");
176 if (c_use_domain && (fqdn = mutt_fqdn(true, NeoMutt->sub)))
177 {
178 /* now qualify all local addresses */
179 mutt_addrlist_qualify(al, fqdn);
180 }
181}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:765
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition address.c:680
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition address.c:462
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition alias.c:275
static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
Expand aliases, recursively.
Definition alias.c:104
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition buffer.c:304
const char * buf_find_char(const struct Buffer *buf, const char c)
Return a pointer to a char found in the buffer.
Definition buffer.c:653
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
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition list.c:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user's real name in /etc/passwd.
Definition muttlib.c:331
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition queue.h:792
#define TAILQ_PREV(elm, headname, field)
Definition queue.h:891
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define TAILQ_FIRST(head)
Definition queue.h:780
#define TAILQ_REMOVE(head, elm, field)
Definition queue.h:901
#define TAILQ_NEXT(elm, field)
Definition queue.h:889
#define TAILQ_HEAD_INITIALIZER(head)
Definition queue.h:694
#define TAILQ_INSERT_BEFORE(listelm, elm, field)
Definition queue.h:843
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:706
An email address.
Definition address.h:35
struct Buffer * personal
Real name of address.
Definition address.h:36
bool group
Group mailbox?
Definition address.h:38
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
A List node for strings.
Definition list.h:37
char * data
String.
Definition list.h:38
Container for Accounts, Notifications.
Definition neomutt.h:128
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:134
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ recode_buf()

static void recode_buf ( struct Buffer * buf)
static

Convert some text between two character sets.

Parameters
bufBuffer to convert

The 'from' charset is controlled by the 'charset' config variable. The 'to' charset is controlled by the 'config_charset' config variable.

Definition at line 190 of file alias.c.

191{
192 const char *const c_config_charset = cs_subset_string(NeoMutt->sub, "config_charset");
193 if (!c_config_charset || !cc_charset())
194 return;
195
196 char *s = buf_strdup(buf);
197 if (!s)
198 return;
199 if (mutt_ch_convert_string(&s, cc_charset(), c_config_charset, MUTT_ICONV_NO_FLAGS) == 0)
200 buf_strcpy(buf, s);
201 FREE(&s);
202}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
const char * cc_charset(void)
Get the cached value of $charset.
#define FREE(x)
Definition memory.h:63
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition charset.c:817
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition charset.h:66
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ check_alias_name()

static int check_alias_name ( const char * s,
struct Buffer * dest )
static

Sanity-check an alias name.

Parameters
sAlias to check
destBuffer for the result
Return values
0Success
-1Error

Only characters which are non-special to both the RFC822 and the neomutt configuration parser are permitted.

Definition at line 214 of file alias.c.

215{
216 wchar_t wc = 0;
217 mbstate_t mbstate = { 0 };
218 size_t l;
219 int rc = 0;
220 bool dry = !dest; // Dry run
221
222 if (!dry)
223 buf_reset(dest);
224 for (; s && *s && (l = mbrtowc(&wc, s, MB_CUR_MAX, &mbstate)) != 0; s += l)
225 {
226 bool bad = (l == ICONV_ILLEGAL_SEQ) || (l == ICONV_BUF_TOO_SMALL); /* conversion error */
227 if (l == 1)
228 bad = bad || (!strchr("-_+=.", *s) && !iswalnum(wc));
229 else
230 bad = bad || !iswalnum(wc);
231 if (bad)
232 {
233 if (dry)
234 return -1;
235 if (l == ICONV_ILLEGAL_SEQ)
236 memset(&mbstate, 0, sizeof(mbstate_t));
237 buf_addch(dest, '_');
238 rc = -1;
239 }
240 else if (!dry)
241 {
242 buf_addstr_n(dest, s, l);
243 }
244 }
245
246 return rc;
247}
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
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition charset.h:116
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition charset.h:114
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ string_is_address()

static bool string_is_address ( const char * str,
const char * user,
const char * domain )
static

Does an email address match a user and domain?

Parameters
strAddress string to test
userUser name
domainDomain name
Return values
trueThey match

Definition at line 256 of file alias.c.

257{
258 char buf[1024] = { 0 };
259
260 snprintf(buf, sizeof(buf), "%s@%s", NONULL(user), NONULL(domain));
261 if (mutt_istr_equal(str, buf))
262 return true;
263
264 return false;
265}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:674
#define NONULL(x)
Definition string2.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_lookup()

struct AddressList * alias_lookup ( const char * name)

Find an Alias.

Parameters
nameAlias name to find
Return values
ptrAddress for the Alias
NULLNo such Alias
Note
The search is case-insensitive

Definition at line 275 of file alias.c.

276{
277 struct Alias *a = NULL;
278
279 TAILQ_FOREACH(a, &Aliases, entries)
280 {
281 if (mutt_istr_equal(name, a->name))
282 return &a->addr;
283 }
284 return NULL;
285}
struct AliasList Aliases
List of all the user's email aliases.
Definition alias.c:60
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
A shortcut for an email address or addresses.
Definition alias.h:35
char * name
Short name.
Definition alias.h:36
struct AddressList addr
List of Addresses the Alias expands to.
Definition alias.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_expand_aliases()

void mutt_expand_aliases ( struct AddressList * al)

Expand aliases in a List of Addresses.

Parameters
alAddressList

Duplicate addresses are dropped

Definition at line 293 of file alias.c.

294{
295 // previously expanded aliases to avoid loops
296 struct ListHead expn = STAILQ_HEAD_INITIALIZER(expn);
297
298 expand_aliases_r(al, &expn);
299 mutt_list_free(&expn);
301}
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition address.c:1397
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition list.c:123
#define STAILQ_HEAD_INITIALIZER(head)
Definition queue.h:324
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_expand_aliases_env()

void mutt_expand_aliases_env ( struct Envelope * env)

Expand aliases in all the fields of an Envelope.

Parameters
envEnvelope to expand

Definition at line 307 of file alias.c.

308{
310 mutt_expand_aliases(&env->to);
311 mutt_expand_aliases(&env->cc);
315}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition alias.c:293
struct AddressList to
Email's 'To' list.
Definition envelope.h:60
struct AddressList reply_to
Email's 'reply-to'.
Definition envelope.h:64
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition envelope.h:65
struct AddressList cc
Email's 'Cc' list.
Definition envelope.h:61
struct AddressList bcc
Email's 'Bcc' list.
Definition envelope.h:62
struct AddressList from
Email's 'From' list.
Definition envelope.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_get_address()

struct AddressList * mutt_get_address ( struct Envelope * env,
const char ** prefix )

Get an Address from an Envelope.

Parameters
[in]envEnvelope to examine
[out]prefixPrefix for the Address, e.g. "To:"
Return values
ptrAddressList in the Envelope
Note
The caller must NOT free the returned AddressList

Definition at line 325 of file alias.c.

326{
327 struct AddressList *al = NULL;
328 const char *pfx = NULL;
329
331 {
332 if (!TAILQ_EMPTY(&env->to) && !mutt_is_mail_list(TAILQ_FIRST(&env->to)))
333 {
334 pfx = "To";
335 al = &env->to;
336 }
337 else
338 {
339 pfx = "Cc";
340 al = &env->cc;
341 }
342 }
343 else if (!TAILQ_EMPTY(&env->reply_to) && !mutt_is_mail_list(TAILQ_FIRST(&env->reply_to)))
344 {
345 pfx = "Reply-To";
346 al = &env->reply_to;
347 }
348 else
349 {
350 al = &env->from;
351 pfx = "From";
352 }
353
354 if (prefix)
355 *prefix = pfx;
356
357 return al;
358}
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition alias.c:594
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list?
Definition maillist.c:44
#define TAILQ_EMPTY(head)
Definition queue.h:778
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_create()

void alias_create ( struct AddressList * al,
const struct ConfigSubset * sub )

Create a new Alias from an Address.

Parameters
alAddress to use
subConfig items

Definition at line 365 of file alias.c.

366{
367 struct Buffer *buf = buf_pool_get();
368 struct Buffer *fixed = buf_pool_get();
369 struct Buffer *prompt = NULL;
370 struct Buffer *tmp = buf_pool_get();
371
372 struct Address *addr = NULL;
373 char *pc = NULL;
374 char *err = NULL;
375 FILE *fp_alias = NULL;
376
377 if (al)
378 {
379 addr = TAILQ_FIRST(al);
380 if (addr && addr->mailbox)
381 {
382 buf_copy(tmp, addr->mailbox);
383 pc = strchr(buf_string(tmp), '@');
384 if (pc)
385 *pc = '\0';
386 }
387 }
388
389 /* Don't suggest a bad alias name in the event of a strange local part. */
390 check_alias_name(buf_string(tmp), buf);
391
392retry_name:
393 /* L10N: prompt to add a new alias */
394 if ((mw_get_field(_("Alias as: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
395 buf_is_empty(buf))
396 {
397 goto done;
398 }
399
400 /* check to see if the user already has an alias defined */
401 if (alias_lookup(buf_string(buf)))
402 {
403 mutt_error(_("You already have an alias defined with that name"));
404 goto done;
405 }
406
407 if (check_alias_name(buf_string(buf), fixed))
408 {
409 switch (query_yesorno(_("Warning: This alias name may not work. Fix it?"), MUTT_YES))
410 {
411 case MUTT_YES:
412 buf_copy(buf, fixed);
413 goto retry_name;
414 case MUTT_ABORT:
415 goto done;
416 default:; // do nothing
417 }
418 }
419
420 struct Alias *alias = alias_new();
421 alias->name = buf_strdup(buf);
422
424
425 if (addr && addr->mailbox)
426 buf_copy(buf, addr->mailbox);
427 else
428 buf_reset(buf);
429
430 mutt_addrlist_to_intl(al, NULL);
431
432 do
433 {
434 if ((mw_get_field(_("Address: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
435 buf_is_empty(buf))
436 {
437 alias_free(&alias);
438 goto done;
439 }
440
441 mutt_addrlist_parse(&alias->addr, buf_string(buf));
442 if (TAILQ_EMPTY(&alias->addr))
443 mutt_beep(false);
444 if (mutt_addrlist_to_intl(&alias->addr, &err))
445 {
446 mutt_error(_("Bad IDN: '%s'"), err);
447 FREE(&err);
448 continue;
449 }
450 } while (TAILQ_EMPTY(&alias->addr));
451
452 if (addr && addr->personal && !mutt_is_mail_list(addr))
453 buf_copy(buf, addr->personal);
454 else
455 buf_reset(buf);
456
457 if (mw_get_field(_("Personal name: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
458 {
459 alias_free(&alias);
460 goto done;
461 }
462
463 TAILQ_FIRST(&alias->addr)->personal = buf_new(buf_string(buf));
464
465 buf_reset(buf);
466 if (mw_get_field(_("Comment: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
467 {
468 mutt_str_replace(&alias->comment, buf_string(buf));
469 }
470
471 buf_reset(buf);
472 if (mw_get_field(_("Tags (comma-separated): "), buf, MUTT_COMP_NO_FLAGS,
473 HC_OTHER, NULL, NULL) == 0)
474 {
475 parse_alias_tags(buf_string(buf), &alias->tags);
476 }
477
478 buf_reset(buf);
479 mutt_addrlist_write(&alias->addr, buf, true);
480 prompt = buf_pool_get();
481
482 buf_printf(prompt, "alias %s %s", alias->name, buf_string(buf));
483
484 bool has_tags = STAILQ_FIRST(&alias->tags);
485
486 if (alias->comment || has_tags)
487 buf_addstr(prompt, " #");
488
489 if (alias->comment)
490 buf_add_printf(prompt, " %s", alias->comment);
491
492 if (has_tags)
493 {
494 if (STAILQ_FIRST(&alias->tags))
495 {
496 buf_addstr(prompt, " tags:");
497 alias_tags_to_buffer(&alias->tags, prompt);
498 }
499 }
500
501 buf_add_printf(prompt, "\n%s", _("Accept?"));
502
503 if (query_yesorno(buf_string(prompt), MUTT_YES) != MUTT_YES)
504 {
505 alias_free(&alias);
506 goto done;
507 }
508
509 alias_reverse_add(alias);
510 TAILQ_INSERT_TAIL(&Aliases, alias, entries);
511
512 const char *const c_alias_file = cs_subset_path(sub, "alias_file");
513 buf_strcpy(buf, c_alias_file);
514
515 struct FileCompletionData cdata = { false, NULL, NULL, NULL, NULL };
516 if (mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
517 &CompleteFileOps, &cdata) != 0)
518 {
519 goto done;
520 }
521 buf_expand_path(buf);
522 fp_alias = mutt_file_fopen(buf_string(buf), "a+");
523 if (!fp_alias)
524 {
525 mutt_perror("%s", buf_string(buf));
526 goto done;
527 }
528
529 /* terminate existing file with \n if necessary */
530 if (ftell(fp_alias) > 0)
531 {
532 if (!mutt_file_seek(fp_alias, -1, SEEK_CUR))
533 {
534 goto done;
535 }
536 if (fread(buf->data, 1, 1, fp_alias) != 1)
537 {
538 mutt_perror(_("Error reading alias file"));
539 goto done;
540 }
541 if (!mutt_file_seek(fp_alias, 0, SEEK_END))
542 {
543 goto done;
544 }
545 if (buf_at(buf, 0) != '\n')
546 fputc('\n', fp_alias);
547 }
548
549 if (check_alias_name(alias->name, NULL))
550 buf_quote_filename(buf, alias->name, true);
551 else
552 buf_strcpy(buf, alias->name);
553
554 recode_buf(buf);
555 fprintf(fp_alias, "alias %s ", buf_string(buf));
556 buf_reset(buf);
557
558 mutt_addrlist_write(&alias->addr, buf, false);
559 recode_buf(buf);
560 write_safe_address(fp_alias, buf_string(buf));
561 if (alias->comment)
562 fprintf(fp_alias, " # %s", alias->comment);
563 if (STAILQ_FIRST(&alias->tags))
564 {
565 fprintf(fp_alias, " tags:");
566
567 struct Tag *tag = NULL;
568 STAILQ_FOREACH(tag, &alias->tags, entries)
569 {
570 fprintf(fp_alias, "%s", tag->name);
571 if (STAILQ_NEXT(tag, entries))
572 fprintf(fp_alias, ",");
573 }
574 }
575 fputc('\n', fp_alias);
576 if (mutt_file_fsync_close(&fp_alias) != 0)
577 mutt_perror(_("Trouble adding alias"));
578 else
579 mutt_message(_("Alias added"));
580
581done:
582 mutt_file_fclose(&fp_alias);
583 buf_pool_release(&buf);
584 buf_pool_release(&fixed);
585 buf_pool_release(&prompt);
586 buf_pool_release(&tmp);
587}
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition address.c:1378
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition address.c:1206
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:480
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition address.c:1293
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
void alias_free(struct Alias **ptr)
Free an Alias.
Definition alias.c:667
static int check_alias_name(const char *s, struct Buffer *dest)
Sanity-check an alias name.
Definition alias.c:214
static void recode_buf(struct Buffer *buf)
Convert some text between two character sets.
Definition alias.c:190
struct Alias * alias_new(void)
Create a new Alias.
Definition alias.c:655
static void write_safe_address(FILE *fp, const char *s)
Defang malicious email addresses.
Definition alias.c:86
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition complete.c:152
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:204
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:668
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:226
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition buffer.c:601
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
void mutt_beep(bool force)
Irritate the user.
Definition curs_lib.c:68
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:43
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition wdata.h:44
void buf_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
Definition file.c:811
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:656
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition file.c:132
#define mutt_file_fclose(FP)
Definition file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition file.h:138
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:271
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_perror(...)
Definition logging2.h:95
@ HC_FILE
Files.
Definition lib.h:58
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:60
#define _(a)
Definition message.h:28
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition muttlib.c:314
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
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition quad.h:37
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition quad.h:39
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:326
#define STAILQ_FIRST(head)
Definition queue.h:388
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition queue.h:866
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
void alias_reverse_add(struct Alias *alias)
Add an email address lookup for an Alias.
Definition reverse.c:61
struct TagList tags
Tags.
Definition alias.h:39
char * comment
Free-form comment string.
Definition alias.h:38
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
Input for the file completion function.
Definition curs_lib.h:39
LinkedList Tag Element.
Definition tags.h:42
char * name
Tag name.
Definition tags.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_is_user()

bool mutt_addr_is_user ( const struct Address * addr)

Does the address belong to the user.

Parameters
addrAddress to check
Return values
trueThe given address belongs to the user

Definition at line 594 of file alias.c.

595{
596 if (!addr)
597 {
598 mutt_debug(LL_DEBUG5, "no, NULL address\n");
599 return false;
600 }
601 if (!addr->mailbox)
602 {
603 mutt_debug(LL_DEBUG5, "no, no mailbox\n");
604 return false;
605 }
606
608 {
609 mutt_debug(LL_DEBUG5, "#1 yes, %s = %s\n", buf_string(addr->mailbox),
611 return true;
612 }
614 {
615 mutt_debug(LL_DEBUG5, "#2 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
617 return true;
618 }
619 const char *fqdn = mutt_fqdn(false, NeoMutt->sub);
621 {
622 mutt_debug(LL_DEBUG5, "#3 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
623 NeoMutt->username, NONULL(fqdn));
624 return true;
625 }
626 fqdn = mutt_fqdn(true, NeoMutt->sub);
628 {
629 mutt_debug(LL_DEBUG5, "#4 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
630 NeoMutt->username, NONULL(fqdn));
631 return true;
632 }
633
634 const struct Address *c_from = cs_subset_address(NeoMutt->sub, "from");
635 if (c_from && mutt_istr_equal(buf_string(c_from->mailbox), buf_string(addr->mailbox)))
636 {
637 mutt_debug(LL_DEBUG5, "#5 yes, %s = %s\n", buf_string(addr->mailbox),
638 buf_string(c_from->mailbox));
639 return true;
640 }
641
643 return true;
644
645 mutt_debug(LL_DEBUG5, "no, all failed\n");
646 return false;
647}
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
static bool string_is_address(const char *str, const char *user, const char *domain)
Does an email address match a user and domain?
Definition alias.c:256
bool mutt_alternates_match(const char *addr)
Compare an Address to the Un/Alternates lists.
Definition alternates.c:180
char * ShortHostname
Short version of the hostname.
Definition globals.c:37
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:49
char * username
User's login name.
Definition neomutt.h:142
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_new()

struct Alias * alias_new ( void )

Create a new Alias.

Return values
ptrNewly allocated Alias

Free the result with alias_free()

Definition at line 655 of file alias.c.

656{
657 struct Alias *a = MUTT_MEM_CALLOC(1, struct Alias);
658 TAILQ_INIT(&a->addr);
659 STAILQ_INIT(&a->tags);
660 return a;
661}
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:48
#define STAILQ_INIT(head)
Definition queue.h:410
#define TAILQ_INIT(head)
Definition queue.h:822
+ Here is the caller graph for this function:

◆ alias_free()

void alias_free ( struct Alias ** ptr)

Free an Alias.

Parameters
[out]ptrAlias to free

Definition at line 667 of file alias.c.

668{
669 if (!ptr || !*ptr)
670 return;
671
672 struct Alias *alias = *ptr;
673
674 mutt_debug(LL_NOTIFY, "NT_ALIAS_DELETE: %s\n", alias->name);
675 struct EventAlias ev_a = { alias };
677
678 FREE(&alias->name);
679 FREE(&alias->comment);
682
683 FREE(ptr);
684}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1460
@ NT_ALIAS_DELETE
Alias is about to be deleted.
Definition alias.h:57
void driver_tags_free(struct TagList *tl)
Free tags from a header.
Definition tags.c:131
@ LL_NOTIFY
Log of notifications.
Definition logging2.h:50
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
@ NT_ALIAS
Alias has changed, NotifyAlias, EventAlias.
Definition notify_type.h:37
An alias-change event.
Definition alias.h:66
struct Alias * alias
Alias that changed.
Definition alias.h:67
struct Notify * notify
Notifications handler.
Definition neomutt.h:130
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ aliaslist_clear()

void aliaslist_clear ( struct AliasList * al)

Empty a List of Aliases.

Parameters
alAliasList to empty

Each Alias will be freed and the AliasList will be left empty.

Definition at line 692 of file alias.c.

693{
694 if (!al)
695 return;
696
697 struct Alias *np = NULL, *tmp = NULL;
698 TAILQ_FOREACH_SAFE(np, al, entries, tmp)
699 {
700 TAILQ_REMOVE(al, np, entries);
701 alias_free(&np);
702 }
703 TAILQ_INIT(al);
704}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_init()

void alias_init ( void )

Set up the Alias globals.

Definition at line 709 of file alias.c.

710{
712}
void alias_reverse_init(void)
Set up the Reverse Alias Hash Table.
Definition reverse.c:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_cleanup()

void alias_cleanup ( void )

Clean up the Alias globals.

Definition at line 717 of file alias.c.

718{
719 struct Alias *np = NULL;
720 TAILQ_FOREACH(np, &Aliases, entries)
721 {
723 }
726}
void aliaslist_clear(struct AliasList *al)
Empty a List of Aliases.
Definition alias.c:692
void alias_reverse_shutdown(void)
Clear up the Reverse Alias Hash Table.
Definition reverse.c:52
void alias_reverse_delete(struct Alias *alias)
Remove an email address lookup for an Alias.
Definition reverse.c:83
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ Aliases

struct AliasList Aliases = TAILQ_HEAD_INITIALIZER(Aliases)

List of all the user's email aliases.

Definition at line 60 of file alias.c.