NeoMutt  2025-01-09-81-g753ae0
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 <stddef.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: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:89
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:43
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:661
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user's real name in /etc/passwd.
Definition: muttlib.c:332
#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:707
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:37
char * data
String.
Definition: list.h:38
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ 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: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.
Definition: config_cache.c:116
#define FREE(x)
Definition: memory.h:55
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:64
+ 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: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:98
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:96
+ 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:673
#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: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 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: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 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:596
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: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 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 buf_expand_path(buf);
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 (ftell(fp_alias) > 0)
533 {
534 if (!mutt_file_seek(fp_alias, -1, SEEK_CUR))
535 {
536 goto done;
537 }
538 if (fread(buf->data, 1, 1, fp_alias) != 1)
539 {
540 mutt_perror(_("Error reading alias file"));
541 goto done;
542 }
543 if (!mutt_file_seek(fp_alias, 0, SEEK_END))
544 {
545 goto done;
546 }
547 if (buf->data[0] != '\n')
548 fputc('\n', fp_alias);
549 }
550
551 if (check_alias_name(alias->name, NULL))
552 buf_quote_filename(buf, alias->name, true);
553 else
554 buf_strcpy(buf, alias->name);
555
556 recode_buf(buf);
557 fprintf(fp_alias, "alias %s ", buf_string(buf));
558 buf_reset(buf);
559
560 mutt_addrlist_write(&alias->addr, buf, false);
561 recode_buf(buf);
562 write_safe_address(fp_alias, buf_string(buf));
563 if (alias->comment)
564 fprintf(fp_alias, " # %s", alias->comment);
565 if (STAILQ_FIRST(&alias->tags))
566 {
567 fprintf(fp_alias, " tags:");
568
569 struct Tag *tag = NULL;
570 STAILQ_FOREACH(tag, &alias->tags, entries)
571 {
572 fprintf(fp_alias, "%s", tag->name);
573 if (STAILQ_NEXT(tag, entries))
574 fprintf(fp_alias, ",");
575 }
576 }
577 fputc('\n', fp_alias);
578 if (mutt_file_fsync_close(&fp_alias) != 0)
579 mutt_perror(_("Trouble adding alias"));
580 else
581 mutt_message(_("Alias added"));
582
583done:
584 mutt_file_fclose(&fp_alias);
585 buf_pool_release(&buf);
586 buf_pool_release(&fixed);
587 buf_pool_release(&prompt);
588 buf_pool_release(&tmp);
589}
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:668
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:656
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:153
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
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:69
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:810
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:655
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:131
#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:273
#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:56
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:58
#define _(a)
Definition: message.h:28
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:281
#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
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
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:327
#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: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 596 of file alias.c.

597{
598 if (!addr)
599 {
600 mutt_debug(LL_DEBUG5, "no, NULL address\n");
601 return false;
602 }
603 if (!addr->mailbox)
604 {
605 mutt_debug(LL_DEBUG5, "no, no mailbox\n");
606 return false;
607 }
608
610 {
611 mutt_debug(LL_DEBUG5, "#1 yes, %s = %s\n", buf_string(addr->mailbox), Username);
612 return true;
613 }
615 {
616 mutt_debug(LL_DEBUG5, "#2 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
618 return true;
619 }
620 const char *fqdn = mutt_fqdn(false, NeoMutt->sub);
621 if (string_is_address(buf_string(addr->mailbox), Username, fqdn))
622 {
623 mutt_debug(LL_DEBUG5, "#3 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
624 Username, NONULL(fqdn));
625 return true;
626 }
627 fqdn = mutt_fqdn(true, NeoMutt->sub);
628 if (string_is_address(buf_string(addr->mailbox), Username, fqdn))
629 {
630 mutt_debug(LL_DEBUG5, "#4 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
631 Username, NONULL(fqdn));
632 return true;
633 }
634
635 const struct Address *c_from = cs_subset_address(NeoMutt->sub, "from");
636 if (c_from && mutt_istr_equal(buf_string(c_from->mailbox), buf_string(addr->mailbox)))
637 {
638 mutt_debug(LL_DEBUG5, "#5 yes, %s = %s\n", buf_string(addr->mailbox),
639 buf_string(c_from->mailbox));
640 return true;
641 }
642
644 return true;
645
646 mutt_debug(LL_DEBUG5, "no, all failed\n");
647 return false;
648}
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: config_type.c:286
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:38
char * Username
User's login name.
Definition: globals.c:40
@ 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 656 of file alias.c.

657{
658 struct Alias *a = MUTT_MEM_CALLOC(1, struct Alias);
659 TAILQ_INIT(&a->addr);
660 STAILQ_INIT(&a->tags);
661 return a;
662}
#define MUTT_MEM_CALLOC(n, type)
Definition: memory.h:40
#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 668 of file alias.c.

669{
670 if (!ptr || !*ptr)
671 return;
672
673 struct Alias *alias = *ptr;
674
675 mutt_debug(LL_NOTIFY, "NT_ALIAS_DELETE: %s\n", alias->name);
676 struct EventAlias ev_a = { alias };
678
679 FREE(&alias->name);
680 FREE(&alias->comment);
683
684 FREE(ptr);
685}
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:43
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 693 of file alias.c.

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

711{
713}
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 718 of file alias.c.

719{
720 struct Alias *np = NULL;
721 TAILQ_FOREACH(np, &Aliases, entries)
722 {
724 }
727}
void aliaslist_clear(struct AliasList *al)
Empty a List of Aliases.
Definition: alias.c:693
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.