NeoMutt  2022-04-29-145-g9b6a0e
Teaching an old dog new tricks
DOXYGEN
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 "enter/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "alternates.h"
#include "maillist.h"
#include "mutt_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. More...
 
static void expand_aliases_r (struct AddressList *al, struct ListHead *expn)
 Expand aliases, recursively. More...
 
static void recode_buf (char *buf, size_t buflen)
 Convert some text between two character sets. More...
 
static int check_alias_name (const char *s, char *dest, size_t destlen)
 Sanity-check an alias name. More...
 
static bool string_is_address (const char *str, const char *user, const char *domain)
 Does an email address match a user and domain? More...
 
struct AddressList * alias_lookup (const char *name)
 Find an Alias. More...
 
void mutt_expand_aliases (struct AddressList *al)
 Expand aliases in a List of Addresses. More...
 
void mutt_expand_aliases_env (struct Envelope *env)
 Expand aliases in all the fields of an Envelope. More...
 
struct AddressList * mutt_get_address (struct Envelope *env, const char **prefix)
 Get an Address from an Envelope. More...
 
void alias_create (struct AddressList *al, const struct ConfigSubset *sub)
 Create a new Alias from an Address. More...
 
bool mutt_addr_is_user (const struct Address *addr)
 Does the address belong to the user. More...
 
struct Aliasalias_new (void)
 Create a new Alias. More...
 
void alias_free (struct Alias **ptr)
 Free an Alias. More...
 
void aliaslist_free (struct AliasList *al)
 Free a List of Aliases. More...
 
void alias_init (void)
 Set up the Alias globals. More...
 
void alias_shutdown (void)
 Clean up the Alias globals. More...
 

Variables

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

Detailed Description

Representation of a single alias to an email address.

Authors
  • Michael R. Elkins
  • Pietro Cerutti
  • Richard Russon

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: Michael /bin/rm -f ~ Elkins me@mu.nosp@m.tt.o.nosp@m.rg and the user creates an alias for this, NeoMutt could wind up executing the backticks because it writes aliases like alias me Michael /bin/rm -f ~ Elkins me@mu.nosp@m.tt.o.nosp@m.rg 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: Michael `/bin/rm -f ~` Elkins me@mu.nosp@m.tt.o.nosp@m.rg since that would get aliased as alias me Michael \`/bin/rm -f ~\` Elkins me@mu.nosp@m.tt.o.nosp@m.rg 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 84 of file alias.c.

85 {
86  while (*s)
87  {
88  if ((*s == '\\') || (*s == '`') || (*s == '\'') || (*s == '"') || (*s == '$'))
89  fputc('\\', fp);
90  fputc(*s, fp);
91  s++;
92  }
93 }
+ 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 102 of file alias.c.

103 {
104  struct Address *a = TAILQ_FIRST(al);
105  while (a)
106  {
107  if (!a->group && !a->personal && a->mailbox && !strchr(a->mailbox, '@'))
108  {
109  struct AddressList *alias = alias_lookup(a->mailbox);
110  if (alias)
111  {
112  bool duplicate = false;
113  struct ListNode *np = NULL;
114  STAILQ_FOREACH(np, expn, entries)
115  {
116  if (mutt_str_equal(a->mailbox, np->data)) /* alias already found */
117  {
118  mutt_debug(LL_DEBUG1, "loop in alias found for '%s'\n", a->mailbox);
119  duplicate = true;
120  break;
121  }
122  }
123 
124  if (duplicate)
125  {
126  // We've already seen this alias, so drop it
127  struct Address *next = TAILQ_NEXT(a, entries);
128  TAILQ_REMOVE(al, a, entries);
129  mutt_addr_free(&a);
130  a = next;
131  continue;
132  }
133 
134  // Keep a list of aliases that we've already seen
136 
137  /* The alias may expand to several addresses,
138  * some of which may themselves be aliases.
139  * Create a copy and recursively expand any aliases within. */
140  struct AddressList copy = TAILQ_HEAD_INITIALIZER(copy);
141  mutt_addrlist_copy(&copy, alias, false);
142  expand_aliases_r(&copy, expn);
143 
144  /* Next, move the expanded addresses
145  * from the copy into the original list (before the alias) */
146  struct Address *a2 = NULL, *tmp = NULL;
147  TAILQ_FOREACH_SAFE(a2, &copy, entries, tmp)
148  {
149  TAILQ_INSERT_BEFORE(a, a2, entries);
150  }
151  a = TAILQ_PREV(a, AddressList, entries);
152  // Finally, remove the alias itself
153  struct Address *next = TAILQ_NEXT(a, entries);
154  TAILQ_REMOVE(al, next, entries);
155  mutt_addr_free(&next);
156  }
157  else
158  {
159  struct passwd *pw = getpwnam(a->mailbox);
160  if (pw)
161  {
162  char namebuf[256];
163 
164  mutt_gecos_name(namebuf, sizeof(namebuf), pw);
165  mutt_str_replace(&a->personal, namebuf);
166  }
167  }
168  }
169  a = TAILQ_NEXT(a, entries);
170  }
171 
172  const char *fqdn = NULL;
173  const bool c_use_domain = cs_subset_bool(NeoMutt->sub, "use_domain");
174  if (c_use_domain && (fqdn = mutt_fqdn(true, NeoMutt->sub)))
175  {
176  /* now qualify all local addresses */
177  mutt_addrlist_qualify(al, fqdn);
178  }
179 }
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:650
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:280
static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
Expand aliases, recursively.
Definition: alias.c:102
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
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: logging.h:40
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user's real name in /etc/passwd.
Definition: muttlib.c:361
#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:698
An email address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:39
char * mailbox
Mailbox and host address.
Definition: address.h:38
char * personal
Real name of address.
Definition: address.h:37
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ recode_buf()

static void recode_buf ( char *  buf,
size_t  buflen 
)
static

Convert some text between two character sets.

Parameters
bufBuffer to convert
buflenLength of buffer

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

Definition at line 189 of file alias.c.

190 {
191  const char *const c_config_charset = cs_subset_string(NeoMutt->sub, "config_charset");
192  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
193  if (!c_config_charset || !c_charset)
194  return;
195 
196  char *s = mutt_str_dup(buf);
197  if (!s)
198  return;
199  if (mutt_ch_convert_string(&s, c_charset, c_config_charset, MUTT_ICONV_NO_FLAGS) == 0)
200  mutt_str_copy(buf, s, buflen);
201  FREE(&s);
202 }
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
#define FREE(x)
Definition: memory.h:43
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:752
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:629
+ 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,
char *  dest,
size_t  destlen 
)
static

Sanity-check an alias name.

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

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

Definition at line 215 of file alias.c.

216 {
217  wchar_t wc = 0;
218  mbstate_t mbstate = { 0 };
219  size_t l;
220  int rc = 0;
221  bool dry = !dest || !destlen;
222 
223  if (!dry)
224  destlen--;
225  for (; s && *s && (dry || destlen) && (l = mbrtowc(&wc, s, MB_CUR_MAX, &mbstate)) != 0;
226  s += l, destlen -= l)
227  {
228  bool bad = (l == (size_t) (-1)) || (l == (size_t) (-2)); /* conversion error */
229  bad = bad || (!dry && l > destlen); /* too few room for mb char */
230  if (l == 1)
231  bad = bad || (!strchr("-_+=.", *s) && !iswalnum(wc));
232  else
233  bad = bad || !iswalnum(wc);
234  if (bad)
235  {
236  if (dry)
237  return -1;
238  if (l == (size_t) (-1))
239  memset(&mbstate, 0, sizeof(mbstate_t));
240  *dest++ = '_';
241  rc = -1;
242  }
243  else if (!dry)
244  {
245  memcpy(dest, s, l);
246  dest += l;
247  }
248  }
249  if (!dry)
250  *dest = '\0';
251  return rc;
252 }
+ 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 261 of file alias.c.

262 {
263  char buf[1024];
264 
265  snprintf(buf, sizeof(buf), "%s@%s", NONULL(user), NONULL(domain));
266  if (mutt_istr_equal(str, buf))
267  return true;
268 
269  return false;
270 }
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
#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 280 of file alias.c.

281 {
282  struct Alias *a = NULL;
283 
284  TAILQ_FOREACH(a, &Aliases, entries)
285  {
286  if (mutt_istr_equal(name, a->name))
287  return &a->addr;
288  }
289  return NULL;
290 }
struct AliasList Aliases
List of all the user's email aliases.
Definition: alias.c:58
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
A shortcut for an email address or addresses.
Definition: alias.h:34
char * name
Short name.
Definition: alias.h:35
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:36
+ 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 298 of file alias.c.

299 {
300  struct ListHead expn; /* previously expanded aliases to avoid loops */
301 
302  STAILQ_INIT(&expn);
303  expand_aliases_r(al, &expn);
304  mutt_list_free(&expn);
306 }
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1407
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
#define STAILQ_INIT(head)
Definition: queue.h:372
+ 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 312 of file alias.c.

313 {
314  mutt_expand_aliases(&env->from);
315  mutt_expand_aliases(&env->to);
316  mutt_expand_aliases(&env->cc);
317  mutt_expand_aliases(&env->bcc);
320 }
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:298
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 330 of file alias.c.

331 {
332  struct AddressList *al = NULL;
333  const char *pfx = NULL;
334 
335  if (mutt_addr_is_user(TAILQ_FIRST(&env->from)))
336  {
337  if (!TAILQ_EMPTY(&env->to) && !mutt_is_mail_list(TAILQ_FIRST(&env->to)))
338  {
339  pfx = "To";
340  al = &env->to;
341  }
342  else
343  {
344  pfx = "Cc";
345  al = &env->cc;
346  }
347  }
348  else if (!TAILQ_EMPTY(&env->reply_to) && !mutt_is_mail_list(TAILQ_FIRST(&env->reply_to)))
349  {
350  pfx = "Reply-To";
351  al = &env->reply_to;
352  }
353  else
354  {
355  al = &env->from;
356  pfx = "From";
357  }
358 
359  if (prefix)
360  *prefix = pfx;
361 
362  return al;
363 }
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:574
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: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 370 of file alias.c.

371 {
372  struct Buffer *buf = mutt_buffer_pool_get();
373  struct Buffer *fixed = mutt_buffer_pool_get();
374  struct Buffer *prompt = NULL;
375  struct Buffer *tmp = mutt_buffer_pool_get();
376 
377  struct Address *addr = NULL;
378  char *pc = NULL;
379  char *err = NULL;
380  FILE *fp_alias = NULL;
381 
382  if (al)
383  {
384  addr = TAILQ_FIRST(al);
385  if (addr && addr->mailbox)
386  {
387  mutt_buffer_strcpy(tmp, addr->mailbox);
388  pc = strchr(mutt_buffer_string(tmp), '@');
389  if (pc)
390  *pc = '\0';
391  }
392  }
393 
394  /* Don't suggest a bad alias name in the event of a strange local part. */
395  check_alias_name(mutt_buffer_string(tmp), buf->data, buf->dsize);
396 
397 retry_name:
398  /* L10N: prompt to add a new alias */
399  if ((mutt_buffer_get_field(_("Alias as: "), buf, MUTT_COMP_NO_FLAGS, false,
400  NULL, NULL, NULL) != 0) ||
402  {
403  goto done;
404  }
405 
406  /* check to see if the user already has an alias defined */
408  {
409  mutt_error(_("You already have an alias defined with that name"));
410  goto done;
411  }
412 
413  if (check_alias_name(mutt_buffer_string(buf), fixed->data, fixed->dsize))
414  {
415  switch (mutt_yesorno(_("Warning: This alias name may not work. Fix it?"), MUTT_YES))
416  {
417  case MUTT_YES:
418  mutt_buffer_copy(buf, fixed);
419  goto retry_name;
420  case MUTT_ABORT:
421  goto done;
422  default:; // do nothing
423  }
424  }
425 
426  struct Alias *alias = alias_new();
427  alias->name = mutt_buffer_strdup(buf);
428 
430 
431  if (addr && addr->mailbox)
432  mutt_buffer_strcpy(buf, addr->mailbox);
433  else
434  mutt_buffer_reset(buf);
435 
436  mutt_addrlist_to_intl(al, NULL);
437 
438  do
439  {
440  if ((mutt_buffer_get_field(_("Address: "), buf, MUTT_COMP_NO_FLAGS, false,
441  NULL, NULL, NULL) != 0) ||
443  {
444  alias_free(&alias);
445  goto done;
446  }
447 
449  if (TAILQ_EMPTY(&alias->addr))
450  mutt_beep(false);
451  if (mutt_addrlist_to_intl(&alias->addr, &err))
452  {
453  mutt_error(_("Bad IDN: '%s'"), err);
454  FREE(&err);
455  continue;
456  }
457  } while (TAILQ_EMPTY(&alias->addr));
458 
459  if (addr && addr->personal && !mutt_is_mail_list(addr))
460  mutt_buffer_strcpy(buf, addr->personal);
461  else
462  mutt_buffer_reset(buf);
463 
464  if (mutt_buffer_get_field(_("Personal name: "), buf, MUTT_COMP_NO_FLAGS,
465  false, NULL, NULL, NULL) != 0)
466  {
467  alias_free(&alias);
468  goto done;
469  }
470  mutt_str_replace(&TAILQ_FIRST(&alias->addr)->personal, mutt_buffer_string(buf));
471 
472  mutt_buffer_reset(buf);
473  if (mutt_buffer_get_field(_("Comment: "), buf, MUTT_COMP_NO_FLAGS, false,
474  NULL, NULL, NULL) == 0)
475  {
477  }
478 
479  mutt_buffer_reset(buf);
480  mutt_addrlist_write(&alias->addr, buf->data, buf->dsize, true);
481  prompt = mutt_buffer_pool_get();
482  if (alias->comment)
483  {
484  mutt_buffer_printf(prompt, "[%s = %s # %s] %s", alias->name,
485  mutt_buffer_string(buf), alias->comment, _("Accept?"));
486  }
487  else
488  {
489  mutt_buffer_printf(prompt, "[%s = %s] %s", alias->name,
490  mutt_buffer_string(buf), _("Accept?"));
491  }
493  {
494  alias_free(&alias);
495  goto done;
496  }
497 
498  alias_reverse_add(alias);
499  TAILQ_INSERT_TAIL(&Aliases, alias, entries);
500 
501  const char *const alias_file = cs_subset_path(sub, "alias_file");
502  mutt_buffer_strcpy(buf, alias_file);
503 
504  if (mutt_buffer_get_field(_("Save to file: "), buf, MUTT_COMP_FILE | MUTT_COMP_CLEAR,
505  false, NULL, NULL, NULL) != 0)
506  {
507  goto done;
508  }
509  mutt_expand_path(buf->data, buf->dsize);
510  fp_alias = fopen(mutt_buffer_string(buf), "a+");
511  if (!fp_alias)
512  {
514  goto done;
515  }
516 
517  /* terminate existing file with \n if necessary */
518  if (!mutt_file_seek(fp_alias, 0, SEEK_END))
519  {
520  goto done;
521  }
522  if (ftell(fp_alias) > 0)
523  {
524  if (!mutt_file_seek(fp_alias, -1, SEEK_CUR))
525  {
526  goto done;
527  }
528  if (fread(buf->data, 1, 1, fp_alias) != 1)
529  {
530  mutt_perror(_("Error reading alias file"));
531  goto done;
532  }
533  if (!mutt_file_seek(fp_alias, 0, SEEK_END))
534  {
535  goto done;
536  }
537  if (buf->data[0] != '\n')
538  fputc('\n', fp_alias);
539  }
540 
541  if (check_alias_name(alias->name, NULL, 0))
542  mutt_file_quote_filename(alias->name, buf->data, buf->dsize);
543  else
544  mutt_buffer_strcpy(buf, alias->name);
545 
546  recode_buf(buf->data, buf->dsize);
547  fprintf(fp_alias, "alias %s ", mutt_buffer_string(buf));
548  mutt_buffer_reset(buf);
549 
550  mutt_addrlist_write(&alias->addr, buf->data, buf->dsize, false);
551  recode_buf(buf->data, buf->dsize);
552  write_safe_address(fp_alias, mutt_buffer_string(buf));
553  if (alias->comment)
554  fprintf(fp_alias, " # %s", alias->comment);
555  fputc('\n', fp_alias);
556  if (mutt_file_fsync_close(&fp_alias) != 0)
557  mutt_perror(_("Trouble adding alias"));
558  else
559  mutt_message(_("Alias added"));
560 
561 done:
562  mutt_file_fclose(&fp_alias);
564  mutt_buffer_pool_release(&fixed);
565  mutt_buffer_pool_release(&prompt);
567 }
size_t mutt_addrlist_write(const struct AddressList *al, char *buf, size_t buflen, bool display)
Write an Address to a buffer.
Definition: address.c:1150
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1388
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1305
void alias_free(struct Alias **ptr)
Free an Alias.
Definition: alias.c:641
static int check_alias_name(const char *s, char *dest, size_t destlen)
Sanity-check an alias name.
Definition: alias.c:215
struct Alias * alias_new(void)
Create a new Alias.
Definition: alias.c:630
static void recode_buf(char *buf, size_t buflen)
Convert some text between two character sets.
Definition: alias.c:189
static void write_safe_address(FILE *fp, const char *s)
Defang malicious email addresses.
Definition: alias.c:84
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:250
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:430
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:158
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:445
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:81
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:130
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
size_t mutt_file_quote_filename(const char *filename, char *buf, size_t buflen)
Quote a filename to survive the shell's quoting rules.
Definition: file.c:848
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:690
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_perror(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
#define MUTT_COMP_FILE
File completion (in browser)
Definition: mutt.h:55
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:123
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
@ 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 mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
void alias_reverse_add(struct Alias *alias)
Add an email address lookup for an Alias.
Definition: reverse.c:61
char * comment
Free-form comment string.
Definition: alias.h:37
String manipulation buffer.
Definition: buffer.h:34
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
+ 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 574 of file alias.c.

575 {
576  if (!addr)
577  {
578  mutt_debug(LL_DEBUG5, "no, NULL address\n");
579  return false;
580  }
581  if (!addr->mailbox)
582  {
583  mutt_debug(LL_DEBUG5, "no, no mailbox\n");
584  return false;
585  }
586 
587  if (mutt_istr_equal(addr->mailbox, Username))
588  {
589  mutt_debug(LL_DEBUG5, "#1 yes, %s = %s\n", addr->mailbox, Username);
590  return true;
591  }
593  {
594  mutt_debug(LL_DEBUG5, "#2 yes, %s = %s @ %s\n", addr->mailbox, Username, ShortHostname);
595  return true;
596  }
597  const char *fqdn = mutt_fqdn(false, NeoMutt->sub);
598  if (string_is_address(addr->mailbox, Username, fqdn))
599  {
600  mutt_debug(LL_DEBUG5, "#3 yes, %s = %s @ %s\n", addr->mailbox, Username, NONULL(fqdn));
601  return true;
602  }
603  fqdn = mutt_fqdn(true, NeoMutt->sub);
604  if (string_is_address(addr->mailbox, Username, fqdn))
605  {
606  mutt_debug(LL_DEBUG5, "#4 yes, %s = %s @ %s\n", addr->mailbox, Username, NONULL(fqdn));
607  return true;
608  }
609 
610  const struct Address *c_from = cs_subset_address(NeoMutt->sub, "from");
611  if (c_from && mutt_istr_equal(c_from->mailbox, addr->mailbox))
612  {
613  mutt_debug(LL_DEBUG5, "#5 yes, %s = %s\n", addr->mailbox, c_from->mailbox);
614  return true;
615  }
616 
617  if (mutt_alternates_match(addr->mailbox))
618  return true;
619 
620  mutt_debug(LL_DEBUG5, "no, all failed\n");
621  return false;
622 }
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:261
bool mutt_alternates_match(const char *addr)
Compare an Address to the Un/Alternates lists.
Definition: alternates.c:152
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: helpers.c:49
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
char * Username
User's login name.
Definition: mutt_globals.h:52
+ 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 630 of file alias.c.

631 {
632  struct Alias *a = mutt_mem_calloc(1, sizeof(struct Alias));
633  TAILQ_INIT(&a->addr);
634  return a;
635 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#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 641 of file alias.c.

642 {
643  if (!ptr || !*ptr)
644  return;
645 
646  struct Alias *alias = *ptr;
647 
648  mutt_debug(LL_NOTIFY, "NT_ALIAS_DELETE: %s\n", alias->name);
649  struct EventAlias ev_a = { alias };
651 
652  FREE(&alias->name);
653  FREE(&alias->comment);
655  FREE(ptr);
656 }
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
@ NT_ALIAS_DELETE
Alias is about to be deleted.
Definition: alias.h:55
@ LL_NOTIFY
Log of notifications.
Definition: logging.h:45
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:171
@ NT_ALIAS
Alias has changed, NotifyAlias, EventAlias.
Definition: notify_type.h:37
An alias-change event.
Definition: alias.h:64
struct Alias * alias
Alias that changed.
Definition: alias.h:65
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ aliaslist_free()

void aliaslist_free ( struct AliasList *  al)

Free a List of Aliases.

Parameters
alAliasList to free

Definition at line 662 of file alias.c.

663 {
664  if (!al)
665  return;
666 
667  struct Alias *np = NULL, *tmp = NULL;
668  TAILQ_FOREACH_SAFE(np, al, entries, tmp)
669  {
670  TAILQ_REMOVE(al, np, entries);
671  alias_free(&np);
672  }
673  TAILQ_INIT(al);
674 }
+ 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 679 of file alias.c.

680 {
682 }
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_shutdown()

void alias_shutdown ( void  )

Clean up the Alias globals.

Definition at line 687 of file alias.c.

688 {
689  struct Alias *np = NULL;
690  TAILQ_FOREACH(np, &Aliases, entries)
691  {
693  }
696 }
void aliaslist_free(struct AliasList *al)
Free a List of Aliases.
Definition: alias.c:662
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 1 of file alias.c.