NeoMutt  2024-04-16-36-g75b6fb
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 <stddef.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 "editor/lib.h"
#include "history/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "alternates.h"
#include "globals.h"
#include "maillist.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 88 of file alias.c.

89{
90 while (*s)
91 {
92 if ((*s == '\\') || (*s == '`') || (*s == '\'') || (*s == '"') || (*s == '$'))
93 fputc('\\', fp);
94 fputc(*s, fp);
95 s++;
96 }
97}
+ 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 106 of file alias.c.

107{
108 struct Address *a = TAILQ_FIRST(al);
109 while (a)
110 {
111 if (!a->group && !a->personal && a->mailbox && !buf_find_char(a->mailbox, '@'))
112 {
113 struct AddressList *alias = alias_lookup(buf_string(a->mailbox));
114 if (alias)
115 {
116 bool duplicate = false;
117 struct ListNode *np = NULL;
118 STAILQ_FOREACH(np, expn, entries)
119 {
120 if (mutt_str_equal(buf_string(a->mailbox), np->data)) /* alias already found */
121 {
122 mutt_debug(LL_DEBUG1, "loop in alias found for '%s'\n", buf_string(a->mailbox));
123 duplicate = true;
124 break;
125 }
126 }
127
128 if (duplicate)
129 {
130 // We've already seen this alias, so drop it
131 struct Address *next = TAILQ_NEXT(a, entries);
132 TAILQ_REMOVE(al, a, entries);
133 mutt_addr_free(&a);
134 a = next;
135 continue;
136 }
137
138 // Keep a list of aliases that we've already seen
140
141 /* The alias may expand to several addresses,
142 * some of which may themselves be aliases.
143 * Create a copy and recursively expand any aliases within. */
144 struct AddressList copy = TAILQ_HEAD_INITIALIZER(copy);
145 mutt_addrlist_copy(&copy, alias, false);
146 expand_aliases_r(&copy, expn);
147
148 /* Next, move the expanded addresses
149 * from the copy into the original list (before the alias) */
150 struct Address *a2 = NULL, *tmp = NULL;
151 TAILQ_FOREACH_SAFE(a2, &copy, entries, tmp)
152 {
153 TAILQ_INSERT_BEFORE(a, a2, entries);
154 }
155 a = TAILQ_PREV(a, AddressList, entries);
156 // Finally, remove the alias itself
157 struct Address *next = TAILQ_NEXT(a, entries);
158 TAILQ_REMOVE(al, next, entries);
159 mutt_addr_free(&next);
160 }
161 else
162 {
163 struct passwd *pw = getpwnam(buf_string(a->mailbox));
164 if (pw)
165 {
166 char namebuf[256] = { 0 };
167
168 mutt_gecos_name(namebuf, sizeof(namebuf), pw);
169 a->personal = buf_new(namebuf);
170 }
171 }
172 }
173 a = TAILQ_NEXT(a, entries);
174 }
175
176 const char *fqdn = NULL;
177 const bool c_use_domain = cs_subset_bool(NeoMutt->sub, "use_domain");
178 if (c_use_domain && (fqdn = mutt_fqdn(true, NeoMutt->sub)))
179 {
180 /* now qualify all local addresses */
181 mutt_addrlist_qualify(al, fqdn);
182 }
183}
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:277
static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
Expand aliases, recursively.
Definition: alias.c:106
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:303
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:654
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:570
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:48
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:654
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user's real name in /etc/passwd.
Definition: muttlib.c:367
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
#define TAILQ_PREV(elm, headname, field)
Definition: queue.h:834
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_INSERT_BEFORE(listelm, elm, field)
Definition: queue.h:786
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:36
struct Buffer * personal
Real name of address.
Definition: address.h:37
bool group
Group mailbox?
Definition: address.h:39
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ 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 192 of file alias.c.

193{
194 const char *const c_config_charset = cs_subset_string(NeoMutt->sub, "config_charset");
195 if (!c_config_charset || !cc_charset())
196 return;
197
198 char *s = buf_strdup(buf);
199 if (!s)
200 return;
201 if (mutt_ch_convert_string(&s, cc_charset(), c_config_charset, MUTT_ICONV_NO_FLAGS) == 0)
202 buf_strcpy(buf, s);
203 FREE(&s);
204}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:394
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
#define FREE(x)
Definition: memory.h:45
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:831
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:72
+ 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 216 of file alias.c.

217{
218 wchar_t wc = 0;
219 mbstate_t mbstate = { 0 };
220 size_t l;
221 int rc = 0;
222 bool dry = !dest; // Dry run
223
224 if (!dry)
225 buf_reset(dest);
226 for (; s && *s && (l = mbrtowc(&wc, s, MB_CUR_MAX, &mbstate)) != 0; s += l)
227 {
228 bool bad = (l == ICONV_ILLEGAL_SEQ) || (l == ICONV_BUF_TOO_SMALL); /* conversion error */
229 if (l == 1)
230 bad = bad || (!strchr("-_+=.", *s) && !iswalnum(wc));
231 else
232 bad = bad || !iswalnum(wc);
233 if (bad)
234 {
235 if (dry)
236 return -1;
237 if (l == ICONV_ILLEGAL_SEQ)
238 memset(&mbstate, 0, sizeof(mbstate_t));
239 buf_addch(dest, '_');
240 rc = -1;
241 }
242 else if (!dry)
243 {
244 buf_addstr_n(dest, s, l);
245 }
246 }
247
248 return rc;
249}
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:95
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:75
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition: charset.h:106
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:104
+ 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 258 of file alias.c.

259{
260 char buf[1024] = { 0 };
261
262 snprintf(buf, sizeof(buf), "%s@%s", NONULL(user), NONULL(domain));
263 if (mutt_istr_equal(str, buf))
264 return true;
265
266 return false;
267}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:666
#define NONULL(x)
Definition: string2.h:37
+ 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 277 of file alias.c.

278{
279 struct Alias *a = NULL;
280
281 TAILQ_FOREACH(a, &Aliases, entries)
282 {
283 if (mutt_istr_equal(name, a->name))
284 return &a->addr;
285 }
286 return NULL;
287}
struct AliasList Aliases
List of all the user's email aliases.
Definition: alias.c:62
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
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 295 of file alias.c.

296{
297 // previously expanded aliases to avoid loops
298 struct ListHead expn = STAILQ_HEAD_INITIALIZER(expn);
299
300 expand_aliases_r(al, &expn);
301 mutt_list_free(&expn);
303}
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:122
#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 309 of file alias.c.

310{
312 mutt_expand_aliases(&env->to);
313 mutt_expand_aliases(&env->cc);
317}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:295
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 327 of file alias.c.

328{
329 struct AddressList *al = NULL;
330 const char *pfx = NULL;
331
333 {
334 if (!TAILQ_EMPTY(&env->to) && !mutt_is_mail_list(TAILQ_FIRST(&env->to)))
335 {
336 pfx = "To";
337 al = &env->to;
338 }
339 else
340 {
341 pfx = "Cc";
342 al = &env->cc;
343 }
344 }
345 else if (!TAILQ_EMPTY(&env->reply_to) && !mutt_is_mail_list(TAILQ_FIRST(&env->reply_to)))
346 {
347 pfx = "Reply-To";
348 al = &env->reply_to;
349 }
350 else
351 {
352 al = &env->from;
353 pfx = "From";
354 }
355
356 if (prefix)
357 *prefix = pfx;
358
359 return al;
360}
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:600
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t -.
Definition: maillist.c:45
#define TAILQ_EMPTY(head)
Definition: queue.h:721
+ 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 367 of file alias.c.

368{
369 struct Buffer *buf = buf_pool_get();
370 struct Buffer *fixed = buf_pool_get();
371 struct Buffer *prompt = NULL;
372 struct Buffer *tmp = buf_pool_get();
373
374 struct Address *addr = NULL;
375 char *pc = NULL;
376 char *err = NULL;
377 FILE *fp_alias = NULL;
378
379 if (al)
380 {
381 addr = TAILQ_FIRST(al);
382 if (addr && addr->mailbox)
383 {
384 buf_copy(tmp, addr->mailbox);
385 pc = strchr(buf_string(tmp), '@');
386 if (pc)
387 *pc = '\0';
388 }
389 }
390
391 /* Don't suggest a bad alias name in the event of a strange local part. */
392 check_alias_name(buf_string(tmp), buf);
393
394retry_name:
395 /* L10N: prompt to add a new alias */
396 if ((mw_get_field(_("Alias as: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
397 buf_is_empty(buf))
398 {
399 goto done;
400 }
401
402 /* check to see if the user already has an alias defined */
403 if (alias_lookup(buf_string(buf)))
404 {
405 mutt_error(_("You already have an alias defined with that name"));
406 goto done;
407 }
408
409 if (check_alias_name(buf_string(buf), fixed))
410 {
411 switch (query_yesorno(_("Warning: This alias name may not work. Fix it?"), MUTT_YES))
412 {
413 case MUTT_YES:
414 buf_copy(buf, fixed);
415 goto retry_name;
416 case MUTT_ABORT:
417 goto done;
418 default:; // do nothing
419 }
420 }
421
422 struct Alias *alias = alias_new();
423 alias->name = buf_strdup(buf);
424
426
427 if (addr && addr->mailbox)
428 buf_copy(buf, addr->mailbox);
429 else
430 buf_reset(buf);
431
432 mutt_addrlist_to_intl(al, NULL);
433
434 do
435 {
436 if ((mw_get_field(_("Address: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
437 buf_is_empty(buf))
438 {
439 alias_free(&alias);
440 goto done;
441 }
442
443 mutt_addrlist_parse(&alias->addr, buf_string(buf));
444 if (TAILQ_EMPTY(&alias->addr))
445 mutt_beep(false);
446 if (mutt_addrlist_to_intl(&alias->addr, &err))
447 {
448 mutt_error(_("Bad IDN: '%s'"), err);
449 FREE(&err);
450 continue;
451 }
452 } while (TAILQ_EMPTY(&alias->addr));
453
454 if (addr && addr->personal && !mutt_is_mail_list(addr))
455 buf_copy(buf, addr->personal);
456 else
457 buf_reset(buf);
458
459 if (mw_get_field(_("Personal name: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
460 {
461 alias_free(&alias);
462 goto done;
463 }
464
465 TAILQ_FIRST(&alias->addr)->personal = buf_new(buf_string(buf));
466
467 buf_reset(buf);
468 if (mw_get_field(_("Comment: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
469 {
470 mutt_str_replace(&alias->comment, buf_string(buf));
471 }
472
473 buf_reset(buf);
474 if (mw_get_field(_("Tags (comma-separated): "), buf, MUTT_COMP_NO_FLAGS,
475 HC_OTHER, NULL, NULL) == 0)
476 {
477 parse_alias_tags(buf_string(buf), &alias->tags);
478 }
479
480 buf_reset(buf);
481 mutt_addrlist_write(&alias->addr, buf, true);
482 prompt = buf_pool_get();
483
484 buf_printf(prompt, "alias %s %s", alias->name, buf_string(buf));
485
486 bool has_tags = STAILQ_FIRST(&alias->tags);
487
488 if (alias->comment || has_tags)
489 buf_addstr(prompt, " #");
490
491 if (alias->comment)
492 buf_add_printf(prompt, " %s", alias->comment);
493
494 if (has_tags)
495 {
496 if (STAILQ_FIRST(&alias->tags))
497 {
498 buf_addstr(prompt, " tags:");
499 alias_tags_to_buffer(&alias->tags, prompt);
500 }
501 }
502
503 buf_add_printf(prompt, "\n%s", _("Accept?"));
504
505 if (query_yesorno(buf_string(prompt), MUTT_YES) != MUTT_YES)
506 {
507 alias_free(&alias);
508 goto done;
509 }
510
511 alias_reverse_add(alias);
512 TAILQ_INSERT_TAIL(&Aliases, alias, entries);
513
514 const char *const c_alias_file = cs_subset_path(sub, "alias_file");
515 buf_strcpy(buf, c_alias_file);
516
517 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
518 if (mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
519 &CompleteFileOps, &cdata) != 0)
520 {
521 goto done;
522 }
523 mutt_expand_path(buf->data, buf->dsize);
524 fp_alias = mutt_file_fopen(buf_string(buf), "a+");
525 if (!fp_alias)
526 {
527 mutt_perror("%s", buf_string(buf));
528 goto done;
529 }
530
531 /* terminate existing file with \n if necessary */
532 if (!mutt_file_seek(fp_alias, 0, SEEK_END))
533 {
534 goto done;
535 }
536 if (ftell(fp_alias) > 0)
537 {
538 if (!mutt_file_seek(fp_alias, -1, SEEK_CUR))
539 {
540 goto done;
541 }
542 if (fread(buf->data, 1, 1, fp_alias) != 1)
543 {
544 mutt_perror(_("Error reading alias file"));
545 goto done;
546 }
547 if (!mutt_file_seek(fp_alias, 0, SEEK_END))
548 {
549 goto done;
550 }
551 if (buf->data[0] != '\n')
552 fputc('\n', fp_alias);
553 }
554
555 if (check_alias_name(alias->name, NULL))
556 buf_quote_filename(buf, alias->name, true);
557 else
558 buf_strcpy(buf, alias->name);
559
560 recode_buf(buf);
561 fprintf(fp_alias, "alias %s ", buf_string(buf));
562 buf_reset(buf);
563
564 mutt_addrlist_write(&alias->addr, buf, false);
565 recode_buf(buf);
566 write_safe_address(fp_alias, buf_string(buf));
567 if (alias->comment)
568 fprintf(fp_alias, " # %s", alias->comment);
569 if (STAILQ_FIRST(&alias->tags))
570 {
571 fprintf(fp_alias, " tags:");
572
573 struct Tag *tag = NULL;
574 STAILQ_FOREACH(tag, &alias->tags, entries)
575 {
576 fprintf(fp_alias, "%s", tag->name);
577 if (STAILQ_NEXT(tag, entries))
578 fprintf(fp_alias, ",");
579 }
580 }
581 fputc('\n', fp_alias);
582 if (mutt_file_fsync_close(&fp_alias) != 0)
583 mutt_perror(_("Trouble adding alias"));
584 else
585 mutt_message(_("Alias added"));
586
587done:
588 mutt_file_fclose(&fp_alias);
589 buf_pool_release(&buf);
590 buf_pool_release(&fixed);
591 buf_pool_release(&prompt);
592 buf_pool_release(&tmp);
593}
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: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
static int check_alias_name(const char *s, struct Buffer *dest)
Sanity-check an alias name.
Definition: alias.c:216
static void recode_buf(struct Buffer *buf)
Convert some text between two character sets.
Definition: alias.c:192
struct Alias * alias_new(void)
Create a new Alias.
Definition: alias.c:660
static void write_safe_address(FILE *fp, const char *s)
Defang malicious email addresses.
Definition: alias.c:88
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:155
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:290
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:600
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:169
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:68
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:930
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:775
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:192
#define mutt_file_fclose(FP)
Definition: file.h:147
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:146
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:274
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_perror(...)
Definition: logging2.h:93
@ HC_FILE
Files.
Definition: lib.h:54
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:56
#define _(a)
Definition: message.h:28
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:274
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:57
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:123
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
@ 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:327
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
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
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
Input for the file completion function.
Definition: curs_lib.h:40
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 600 of file alias.c.

601{
602 if (!addr)
603 {
604 mutt_debug(LL_DEBUG5, "no, NULL address\n");
605 return false;
606 }
607 if (!addr->mailbox)
608 {
609 mutt_debug(LL_DEBUG5, "no, no mailbox\n");
610 return false;
611 }
612
614 {
615 mutt_debug(LL_DEBUG5, "#1 yes, %s = %s\n", buf_string(addr->mailbox), Username);
616 return true;
617 }
619 {
620 mutt_debug(LL_DEBUG5, "#2 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
622 return true;
623 }
624 const char *fqdn = mutt_fqdn(false, NeoMutt->sub);
625 if (string_is_address(buf_string(addr->mailbox), Username, fqdn))
626 {
627 mutt_debug(LL_DEBUG5, "#3 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
628 Username, NONULL(fqdn));
629 return true;
630 }
631 fqdn = mutt_fqdn(true, NeoMutt->sub);
632 if (string_is_address(buf_string(addr->mailbox), Username, fqdn))
633 {
634 mutt_debug(LL_DEBUG5, "#4 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
635 Username, NONULL(fqdn));
636 return true;
637 }
638
639 const struct Address *c_from = cs_subset_address(NeoMutt->sub, "from");
640 if (c_from && mutt_istr_equal(buf_string(c_from->mailbox), buf_string(addr->mailbox)))
641 {
642 mutt_debug(LL_DEBUG5, "#5 yes, %s = %s\n", buf_string(addr->mailbox),
643 buf_string(c_from->mailbox));
644 return true;
645 }
646
648 return true;
649
650 mutt_debug(LL_DEBUG5, "no, all failed\n");
651 return false;
652}
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: config_type.c:273
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:258
bool mutt_alternates_match(const char *addr)
Compare an Address to the Un/Alternates lists.
Definition: alternates.c:155
char * ShortHostname
Short version of the hostname.
Definition: globals.c:39
char * Username
User's login name.
Definition: globals.c:41
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
+ 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 660 of file alias.c.

661{
662 struct Alias *a = mutt_mem_calloc(1, sizeof(struct Alias));
663 TAILQ_INIT(&a->addr);
664 STAILQ_INIT(&a->tags);
665 return a;
666}
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define STAILQ_INIT(head)
Definition: queue.h:372
#define TAILQ_INIT(head)
Definition: queue.h:765
+ Here is the call graph for this function:
+ 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 672 of file alias.c.

673{
674 if (!ptr || !*ptr)
675 return;
676
677 struct Alias *alias = *ptr;
678
679 mutt_debug(LL_NOTIFY, "NT_ALIAS_DELETE: %s\n", alias->name);
680 struct EventAlias ev_a = { alias };
682
683 FREE(&alias->name);
684 FREE(&alias->comment);
687
688 FREE(ptr);
689}
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
@ LL_NOTIFY
Log of notifications.
Definition: logging2.h:48
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:42
void driver_tags_free(struct TagList *tl)
Free tags from a header.
Definition: tags.c:131
+ 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 697 of file alias.c.

698{
699 if (!al)
700 return;
701
702 struct Alias *np = NULL, *tmp = NULL;
703 TAILQ_FOREACH_SAFE(np, al, entries, tmp)
704 {
705 TAILQ_REMOVE(al, np, entries);
706 alias_free(&np);
707 }
708 TAILQ_INIT(al);
709}
+ 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 714 of file alias.c.

715{
717}
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 722 of file alias.c.

723{
724 struct Alias *np = NULL;
725 TAILQ_FOREACH(np, &Aliases, entries)
726 {
728 }
731}
void aliaslist_clear(struct AliasList *al)
Empty a List of Aliases.
Definition: alias.c:697
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 62 of file alias.c.