NeoMutt  2021-10-22-8-g9cb437
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 "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, 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,
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 83 of file alias.c.

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

102 {
103  struct Address *a = TAILQ_FIRST(al);
104  while (a)
105  {
106  if (!a->group && !a->personal && a->mailbox && !strchr(a->mailbox, '@'))
107  {
108  struct AddressList *alias = alias_lookup(a->mailbox);
109  if (alias)
110  {
111  bool duplicate = false;
112  struct ListNode *np = NULL;
113  STAILQ_FOREACH(np, expn, entries)
114  {
115  if (mutt_str_equal(a->mailbox, np->data)) /* alias already found */
116  {
117  mutt_debug(LL_DEBUG1, "loop in alias found for '%s'\n", a->mailbox);
118  duplicate = true;
119  break;
120  }
121  }
122 
123  if (duplicate)
124  {
125  // We've already seen this alias, so drop it
126  struct Address *next = TAILQ_NEXT(a, entries);
127  TAILQ_REMOVE(al, a, entries);
128  mutt_addr_free(&a);
129  a = next;
130  continue;
131  }
132 
133  // Keep a list of aliases that we've already seen
135 
136  /* The alias may expand to several addresses,
137  * some of which may themselves be aliases.
138  * Create a copy and recursively expand any aliases within. */
139  struct AddressList copy = TAILQ_HEAD_INITIALIZER(copy);
140  mutt_addrlist_copy(&copy, alias, false);
141  expand_aliases_r(&copy, expn);
142 
143  /* Next, move the expanded addresses
144  * from the copy into the original list (before the alias) */
145  struct Address *a2 = NULL, *tmp = NULL;
146  TAILQ_FOREACH_SAFE(a2, &copy, entries, tmp)
147  {
148  TAILQ_INSERT_BEFORE(a, a2, entries);
149  }
150  a = TAILQ_PREV(a, AddressList, entries);
151  // Finally, remove the alias itself
152  struct Address *next = TAILQ_NEXT(a, entries);
153  TAILQ_REMOVE(al, next, entries);
154  mutt_addr_free(&next);
155  }
156  else
157  {
158  struct passwd *pw = getpwnam(a->mailbox);
159  if (pw)
160  {
161  char namebuf[256];
162 
163  mutt_gecos_name(namebuf, sizeof(namebuf), pw);
164  mutt_str_replace(&a->personal, namebuf);
165  }
166  }
167  }
168  a = TAILQ_NEXT(a, entries);
169  }
170 
171  const char *fqdn = NULL;
172  const bool c_use_domain = cs_subset_bool(NeoMutt->sub, "use_domain");
173  if (c_use_domain && (fqdn = mutt_fqdn(true, NeoMutt->sub)))
174  {
175  /* now qualify all local addresses */
176  mutt_addrlist_qualify(al, fqdn);
177  }
178 }
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:282
static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
Expand aliases, recursively.
Definition: alias.c:101
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
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:370
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
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:1195
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 188 of file alias.c.

189 {
190  const char *const c_config_charset =
191  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:40
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:765
#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:749
+ 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;
218  mbstate_t mb;
219  size_t l;
220  int rc = 0;
221  bool dry = !dest || !destlen;
222 
223  memset(&mb, 0, sizeof(mbstate_t));
224 
225  if (!dry)
226  destlen--;
227  for (; s && *s && (dry || destlen) && (l = mbrtowc(&wc, s, MB_CUR_MAX, &mb)) != 0;
228  s += l, destlen -= l)
229  {
230  bool bad = (l == (size_t) (-1)) || (l == (size_t) (-2)); /* conversion error */
231  bad = bad || (!dry && l > destlen); /* too few room for mb char */
232  if (l == 1)
233  bad = bad || (!strchr("-_+=.", *s) && !iswalnum(wc));
234  else
235  bad = bad || !iswalnum(wc);
236  if (bad)
237  {
238  if (dry)
239  return -1;
240  if (l == (size_t) (-1))
241  memset(&mb, 0, sizeof(mbstate_t));
242  *dest++ = '_';
243  rc = -1;
244  }
245  else if (!dry)
246  {
247  memcpy(dest, s, l);
248  dest += l;
249  }
250  }
251  if (!dry)
252  *dest = '\0';
253  return rc;
254 }
+ 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 263 of file alias.c.

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

283 {
284  struct Alias *a = NULL;
285 
286  TAILQ_FOREACH(a, &Aliases, entries)
287  {
288  if (mutt_istr_equal(name, a->name))
289  return &a->addr;
290  }
291  return NULL;
292 }
struct AliasList Aliases
List of all the user's email aliases.
Definition: alias.c:57
#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 300 of file alias.c.

301 {
302  struct ListHead expn; /* previously expanded aliases to avoid loops */
303 
304  STAILQ_INIT(&expn);
305  expand_aliases_r(al, &expn);
306  mutt_list_free(&expn);
308 }
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 314 of file alias.c.

315 {
316  mutt_expand_aliases(&env->from);
317  mutt_expand_aliases(&env->to);
318  mutt_expand_aliases(&env->cc);
319  mutt_expand_aliases(&env->bcc);
322 }
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:300
struct AddressList to
Email's 'To' list.
Definition: envelope.h:58
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:62
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition: envelope.h:63
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:59
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:60
struct AddressList from
Email's 'From' list.
Definition: envelope.h:57
+ 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 332 of file alias.c.

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

373 {
374  struct Address *addr = NULL;
375  char buf[1024], tmp[1024] = { 0 }, prompt[2048];
376  char *pc = NULL;
377  char *err = NULL;
378  char fixed[1024];
379 
380  if (al)
381  {
382  addr = TAILQ_FIRST(al);
383  if (addr && addr->mailbox)
384  {
385  mutt_str_copy(tmp, addr->mailbox, sizeof(tmp));
386  pc = strchr(tmp, '@');
387  if (pc)
388  *pc = '\0';
389  }
390  }
391 
392  /* Don't suggest a bad alias name in the event of a strange local part. */
393  check_alias_name(tmp, buf, sizeof(buf));
394 
395 retry_name:
396  /* L10N: prompt to add a new alias */
397  if ((mutt_get_field(_("Alias as: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS,
398  false, NULL, NULL) != 0) ||
399  (buf[0] == '\0'))
400  {
401  return;
402  }
403 
404  /* check to see if the user already has an alias defined */
405  if (alias_lookup(buf))
406  {
407  mutt_error(_("You already have an alias defined with that name"));
408  return;
409  }
410 
411  if (check_alias_name(buf, fixed, sizeof(fixed)))
412  {
413  switch (mutt_yesorno(_("Warning: This alias name may not work. Fix it?"), MUTT_YES))
414  {
415  case MUTT_YES:
416  mutt_str_copy(buf, fixed, sizeof(buf));
417  goto retry_name;
418  case MUTT_ABORT:
419  return;
420  default:; // do nothing
421  }
422  }
423 
424  struct Alias *alias = alias_new();
425  alias->name = mutt_str_dup(buf);
426 
428 
429  if (addr && addr->mailbox)
430  mutt_str_copy(buf, addr->mailbox, sizeof(buf));
431  else
432  buf[0] = '\0';
433 
434  mutt_addrlist_to_intl(al, NULL);
435 
436  do
437  {
438  if ((mutt_get_field(_("Address: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS,
439  false, NULL, NULL) != 0) ||
440  (buf[0] == '\0'))
441  {
442  alias_free(&alias);
443  return;
444  }
445 
446  mutt_addrlist_parse(&alias->addr, buf);
447  if (TAILQ_EMPTY(&alias->addr))
448  mutt_beep(false);
449  if (mutt_addrlist_to_intl(&alias->addr, &err))
450  {
451  mutt_error(_("Bad IDN: '%s'"), err);
452  FREE(&err);
453  continue;
454  }
455  } while (TAILQ_EMPTY(&alias->addr));
456 
457  if (addr && addr->personal && !mutt_is_mail_list(addr))
458  mutt_str_copy(buf, addr->personal, sizeof(buf));
459  else
460  buf[0] = '\0';
461 
462  if (mutt_get_field(_("Personal name: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS,
463  false, NULL, NULL) != 0)
464  {
465  alias_free(&alias);
466  return;
467  }
468  mutt_str_replace(&TAILQ_FIRST(&alias->addr)->personal, buf);
469 
470  buf[0] = '\0';
471  if (mutt_get_field(_("Comment: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS,
472  false, NULL, NULL) == 0)
473  {
474  mutt_str_replace(&alias->comment, buf);
475  }
476 
477  buf[0] = '\0';
478  mutt_addrlist_write(&alias->addr, buf, sizeof(buf), true);
479  if (alias->comment)
480  {
481  snprintf(prompt, sizeof(prompt), "[%s = %s # %s] %s", alias->name, buf,
482  alias->comment, _("Accept?"));
483  }
484  else
485  {
486  snprintf(prompt, sizeof(prompt), "[%s = %s] %s", alias->name, buf, _("Accept?"));
487  }
488  if (mutt_yesorno(prompt, MUTT_YES) != MUTT_YES)
489  {
490  alias_free(&alias);
491  return;
492  }
493 
494  alias_reverse_add(alias);
495  TAILQ_INSERT_TAIL(&Aliases, alias, entries);
496 
497  const char *const alias_file = cs_subset_path(sub, "alias_file");
498  mutt_str_copy(buf, NONULL(alias_file), sizeof(buf));
499 
500  if (mutt_get_field(_("Save to file: "), buf, sizeof(buf),
501  MUTT_FILE | MUTT_CLEAR, false, NULL, NULL) != 0)
502  {
503  return;
504  }
505  mutt_expand_path(buf, sizeof(buf));
506  FILE *fp_alias = fopen(buf, "a+");
507  if (!fp_alias)
508  {
509  mutt_perror(buf);
510  return;
511  }
512 
513  /* terminate existing file with \n if necessary */
514  if (fseek(fp_alias, 0, SEEK_END))
515  goto fseek_err;
516  if (ftell(fp_alias) > 0)
517  {
518  if (fseek(fp_alias, -1, SEEK_CUR) < 0)
519  goto fseek_err;
520  if (fread(buf, 1, 1, fp_alias) != 1)
521  {
522  mutt_perror(_("Error reading alias file"));
523  mutt_file_fclose(&fp_alias);
524  return;
525  }
526  if (fseek(fp_alias, 0, SEEK_END) < 0)
527  goto fseek_err;
528  if (buf[0] != '\n')
529  fputc('\n', fp_alias);
530  }
531 
532  if (check_alias_name(alias->name, NULL, 0))
533  mutt_file_quote_filename(alias->name, buf, sizeof(buf));
534  else
535  mutt_str_copy(buf, alias->name, sizeof(buf));
536  recode_buf(buf, sizeof(buf));
537  fprintf(fp_alias, "alias %s ", buf);
538  buf[0] = '\0';
539  mutt_addrlist_write(&alias->addr, buf, sizeof(buf), false);
540  recode_buf(buf, sizeof(buf));
541  write_safe_address(fp_alias, buf);
542  if (alias->comment)
543  fprintf(fp_alias, " # %s", alias->comment);
544  fputc('\n', fp_alias);
545  if (mutt_file_fsync_close(&fp_alias) != 0)
546  mutt_perror(_("Trouble adding alias"));
547  else
548  mutt_message(_("Alias added"));
549 
550  return;
551 
552 fseek_err:
553  mutt_perror(_("Error seeking in alias file"));
554  mutt_file_fclose(&fp_alias);
555 }
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:629
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:618
static void write_safe_address(FILE *fp, char *s)
Defang malicious email addresses.
Definition: alias.c:83
static void recode_buf(char *buf, size_t buflen)
Convert some text between two character sets.
Definition: alias.c:188
int mutt_get_field(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:335
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:104
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
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:799
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:169
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_perror(...)
Definition: logging.h:88
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
#define _(a)
Definition: message.h:28
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:58
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
#define MUTT_FILE
Do file completion.
Definition: mutt.h:54
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:122
@ 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:182
#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
+ 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 562 of file alias.c.

563 {
564  if (!addr)
565  {
566  mutt_debug(LL_DEBUG5, "no, NULL address\n");
567  return false;
568  }
569  if (!addr->mailbox)
570  {
571  mutt_debug(LL_DEBUG5, "no, no mailbox\n");
572  return false;
573  }
574 
575  if (mutt_istr_equal(addr->mailbox, Username))
576  {
577  mutt_debug(LL_DEBUG5, "#1 yes, %s = %s\n", addr->mailbox, Username);
578  return true;
579  }
581  {
582  mutt_debug(LL_DEBUG5, "#2 yes, %s = %s @ %s\n", addr->mailbox, Username, ShortHostname);
583  return true;
584  }
585  const char *fqdn = mutt_fqdn(false, NeoMutt->sub);
586  if (string_is_address(addr->mailbox, Username, fqdn))
587  {
588  mutt_debug(LL_DEBUG5, "#3 yes, %s = %s @ %s\n", addr->mailbox, Username, NONULL(fqdn));
589  return true;
590  }
591  fqdn = mutt_fqdn(true, NeoMutt->sub);
592  if (string_is_address(addr->mailbox, Username, fqdn))
593  {
594  mutt_debug(LL_DEBUG5, "#4 yes, %s = %s @ %s\n", addr->mailbox, Username, NONULL(fqdn));
595  return true;
596  }
597 
598  const struct Address *c_from = cs_subset_address(NeoMutt->sub, "from");
599  if (c_from && mutt_istr_equal(c_from->mailbox, addr->mailbox))
600  {
601  mutt_debug(LL_DEBUG5, "#5 yes, %s = %s\n", addr->mailbox, c_from->mailbox);
602  return true;
603  }
604 
605  if (mutt_alternates_match(addr->mailbox))
606  return true;
607 
608  mutt_debug(LL_DEBUG5, "no, all failed\n");
609  return false;
610 }
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:263
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:52
char * Username
User's login name.
Definition: mutt_globals.h:54
+ 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 618 of file alias.c.

619 {
620  struct Alias *a = mutt_mem_calloc(1, sizeof(struct Alias));
621  TAILQ_INIT(&a->addr);
622  return a;
623 }
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 629 of file alias.c.

630 {
631  if (!ptr || !*ptr)
632  return;
633 
634  struct Alias *alias = *ptr;
635 
636  mutt_debug(LL_NOTIFY, "NT_ALIAS_DELETE: %s\n", alias->name);
637  struct EventAlias ev_a = { alias };
639 
640  FREE(&alias->name);
641  FREE(&alias->comment);
643  FREE(ptr);
644 }
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:35
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 650 of file alias.c.

651 {
652  struct Alias *np = NULL, *tmp = NULL;
653  TAILQ_FOREACH_SAFE(np, al, entries, tmp)
654  {
655  TAILQ_REMOVE(al, np, entries);
656  alias_free(&np);
657  }
658  TAILQ_INIT(al);
659 }
+ 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 664 of file alias.c.

665 {
667 }
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 672 of file alias.c.

673 {
674  struct Alias *np = NULL;
675  TAILQ_FOREACH(np, &Aliases, entries)
676  {
678  }
681 }
void aliaslist_free(struct AliasList *al)
Free a List of Aliases.
Definition: alias.c:650
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.