NeoMutt  2020-03-20-65-g141838
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 "gui/lib.h"
#include "mutt.h"
#include "alias.h"
#include "addrbook.h"
#include "globals.h"
#include "hdrline.h"
#include "muttlib.h"
#include "sendlib.h"
+ Include dependency graph for alias.c:

Go to the source code of this file.

Functions

static void expand_aliases_r (struct AddressList *al, struct ListHead *expn)
 Expand aliases, recursively. More...
 
struct Aliasmutt_alias_new (void)
 Create a new Alias. More...
 
static void write_safe_address (FILE *fp, char *s)
 Defang malicious email addresses. 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 *u, const char *d)
 Does an email address match a user and domain? More...
 
struct AddressList * mutt_alias_lookup (const char *s)
 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 **pfxp)
 Get an Address from an Envelope. More...
 
void mutt_alias_create (struct Envelope *cur, struct AddressList *al)
 Create a new Alias from an Envelope or an Address. More...
 
struct Addressmutt_alias_reverse_lookup (const struct Address *a)
 Does the user have an alias for the given address. More...
 
void mutt_alias_add_reverse (struct Alias *t)
 Add an email address lookup for an Alias. More...
 
void mutt_alias_delete_reverse (struct Alias *t)
 Remove an email address lookup for an Alias. More...
 
int mutt_alias_complete (char *buf, size_t buflen)
 alias completion routine More...
 
bool mutt_addr_is_user (const struct Address *addr)
 Does the address belong to the user. More...
 
void mutt_alias_free (struct Alias **ptr)
 Free an Alias. More...
 
void mutt_aliaslist_free (struct AliasList *a_list)
 Free a List of Aliases. More...
 

Detailed Description

Representation of a single alias to an email address.

Authors
  • Michael R. Elkins
  • Pietro Cerutti

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

◆ 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
Return values
ptrAddress List with aliases expanded

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

Definition at line 60 of file alias.c.

61 {
62  struct Address *a = TAILQ_FIRST(al);
63  while (a)
64  {
65  if (!a->group && !a->personal && a->mailbox && !strchr(a->mailbox, '@'))
66  {
67  struct AddressList *alias = mutt_alias_lookup(a->mailbox);
68  if (alias)
69  {
70  bool duplicate = false;
71  struct ListNode *np = NULL;
72  STAILQ_FOREACH(np, expn, entries)
73  {
74  if (mutt_str_strcmp(a->mailbox, np->data) == 0) /* alias already found */
75  {
76  mutt_debug(LL_DEBUG1, "loop in alias found for '%s'\n", a->mailbox);
77  duplicate = true;
78  break;
79  }
80  }
81 
82  if (duplicate)
83  {
84  // We've already seen this alias, so drop it
85  struct Address *next = TAILQ_NEXT(a, entries);
86  TAILQ_REMOVE(al, a, entries);
87  mutt_addr_free(&a);
88  a = next;
89  continue;
90  }
91 
92  // Keep a list of aliases that we've already seen
94 
95  /* The alias may expand to several addresses,
96  * some of which may themselves be aliases.
97  * Create a copy and recursively expand any aliases within. */
98  struct AddressList copy = TAILQ_HEAD_INITIALIZER(copy);
99  mutt_addrlist_copy(&copy, alias, false);
100  expand_aliases_r(&copy, expn);
101 
102  /* Next, move the expanded addresses
103  * from the copy into the original list (before the alias) */
104  struct Address *a2 = NULL, *tmp = NULL;
105  TAILQ_FOREACH_SAFE(a2, &copy, entries, tmp)
106  {
107  TAILQ_INSERT_BEFORE(a, a2, entries);
108  }
109  a = TAILQ_PREV(a, AddressList, entries);
110  // Finally, remove the alias itself
111  struct Address *next = TAILQ_NEXT(a, entries);
112  TAILQ_REMOVE(al, next, entries);
113  mutt_addr_free(&next);
114  }
115  else
116  {
117  struct passwd *pw = getpwnam(a->mailbox);
118  if (pw)
119  {
120  char namebuf[256];
121 
122  mutt_gecos_name(namebuf, sizeof(namebuf), pw);
123  mutt_str_replace(&a->personal, namebuf);
124  }
125  }
126  }
127  a = TAILQ_NEXT(a, entries);
128  }
129 
130  const char *fqdn = NULL;
131  if (C_UseDomain && (fqdn = mutt_fqdn(true)))
132  {
133  /* now qualify all local addresses */
134  mutt_addrlist_qualify(al, fqdn);
135  }
136 }
#define TAILQ_INSERT_BEFORE(listelm, elm, field)
Definition: queue.h:779
struct AddressList * mutt_alias_lookup(const char *s)
Find an Alias.
Definition: alias.c:285
#define TAILQ_FIRST(head)
Definition: queue.h:716
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:728
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:728
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
WHERE bool C_UseDomain
Config: Qualify local addresses using this domain.
Definition: globals.h:256
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:46
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
const char * mutt_fqdn(bool may_hide_host)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:2526
char * personal
Real name of address.
Definition: address.h:36
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:641
char * data
String.
Definition: list.h:35
Log at debug level 1.
Definition: logging.h:40
bool group
Group mailbox?
Definition: address.h:38
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user&#39;s real name in /etc/passwd.
Definition: muttlib.c:367
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
Expand aliases, recursively.
Definition: alias.c:60
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
A List node for strings.
Definition: list.h:33
#define TAILQ_PREV(elm, headname, field)
Definition: queue.h:827
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:630
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:638
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_alias_new()

struct Alias* mutt_alias_new ( void  )

Create a new Alias.

Return values
ptrNewly allocated Alias

Free the result with mutt_alias_free()

Definition at line 144 of file alias.c.

145 {
146  struct Alias *a = mutt_mem_calloc(1, sizeof(struct Alias));
147  TAILQ_INIT(&a->addr);
148  return a;
149 }
A shortcut for an email address.
Definition: alias.h:37
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:758
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ 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 175 of file alias.c.

176 {
177  while (*s)
178  {
179  if ((*s == '\\') || (*s == '`') || (*s == '\'') || (*s == '"') || (*s == '$'))
180  fputc('\\', fp);
181  fputc(*s, fp);
182  s++;
183  }
184 }
+ 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 194 of file alias.c.

195 {
196  if (!C_ConfigCharset || !C_Charset)
197  return;
198 
199  char *s = mutt_str_strdup(buf);
200  if (!s)
201  return;
203  mutt_str_strfcpy(buf, s, buflen);
204  FREE(&s);
205 }
int mutt_ch_convert_string(char **ps, const char *from, const char *to, int flags)
Convert a string between encodings.
Definition: charset.c:748
WHERE char * C_ConfigCharset
Config: Character set that the config files are in.
Definition: globals.h:106
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:773
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define FREE(x)
Definition: memory.h:40
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:54
+ 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 218 of file alias.c.

219 {
220  wchar_t wc;
221  mbstate_t mb;
222  size_t l;
223  int rc = 0;
224  bool dry = !dest || !destlen;
225 
226  memset(&mb, 0, sizeof(mbstate_t));
227 
228  if (!dry)
229  destlen--;
230  for (; s && *s && (dry || destlen) && (l = mbrtowc(&wc, s, MB_CUR_MAX, &mb)) != 0;
231  s += l, destlen -= l)
232  {
233  bool bad = (l == (size_t)(-1)) || (l == (size_t)(-2)); /* conversion error */
234  bad = bad || (!dry && l > destlen); /* too few room for mb char */
235  if (l == 1)
236  bad = bad || (!strchr("-_+=.", *s) && !iswalnum(wc));
237  else
238  bad = bad || !iswalnum(wc);
239  if (bad)
240  {
241  if (dry)
242  return -1;
243  if (l == (size_t)(-1))
244  memset(&mb, 0, sizeof(mbstate_t));
245  *dest++ = '_';
246  rc = -1;
247  }
248  else if (!dry)
249  {
250  memcpy(dest, s, l);
251  dest += l;
252  }
253  }
254  if (!dry)
255  *dest = '\0';
256  return rc;
257 }
+ Here is the caller graph for this function:

◆ string_is_address()

static bool string_is_address ( const char *  str,
const char *  u,
const char *  d 
)
static

Does an email address match a user and domain?

Parameters
strAddress string to test
uUser name
dDomain name
Return values
trueThey match

Definition at line 266 of file alias.c.

267 {
268  char buf[1024];
269 
270  snprintf(buf, sizeof(buf), "%s@%s", NONULL(u), NONULL(d));
271  if (mutt_str_strcasecmp(str, buf) == 0)
272  return true;
273 
274  return false;
275 }
#define NONULL(x)
Definition: string2.h:37
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:651
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_alias_lookup()

struct AddressList* mutt_alias_lookup ( const char *  s)

Find an Alias.

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

Definition at line 285 of file alias.c.

286 {
287  struct Alias *a = NULL;
288 
289  TAILQ_FOREACH(a, &Aliases, entries)
290  {
291  if (mutt_str_strcasecmp(s, a->name) == 0)
292  return &a->addr;
293  }
294  return NULL;
295 }
A shortcut for an email address.
Definition: alias.h:37
char * name
Short name.
Definition: alias.h:39
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:651
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:40
+ 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 303 of file alias.c.

304 {
305  struct ListHead expn; /* previously expanded aliases to avoid loops */
306 
307  STAILQ_INIT(&expn);
308  expand_aliases_r(al, &expn);
309  mutt_list_free(&expn);
311 }
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1319
#define STAILQ_INIT(head)
Definition: queue.h:369
static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
Expand aliases, recursively.
Definition: alias.c:60
+ 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 317 of file alias.c.

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

Get an Address from an Envelope.

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

Definition at line 335 of file alias.c.

336 {
337  struct AddressList *al = NULL;
338  const char *pfx = NULL;
339 
340  if (mutt_addr_is_user(TAILQ_FIRST(&env->from)))
341  {
342  if (!TAILQ_EMPTY(&env->to) && !mutt_is_mail_list(TAILQ_FIRST(&env->to)))
343  {
344  pfx = "To";
345  al = &env->to;
346  }
347  else
348  {
349  pfx = "Cc";
350  al = &env->cc;
351  }
352  }
353  else if (!TAILQ_EMPTY(&env->reply_to) && !mutt_is_mail_list(TAILQ_FIRST(&env->reply_to)))
354  {
355  pfx = "Reply-To";
356  al = &env->reply_to;
357  }
358  else
359  {
360  al = &env->from;
361  pfx = "From";
362  }
363 
364  if (pfxp)
365  *pfxp = pfx;
366 
367  return al;
368 }
#define TAILQ_FIRST(head)
Definition: queue.h:716
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t.
Definition: hdrline.c:114
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:686
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_EMPTY(head)
Definition: queue.h:714
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_alias_create()

void mutt_alias_create ( struct Envelope cur,
struct AddressList *  al 
)

Create a new Alias from an Envelope or an Address.

Parameters
curEnvelope to use
alAddress to use

Definition at line 375 of file alias.c.

376 {
377  struct Address *addr = NULL;
378  char buf[1024], tmp[1024] = { 0 }, prompt[128];
379  char *pc = NULL;
380  char *err = NULL;
381  char fixed[1024];
382 
383  if (cur)
384  {
385  al = mutt_get_address(cur, NULL);
386  }
387 
388  if (al)
389  {
390  addr = TAILQ_FIRST(al);
391  if (addr && addr->mailbox)
392  {
393  mutt_str_strfcpy(tmp, addr->mailbox, sizeof(tmp));
394  pc = strchr(tmp, '@');
395  if (pc)
396  *pc = '\0';
397  }
398  }
399 
400  /* Don't suggest a bad alias name in the event of a strange local part. */
401  check_alias_name(tmp, buf, sizeof(buf));
402 
403 retry_name:
404  /* L10N: prompt to add a new alias */
405  if ((mutt_get_field(_("Alias as: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0) ||
406  !buf[0])
407  {
408  return;
409  }
410 
411  /* check to see if the user already has an alias defined */
412  if (mutt_alias_lookup(buf))
413  {
414  mutt_error(_("You already have an alias defined with that name"));
415  return;
416  }
417 
418  if (check_alias_name(buf, fixed, sizeof(fixed)))
419  {
420  switch (mutt_yesorno(_("Warning: This alias name may not work. Fix it?"), MUTT_YES))
421  {
422  case MUTT_YES:
423  mutt_str_strfcpy(buf, fixed, sizeof(buf));
424  goto retry_name;
425  case MUTT_ABORT:
426  return;
427  default:; // do nothing
428  }
429  }
430 
431  struct Alias *alias = mutt_alias_new();
432  alias->name = mutt_str_strdup(buf);
433 
435 
436  if (addr && addr->mailbox)
437  mutt_str_strfcpy(buf, addr->mailbox, sizeof(buf));
438  else
439  buf[0] = '\0';
440 
441  mutt_addrlist_to_intl(al, NULL);
442 
443  do
444  {
445  if ((mutt_get_field(_("Address: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0) ||
446  !buf[0])
447  {
448  mutt_alias_free(&alias);
449  return;
450  }
451 
452  mutt_addrlist_parse(&alias->addr, buf);
453  if (TAILQ_EMPTY(&alias->addr))
454  mutt_beep(false);
455  if (mutt_addrlist_to_intl(&alias->addr, &err))
456  {
457  mutt_error(_("Bad IDN: '%s'"), err);
458  FREE(&err);
459  continue;
460  }
461  } while (TAILQ_EMPTY(&alias->addr));
462 
463  if (addr && addr->personal && !mutt_is_mail_list(addr))
464  mutt_str_strfcpy(buf, addr->personal, sizeof(buf));
465  else
466  buf[0] = '\0';
467 
468  if (mutt_get_field(_("Personal name: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0)
469  {
470  mutt_alias_free(&alias);
471  return;
472  }
473  mutt_str_replace(&TAILQ_FIRST(&alias->addr)->personal, buf);
474 
475  buf[0] = '\0';
476  mutt_addrlist_write(&alias->addr, buf, sizeof(buf), true);
477  snprintf(prompt, sizeof(prompt), _("[%s = %s] Accept?"), alias->name, buf);
478  if (mutt_yesorno(prompt, MUTT_YES) != MUTT_YES)
479  {
480  mutt_alias_free(&alias);
481  return;
482  }
483 
484  mutt_alias_add_reverse(alias);
485  TAILQ_INSERT_TAIL(&Aliases, alias, entries);
486 
487  mutt_str_strfcpy(buf, C_AliasFile, sizeof(buf));
488  if (mutt_get_field(_("Save to file: "), buf, sizeof(buf), MUTT_FILE) != 0)
489  return;
490  mutt_expand_path(buf, sizeof(buf));
491  FILE *fp_alias = fopen(buf, "a+");
492  if (!fp_alias)
493  {
494  mutt_perror(buf);
495  return;
496  }
497 
498  /* terminate existing file with \n if necessary */
499  if (fseek(fp_alias, 0, SEEK_END))
500  goto fseek_err;
501  if (ftell(fp_alias) > 0)
502  {
503  if (fseek(fp_alias, -1, SEEK_CUR) < 0)
504  goto fseek_err;
505  if (fread(buf, 1, 1, fp_alias) != 1)
506  {
507  mutt_perror(_("Error reading alias file"));
508  mutt_file_fclose(&fp_alias);
509  return;
510  }
511  if (fseek(fp_alias, 0, SEEK_END) < 0)
512  goto fseek_err;
513  if (buf[0] != '\n')
514  fputc('\n', fp_alias);
515  }
516 
517  if (check_alias_name(alias->name, NULL, 0))
518  mutt_file_quote_filename(alias->name, buf, sizeof(buf));
519  else
520  mutt_str_strfcpy(buf, alias->name, sizeof(buf));
521  recode_buf(buf, sizeof(buf));
522  fprintf(fp_alias, "alias %s ", buf);
523  buf[0] = '\0';
524  mutt_addrlist_write(&alias->addr, buf, sizeof(buf), false);
525  recode_buf(buf, sizeof(buf));
526  write_safe_address(fp_alias, buf);
527  fputc('\n', fp_alias);
528  if (mutt_file_fsync_close(&fp_alias) != 0)
529  mutt_perror(_("Trouble adding alias"));
530  else
531  mutt_message(_("Alias added"));
532 
533  return;
534 
535 fseek_err:
536  mutt_perror(_("Error seeking in alias file"));
537  mutt_file_fclose(&fp_alias);
538 }
A shortcut for an email address.
Definition: alias.h:37
char * name
Short name.
Definition: alias.h:39
struct AddressList * mutt_alias_lookup(const char *s)
Find an Alias.
Definition: alias.c:285
#define TAILQ_FIRST(head)
Definition: queue.h:716
#define mutt_perror(...)
Definition: logging.h:85
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:169
User aborted the question (with Ctrl-G)
Definition: quad.h:38
#define mutt_message(...)
Definition: logging.h:83
struct AddressList * mutt_get_address(struct Envelope *env, const char **pfxp)
Get an Address from an Envelope.
Definition: alias.c:335
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1299
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t.
Definition: hdrline.c:114
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
WHERE char * C_AliasFile
Config: Save new aliases to this file.
Definition: globals.h:98
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:90
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:98
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:133
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:378
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
struct Alias * mutt_alias_new(void)
Create a new Alias.
Definition: alias.c:144
void mutt_alias_free(struct Alias **ptr)
Free an Alias.
Definition: alias.c:745
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:773
static int check_alias_name(const char *s, char *dest, size_t destlen)
Sanity-check an alias name.
Definition: alias.c:218
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:802
size_t mutt_file_quote_filename(const char *filename, char *buf, size_t buflen)
Quote a filename to survive the shell&#39;s quoting rules.
Definition: file.c:793
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
#define MUTT_FILE
Do file completion.
Definition: mutt.h:58
static void write_safe_address(FILE *fp, char *s)
Defang malicious email addresses.
Definition: alias.c:175
char * personal
Real name of address.
Definition: address.h:36
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1217
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define mutt_error(...)
Definition: logging.h:84
void mutt_alias_add_reverse(struct Alias *t)
Add an email address lookup for an Alias.
Definition: alias.c:557
#define FREE(x)
Definition: memory.h:40
#define TAILQ_EMPTY(head)
Definition: queue.h:714
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:40
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:1138
static void recode_buf(char *buf, size_t buflen)
Convert some text between two character sets.
Definition: alias.c:194
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_alias_reverse_lookup()

struct Address* mutt_alias_reverse_lookup ( const struct Address a)

Does the user have an alias for the given address.

Parameters
aAddress to lookup
Return values
ptrMatching Address

Definition at line 545 of file alias.c.

546 {
547  if (!a || !a->mailbox)
548  return NULL;
549 
551 }
void * mutt_hash_find(const struct Hash *table, const char *strkey)
Find the HashElem data in a Hash table element using a key.
Definition: hash.c:378
char * mailbox
Mailbox and host address.
Definition: address.h:37
WHERE struct Hash * ReverseAliases
Hash table of aliases (email address -> alias)
Definition: globals.h:59
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_alias_add_reverse()

void mutt_alias_add_reverse ( struct Alias t)

Add an email address lookup for an Alias.

Parameters
tAlias to use

Definition at line 557 of file alias.c.

558 {
559  if (!t)
560  return;
561 
562  /* Note that the address mailbox should be converted to intl form
563  * before using as a key in the hash. This is currently done
564  * by all callers, but added here mostly as documentation. */
565  mutt_addrlist_to_intl(&t->addr, NULL);
566 
567  struct Address *a = NULL;
568  TAILQ_FOREACH(a, &t->addr, entries)
569  {
570  if (!a->group && a->mailbox)
572  }
573 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
WHERE struct Hash * ReverseAliases
Hash table of aliases (email address -> alias)
Definition: globals.h:59
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1217
bool group
Group mailbox?
Definition: address.h:38
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:40
struct HashElem * mutt_hash_insert(struct Hash *table, const char *strkey, void *data)
Add a new element to the Hash table (with string keys)
Definition: hash.c:351
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_alias_delete_reverse()

void mutt_alias_delete_reverse ( struct Alias t)

Remove an email address lookup for an Alias.

Parameters
tAlias to use

Definition at line 579 of file alias.c.

580 {
581  if (!t)
582  return;
583 
584  /* If the alias addresses were converted to local form, they won't
585  * match the hash entries. */
586  mutt_addrlist_to_intl(&t->addr, NULL);
587 
588  struct Address *a = NULL;
589  TAILQ_FOREACH(a, &t->addr, entries)
590  {
591  if (!a->group && a->mailbox)
593  }
594 }
void mutt_hash_delete(struct Hash *table, const char *strkey, const void *data)
Remove an element from a Hash table.
Definition: hash.c:443
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
WHERE struct Hash * ReverseAliases
Hash table of aliases (email address -> alias)
Definition: globals.h:59
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1217
bool group
Group mailbox?
Definition: address.h:38
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_alias_complete()

int mutt_alias_complete ( char *  buf,
size_t  buflen 
)

alias completion routine

Parameters
bufPartial Alias to complete
buflenLength of buffer
Return values
1Success
0Error

Given a partial alias, this routine attempts to fill in the alias from the alias list as much as possible. if given empty search string or found nothing, present all aliases

Definition at line 607 of file alias.c.

608 {
609  struct Alias *a = NULL, *tmp = NULL;
610  struct AliasList a_list = TAILQ_HEAD_INITIALIZER(a_list);
611  char bestname[8192] = { 0 };
612 
613  if (buf[0] != '\0') /* avoid empty string as strstr argument */
614  {
615  TAILQ_FOREACH(a, &Aliases, entries)
616  {
617  if (a->name && (strncmp(a->name, buf, strlen(buf)) == 0))
618  {
619  if (bestname[0] == '\0') /* init */
620  {
621  mutt_str_strfcpy(bestname, a->name,
622  MIN(mutt_str_strlen(a->name) + 1, sizeof(bestname)));
623  }
624  else
625  {
626  int i;
627  for (i = 0; a->name[i] && (a->name[i] == bestname[i]); i++)
628  ;
629  bestname[i] = '\0';
630  }
631  }
632  }
633 
634  if (bestname[0] != '\0')
635  {
636  if (mutt_str_strcmp(bestname, buf) != 0)
637  {
638  /* we are adding something to the completion */
639  mutt_str_strfcpy(buf, bestname, mutt_str_strlen(bestname) + 1);
640  return 1;
641  }
642 
643  /* build alias list and show it */
644  TAILQ_FOREACH(a, &Aliases, entries)
645  {
646  if (a->name && (strncmp(a->name, buf, strlen(buf)) == 0))
647  {
648  tmp = mutt_mem_calloc(1, sizeof(struct Alias));
649  memcpy(tmp, a, sizeof(struct Alias));
650  TAILQ_INSERT_TAIL(&a_list, tmp, entries);
651  }
652  }
653  }
654  }
655 
656  bestname[0] = '\0';
657  mutt_alias_menu(bestname, sizeof(bestname), !TAILQ_EMPTY(&a_list) ? &a_list : &Aliases);
658  if (bestname[0] != '\0')
659  mutt_str_strfcpy(buf, bestname, buflen);
660 
661  /* free the alias list */
662  TAILQ_FOREACH_SAFE(a, &a_list, entries, tmp)
663  {
664  TAILQ_REMOVE(&a_list, a, entries);
665  FREE(&a);
666  }
667 
668  /* remove any aliases marked for deletion */
669  TAILQ_FOREACH_SAFE(a, &Aliases, entries, tmp)
670  {
671  if (a->del)
672  {
673  TAILQ_REMOVE(&Aliases, a, entries);
674  mutt_alias_free(&a);
675  }
676  }
677 
678  return 0;
679 }
A shortcut for an email address.
Definition: alias.h:37
char * name
Short name.
Definition: alias.h:39
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define MIN(a, b)
Definition: memory.h:31
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:728
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:689
bool del
Is it deleted?
Definition: alias.h:42
void mutt_alias_menu(char *buf, size_t buflen, struct AliasList *aliases)
Display a menu of Aliases.
Definition: addrbook.c:224
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
void mutt_alias_free(struct Alias **ptr)
Free an Alias.
Definition: alias.c:745
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:773
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:802
#define FREE(x)
Definition: memory.h:40
#define TAILQ_EMPTY(head)
Definition: queue.h:714
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:630
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:638
+ 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
trueif the given address belongs to the user

Definition at line 686 of file alias.c.

687 {
688  if (!addr)
689  {
690  mutt_debug(LL_DEBUG5, "no, NULL address\n");
691  return false;
692  }
693  if (!addr->mailbox)
694  {
695  mutt_debug(LL_DEBUG5, "no, no mailbox\n");
696  return false;
697  }
698 
699  if (mutt_str_strcasecmp(addr->mailbox, Username) == 0)
700  {
701  mutt_debug(LL_DEBUG5, "#1 yes, %s = %s\n", addr->mailbox, Username);
702  return true;
703  }
705  {
706  mutt_debug(LL_DEBUG5, "#2 yes, %s = %s @ %s\n", addr->mailbox, Username, ShortHostname);
707  return true;
708  }
709  const char *fqdn = mutt_fqdn(false);
710  if (string_is_address(addr->mailbox, Username, fqdn))
711  {
712  mutt_debug(LL_DEBUG5, "#3 yes, %s = %s @ %s\n", addr->mailbox, Username, NONULL(fqdn));
713  return true;
714  }
715  fqdn = mutt_fqdn(true);
716  if (string_is_address(addr->mailbox, Username, fqdn))
717  {
718  mutt_debug(LL_DEBUG5, "#4 yes, %s = %s @ %s\n", addr->mailbox, Username, NONULL(fqdn));
719  return true;
720  }
721 
722  if (C_From && (mutt_str_strcasecmp(C_From->mailbox, addr->mailbox) == 0))
723  {
724  mutt_debug(LL_DEBUG5, "#5 yes, %s = %s\n", addr->mailbox, C_From->mailbox);
725  return true;
726  }
727 
728  if (mutt_regexlist_match(&Alternates, addr->mailbox))
729  {
730  mutt_debug(LL_DEBUG5, "yes, %s matched by alternates\n", addr->mailbox);
731  if (mutt_regexlist_match(&UnAlternates, addr->mailbox))
732  mutt_debug(LL_DEBUG5, "but, %s matched by unalternates\n", addr->mailbox);
733  else
734  return true;
735  }
736 
737  mutt_debug(LL_DEBUG5, "no, all failed\n");
738  return false;
739 }
WHERE char * Username
User&#39;s login name.
Definition: globals.h:52
#define NONULL(x)
Definition: string2.h:37
char * mailbox
Mailbox and host address.
Definition: address.h:37
WHERE struct Address * C_From
Config: Default &#39;From&#39; address to use, if isn&#39;t otherwise set.
Definition: globals.h:94
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition: regex.c:191
static bool string_is_address(const char *str, const char *u, const char *d)
Does an email address match a user and domain?
Definition: alias.c:266
const char * mutt_fqdn(bool may_hide_host)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:2526
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:651
WHERE char * ShortHostname
Short version of the hostname.
Definition: globals.h:50
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 5.
Definition: logging.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_alias_free()

void mutt_alias_free ( struct Alias **  ptr)

Free an Alias.

Parameters
[out]ptrAlias to free

Definition at line 745 of file alias.c.

746 {
747  if (!ptr || !*ptr)
748  return;
749 
750  struct Alias *a = *ptr;
751 
753  FREE(&a->name);
754  mutt_addrlist_clear(&(a->addr));
755  FREE(ptr);
756 }
void mutt_alias_delete_reverse(struct Alias *t)
Remove an email address lookup for an Alias.
Definition: alias.c:579
A shortcut for an email address.
Definition: alias.h:37
char * name
Short name.
Definition: alias.h:39
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1382
#define FREE(x)
Definition: memory.h:40
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:40
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_aliaslist_free()

void mutt_aliaslist_free ( struct AliasList *  a_list)

Free a List of Aliases.

Parameters
a_listAliasList to free

Definition at line 762 of file alias.c.

763 {
764  struct Alias *a = NULL, *tmp = NULL;
765  TAILQ_FOREACH_SAFE(a, a_list, entries, tmp)
766  {
767  TAILQ_REMOVE(a_list, a, entries);
768  mutt_alias_free(&a);
769  }
770  TAILQ_INIT(a_list);
771 }
A shortcut for an email address.
Definition: alias.h:37
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:728
#define TAILQ_INIT(head)
Definition: queue.h:758
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
void mutt_alias_free(struct Alias **ptr)
Free an Alias.
Definition: alias.c:745
+ Here is the call graph for this function:
+ Here is the caller graph for this function: