NeoMutt  2018-07-16 +2225-8687db
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 <errno.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>
#include "mutt/mutt.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "mutt.h"
#include "alias.h"
#include "addrbook.h"
#include "curs_lib.h"
#include "globals.h"
#include "hdrline.h"
#include "mutt_curses.h"
#include "muttlib.h"
#include "sendlib.h"

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 ()
 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 **p)
 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

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

63 {
64  bool i;
65  const char *fqdn = NULL;
66 
67  struct Address *a = TAILQ_FIRST(al);
68  while (a)
69  {
70  if (!a->group && !a->personal && a->mailbox && !strchr(a->mailbox, '@'))
71  {
72  struct AddressList *alias = mutt_alias_lookup(a->mailbox);
73  if (alias)
74  {
75  i = false;
76  struct ListNode *np = NULL;
77  STAILQ_FOREACH(np, expn, entries)
78  {
79  if (mutt_str_strcmp(a->mailbox, np->data) == 0) /* alias already found */
80  {
81  mutt_debug(LL_DEBUG1, "loop in alias found for '%s'\n", a->mailbox);
82  i = true;
83  break;
84  }
85  }
86 
87  if (!i)
88  {
90  struct AddressList copy = TAILQ_HEAD_INITIALIZER(copy);
91  mutt_addrlist_copy(&copy, alias, false);
92  expand_aliases_r(&copy, expn);
93  struct Address *a2 = NULL, *tmp = NULL;
94  TAILQ_FOREACH_SAFE(a2, &copy, entries, tmp)
95  {
96  TAILQ_INSERT_BEFORE(a, a2, entries);
97  }
98  a = TAILQ_PREV(a, AddressList, entries);
99  TAILQ_REMOVE(al, TAILQ_NEXT(a, entries), entries);
100  }
101  }
102  else
103  {
104  struct passwd *pw = getpwnam(a->mailbox);
105 
106  if (pw)
107  {
108  char namebuf[256];
109 
110  mutt_gecos_name(namebuf, sizeof(namebuf), pw);
111  mutt_str_replace(&a->personal, namebuf);
112  }
113  }
114  }
115  a = TAILQ_NEXT(a, entries);
116  }
117 
118  if (C_UseDomain && (fqdn = mutt_fqdn(true)))
119  {
120  /* now qualify all local addresses */
121  mutt_addrlist_qualify(al, fqdn);
122  }
123 }
#define TAILQ_INSERT_BEFORE(listelm, elm, field)
Definition: queue.h:780
struct AddressList * mutt_alias_lookup(const char *s)
Find an Alias.
Definition: alias.c:272
#define TAILQ_FIRST(head)
Definition: queue.h:717
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:724
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:729
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
WHERE bool C_UseDomain
Config: Qualify local addresses using this domain.
Definition: globals.h:257
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:821
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:350
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:2449
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:637
char * data
Definition: list.h:35
Log at debug level 1.
Definition: logging.h:56
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:362
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:62
#define TAILQ_NEXT(elm, field)
Definition: queue.h:816
#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:818
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:631
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
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 131 of file alias.c.

132 {
133  struct Alias *a = mutt_mem_calloc(1, sizeof(struct Alias));
134  TAILQ_INIT(&a->addr);
135  return a;
136 }
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:759
struct AddressList addr
Definition: alias.h:40
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 162 of file alias.c.

163 {
164  while (*s)
165  {
166  if ((*s == '\\') || (*s == '`') || (*s == '\'') || (*s == '"') || (*s == '$'))
167  fputc('\\', fp);
168  fputc(*s, fp);
169  s++;
170  }
171 }
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 181 of file alias.c.

182 {
183  if (!C_ConfigCharset || !C_Charset)
184  return;
185 
186  char *s = mutt_str_strdup(buf);
187  if (!s)
188  return;
190  mutt_str_strfcpy(buf, s, buflen);
191  FREE(&s);
192 }
int mutt_ch_convert_string(char **ps, const char *from, const char *to, int flags)
Convert a string between encodings.
Definition: charset.c:724
WHERE char * C_ConfigCharset
Config: Character set that the config files are in.
Definition: globals.h:99
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:750
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
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 205 of file alias.c.

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

254 {
255  char buf[1024];
256 
257  snprintf(buf, sizeof(buf), "%s@%s", NONULL(u), NONULL(d));
258  if (mutt_str_strcasecmp(str, buf) == 0)
259  return true;
260 
261  return false;
262 }
#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:628
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 272 of file alias.c.

273 {
274  struct Alias *a = NULL;
275 
276  TAILQ_FOREACH(a, &Aliases, entries)
277  {
278  if (mutt_str_strcasecmp(s, a->name) == 0)
279  return &a->addr;
280  }
281  return NULL;
282 }
A shortcut for an email address.
Definition: alias.h:37
char * name
Definition: alias.h:39
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
struct AddressList addr
Definition: alias.h:40
void mutt_expand_aliases ( struct AddressList *  al)

Expand aliases in a List of Addresses.

Parameters
alAddressList

Duplicate addresses are dropped

Definition at line 290 of file alias.c.

291 {
292  struct ListHead expn; /* previously expanded aliases to avoid loops */
293 
294  STAILQ_INIT(&expn);
295  expand_aliases_r(al, &expn);
296  mutt_list_free(&expn);
298 }
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:1288
#define STAILQ_INIT(head)
Definition: queue.h:370
static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
Expand aliases, recursively.
Definition: alias.c:62
void mutt_expand_aliases_env ( struct Envelope env)

Expand aliases in all the fields of an Envelope.

Parameters
envEnvelope to expand

Definition at line 304 of file alias.c.

305 {
306  mutt_expand_aliases(&env->from);
307  mutt_expand_aliases(&env->to);
308  mutt_expand_aliases(&env->cc);
309  mutt_expand_aliases(&env->bcc);
312 }
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:290
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:49
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:48
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:46
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:43
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:45
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:44
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 322 of file alias.c.

323 {
324  struct AddressList *al = NULL;
325  const char *pfx = NULL;
326 
327  if (mutt_addr_is_user(TAILQ_FIRST(&env->from)))
328  {
329  if (!TAILQ_EMPTY(&env->to) && !mutt_is_mail_list(TAILQ_FIRST(&env->to)))
330  {
331  pfx = "To";
332  al = &env->to;
333  }
334  else
335  {
336  pfx = "Cc";
337  al = &env->cc;
338  }
339  }
340  else if (!TAILQ_EMPTY(&env->reply_to) && !mutt_is_mail_list(TAILQ_FIRST(&env->reply_to)))
341  {
342  pfx = "Reply-To";
343  al = &env->reply_to;
344  }
345  else
346  {
347  al = &env->from;
348  pfx = "From";
349  }
350 
351  if (pfxp)
352  *pfxp = pfx;
353 
354  return al;
355 }
#define TAILQ_FIRST(head)
Definition: queue.h:717
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:48
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list?
Definition: hdrline.c:102
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:43
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:45
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:669
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:44
#define TAILQ_EMPTY(head)
Definition: queue.h:715
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 362 of file alias.c.

363 {
364  struct Address *addr = NULL;
365  char buf[1024], tmp[1024] = { 0 }, prompt[128];
366  char *pc = NULL;
367  char *err = NULL;
368  char fixed[1024];
369 
370  if (cur)
371  {
372  al = mutt_get_address(cur, NULL);
373  }
374 
375  if (al)
376  {
377  addr = TAILQ_FIRST(al);
378  if (addr && addr->mailbox)
379  {
380  mutt_str_strfcpy(tmp, addr->mailbox, sizeof(tmp));
381  pc = strchr(tmp, '@');
382  if (pc)
383  *pc = '\0';
384  }
385  }
386 
387  /* Don't suggest a bad alias name in the event of a strange local part. */
388  check_alias_name(tmp, buf, sizeof(buf));
389 
390 retry_name:
391  /* L10N: prompt to add a new alias */
392  if ((mutt_get_field(_("Alias as: "), buf, sizeof(buf), 0) != 0) || !buf[0])
393  return;
394 
395  /* check to see if the user already has an alias defined */
396  if (mutt_alias_lookup(buf))
397  {
398  mutt_error(_("You already have an alias defined with that name"));
399  return;
400  }
401 
402  if (check_alias_name(buf, fixed, sizeof(fixed)))
403  {
404  switch (mutt_yesorno(_("Warning: This alias name may not work. Fix it?"), MUTT_YES))
405  {
406  case MUTT_YES:
407  mutt_str_strfcpy(buf, fixed, sizeof(buf));
408  goto retry_name;
409  case MUTT_ABORT:
410  return;
411  default:; // do nothing
412  }
413  }
414 
415  struct Alias *alias = mutt_alias_new();
416  alias->name = mutt_str_strdup(buf);
417 
419 
420  if (addr && addr->mailbox)
421  mutt_str_strfcpy(buf, addr->mailbox, sizeof(buf));
422  else
423  buf[0] = '\0';
424 
425  mutt_addrlist_to_intl(al, NULL);
426 
427  do
428  {
429  if ((mutt_get_field(_("Address: "), buf, sizeof(buf), 0) != 0) || !buf[0])
430  {
431  mutt_alias_free(&alias);
432  return;
433  }
434 
435  mutt_addrlist_parse(&alias->addr, buf);
436  if (TAILQ_EMPTY(&alias->addr))
437  BEEP();
438  if (mutt_addrlist_to_intl(&alias->addr, &err))
439  {
440  mutt_error(_("Bad IDN: '%s'"), err);
441  FREE(&err);
442  continue;
443  }
444  } while (TAILQ_EMPTY(&alias->addr));
445 
446  if (addr && addr->personal && !mutt_is_mail_list(addr))
447  mutt_str_strfcpy(buf, addr->personal, sizeof(buf));
448  else
449  buf[0] = '\0';
450 
451  if (mutt_get_field(_("Personal name: "), buf, sizeof(buf), 0) != 0)
452  {
453  mutt_alias_free(&alias);
454  return;
455  }
456  mutt_str_replace(&TAILQ_FIRST(&alias->addr)->personal, buf);
457 
458  buf[0] = '\0';
459  mutt_addrlist_write(buf, sizeof(buf), &alias->addr, true);
460  snprintf(prompt, sizeof(prompt), _("[%s = %s] Accept?"), alias->name, buf);
461  if (mutt_yesorno(prompt, MUTT_YES) != MUTT_YES)
462  {
463  mutt_alias_free(&alias);
464  return;
465  }
466 
467  mutt_alias_add_reverse(alias);
468  TAILQ_INSERT_TAIL(&Aliases, alias, entries);
469 
470  mutt_str_strfcpy(buf, C_AliasFile, sizeof(buf));
471  if (mutt_get_field(_("Save to file: "), buf, sizeof(buf), MUTT_FILE) != 0)
472  return;
473  mutt_expand_path(buf, sizeof(buf));
474  FILE *fp_alias = fopen(buf, "a+");
475  if (!fp_alias)
476  {
477  mutt_perror(buf);
478  return;
479  }
480 
481  /* terminate existing file with \n if necessary */
482  if (fseek(fp_alias, 0, SEEK_END))
483  goto fseek_err;
484  if (ftell(fp_alias) > 0)
485  {
486  if (fseek(fp_alias, -1, SEEK_CUR) < 0)
487  goto fseek_err;
488  if (fread(buf, 1, 1, fp_alias) != 1)
489  {
490  mutt_perror(_("Error reading alias file"));
491  mutt_file_fclose(&fp_alias);
492  return;
493  }
494  if (fseek(fp_alias, 0, SEEK_END) < 0)
495  goto fseek_err;
496  if (buf[0] != '\n')
497  fputc('\n', fp_alias);
498  }
499 
500  if (check_alias_name(alias->name, NULL, 0))
501  mutt_file_quote_filename(alias->name, buf, sizeof(buf));
502  else
503  mutt_str_strfcpy(buf, alias->name, sizeof(buf));
504  recode_buf(buf, sizeof(buf));
505  fprintf(fp_alias, "alias %s ", buf);
506  buf[0] = '\0';
507  mutt_addrlist_write(buf, sizeof(buf), &alias->addr, false);
508  recode_buf(buf, sizeof(buf));
509  write_safe_address(fp_alias, buf);
510  fputc('\n', fp_alias);
511  if (mutt_file_fsync_close(&fp_alias) != 0)
512  mutt_perror(_("Trouble adding alias"));
513  else
514  mutt_message(_("Alias added"));
515 
516  return;
517 
518 fseek_err:
519  mutt_perror(_("Error seeking in alias file"));
520  mutt_file_fclose(&fp_alias);
521 }
A shortcut for an email address.
Definition: alias.h:37
char * name
Definition: alias.h:39
struct AddressList * mutt_alias_lookup(const char *s)
Find an Alias.
Definition: alias.c:272
#define TAILQ_FIRST(head)
Definition: queue.h:717
#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:454
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:165
User aborted the question (with Ctrl-G)
Definition: quad.h:37
#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:322
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1268
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list?
Definition: hdrline.c:102
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
size_t mutt_addrlist_write(char *buf, size_t buflen, const struct AddressList *al, bool display)
Write an Address to a buffer.
Definition: address.c:1134
WHERE char * C_AliasFile
Config: Save new aliases to this file.
Definition: globals.h:95
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:86
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:128
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:332
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
struct Alias * mutt_alias_new()
Create a new Alias.
Definition: alias.c:131
#define BEEP()
Definition: mutt_curses.h:80
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:750
static int check_alias_name(const char *s, char *dest, size_t destlen)
Sanity-check an alias name.
Definition: alias.c:205
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:803
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:789
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:64
static void write_safe_address(FILE *fp, char *s)
Defang malicious email addresses.
Definition: alias.c:162
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:1186
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:540
void mutt_alias_free(struct Alias **p)
Free an Alias.
Definition: alias.c:728
#define FREE(x)
Definition: memory.h:40
#define TAILQ_EMPTY(head)
Definition: queue.h:715
struct AddressList addr
Definition: alias.h:40
static void recode_buf(char *buf, size_t buflen)
Convert some text between two character sets.
Definition: alias.c:181
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 528 of file alias.c.

529 {
530  if (!a || !a->mailbox)
531  return NULL;
532 
534 }
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:379
char * mailbox
Mailbox and host address.
Definition: address.h:37
WHERE struct Hash * ReverseAliases
Hash table of aliases (email address -> alias)
Definition: globals.h:58
void mutt_alias_add_reverse ( struct Alias t)

Add an email address lookup for an Alias.

Parameters
tAlias to use

Definition at line 540 of file alias.c.

541 {
542  if (!t)
543  return;
544 
545  /* Note that the address mailbox should be converted to intl form
546  * before using as a key in the hash. This is currently done
547  * by all callers, but added here mostly as documentation. */
548  mutt_addrlist_to_intl(&t->addr, NULL);
549 
550  struct Address *a = NULL;
551  TAILQ_FOREACH(a, &t->addr, entries)
552  {
553  if (!a->group && a->mailbox)
555  }
556 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
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:58
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1186
bool group
Group mailbox?
Definition: address.h:38
struct AddressList addr
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:352
void mutt_alias_delete_reverse ( struct Alias t)

Remove an email address lookup for an Alias.

Parameters
tAlias to use

Definition at line 562 of file alias.c.

563 {
564  if (!t)
565  return;
566 
567  /* If the alias addresses were converted to local form, they won't
568  * match the hash entries. */
569  mutt_addrlist_to_intl(&t->addr, NULL);
570 
571  struct Address *a = NULL;
572  TAILQ_FOREACH(a, &t->addr, entries)
573  {
574  if (!a->group && a->mailbox)
576  }
577 }
void mutt_hash_delete(struct Hash *table, const char *strkey, const void *data)
Remove an element from a Hash table.
Definition: hash.c:444
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:719
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:58
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1186
bool group
Group mailbox?
Definition: address.h:38
struct AddressList addr
Definition: alias.h:40
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 590 of file alias.c.

591 {
592  struct Alias *a = NULL, *tmp = NULL;
593  struct AliasList a_list = TAILQ_HEAD_INITIALIZER(a_list);
594  char bestname[8192] = { 0 };
595 
596  if (buf[0] != '\0') /* avoid empty string as strstr argument */
597  {
598  TAILQ_FOREACH(a, &Aliases, entries)
599  {
600  if (a->name && (strncmp(a->name, buf, strlen(buf)) == 0))
601  {
602  if (bestname[0] == '\0') /* init */
603  {
604  mutt_str_strfcpy(bestname, a->name,
605  MIN(mutt_str_strlen(a->name) + 1, sizeof(bestname)));
606  }
607  else
608  {
609  int i;
610  for (i = 0; a->name[i] && (a->name[i] == bestname[i]); i++)
611  ;
612  bestname[i] = '\0';
613  }
614  }
615  }
616 
617  if (bestname[0] != '\0')
618  {
619  if (mutt_str_strcmp(bestname, buf) != 0)
620  {
621  /* we are adding something to the completion */
622  mutt_str_strfcpy(buf, bestname, mutt_str_strlen(bestname) + 1);
623  return 1;
624  }
625 
626  /* build alias list and show it */
627  TAILQ_FOREACH(a, &Aliases, entries)
628  {
629  if (a->name && (strncmp(a->name, buf, strlen(buf)) == 0))
630  {
631  tmp = mutt_mem_calloc(1, sizeof(struct Alias));
632  memcpy(tmp, a, sizeof(struct Alias));
633  TAILQ_INSERT_TAIL(&a_list, tmp, entries);
634  }
635  }
636  }
637  }
638 
639  bestname[0] = '\0';
640  mutt_alias_menu(bestname, sizeof(bestname), !TAILQ_EMPTY(&a_list) ? &a_list : &Aliases);
641  if (bestname[0] != '\0')
642  mutt_str_strfcpy(buf, bestname, buflen);
643 
644  /* free the alias list */
645  TAILQ_FOREACH_SAFE(a, &a_list, entries, tmp)
646  {
647  TAILQ_REMOVE(&a_list, a, entries);
648  FREE(&a);
649  }
650 
651  /* remove any aliases marked for deletion */
652  TAILQ_FOREACH_SAFE(a, &Aliases, entries, tmp)
653  {
654  if (a->del)
655  {
656  TAILQ_REMOVE(&Aliases, a, entries);
657  mutt_alias_free(&a);
658  }
659  }
660 
661  return 0;
662 }
A shortcut for an email address.
Definition: alias.h:37
char * 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:719
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:729
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
bool del
Definition: alias.h:42
void mutt_alias_menu(char *buf, size_t buflen, struct AliasList *aliases)
Display a menu of Aliases.
Definition: addrbook.c:195
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:821
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:750
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:803
void mutt_alias_free(struct Alias **p)
Free an Alias.
Definition: alias.c:728
#define FREE(x)
Definition: memory.h:40
#define TAILQ_EMPTY(head)
Definition: queue.h:715
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:631
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:615
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 669 of file alias.c.

670 {
671  if (!addr)
672  {
673  mutt_debug(LL_DEBUG5, "no, NULL address\n");
674  return false;
675  }
676  if (!addr->mailbox)
677  {
678  mutt_debug(LL_DEBUG5, "no, no mailbox\n");
679  return false;
680  }
681 
682  if (mutt_str_strcasecmp(addr->mailbox, Username) == 0)
683  {
684  mutt_debug(LL_DEBUG5, "#1 yes, %s = %s\n", addr->mailbox, Username);
685  return true;
686  }
688  {
689  mutt_debug(LL_DEBUG5, "#2 yes, %s = %s @ %s\n", addr->mailbox, Username, ShortHostname);
690  return true;
691  }
692  const char *fqdn = mutt_fqdn(false);
693  if (string_is_address(addr->mailbox, Username, fqdn))
694  {
695  mutt_debug(LL_DEBUG5, "#3 yes, %s = %s @ %s\n", addr->mailbox, Username, NONULL(fqdn));
696  return true;
697  }
698  fqdn = mutt_fqdn(true);
699  if (string_is_address(addr->mailbox, Username, fqdn))
700  {
701  mutt_debug(LL_DEBUG5, "#4 yes, %s = %s @ %s\n", addr->mailbox, Username, NONULL(fqdn));
702  return true;
703  }
704 
705  if (C_From && (mutt_str_strcasecmp(C_From->mailbox, addr->mailbox) == 0))
706  {
707  mutt_debug(LL_DEBUG5, "#5 yes, %s = %s\n", addr->mailbox, C_From->mailbox);
708  return true;
709  }
710 
711  if (mutt_regexlist_match(&Alternates, addr->mailbox))
712  {
713  mutt_debug(LL_DEBUG5, "yes, %s matched by alternates\n", addr->mailbox);
714  if (mutt_regexlist_match(&UnAlternates, addr->mailbox))
715  mutt_debug(LL_DEBUG5, "but, %s matched by unalternates\n", addr->mailbox);
716  else
717  return true;
718  }
719 
720  mutt_debug(LL_DEBUG5, "no, all failed\n");
721  return false;
722 }
WHERE char * Username
User&#39;s login name.
Definition: globals.h:51
#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:93
bool mutt_regexlist_match(struct RegexList *rl, const char *str)
Does a string match any Regex in the list?
Definition: regex.c:190
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:253
const char * mutt_fqdn(bool may_hide_host)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:2449
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:628
WHERE char * ShortHostname
Short version of the hostname.
Definition: globals.h:49
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Log at debug level 5.
Definition: logging.h:60
void mutt_alias_free ( struct Alias **  p)

Free an Alias.

Parameters
[out]pAlias to free

Definition at line 728 of file alias.c.

729 {
730  if (!p || !*p)
731  return;
732 
734  FREE(&(*p)->name);
735  mutt_addrlist_clear(&((*p)->addr));
736  FREE(p);
737 }
void mutt_alias_delete_reverse(struct Alias *t)
Remove an email address lookup for an Alias.
Definition: alias.c:562
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1351
#define FREE(x)
Definition: memory.h:40
void mutt_aliaslist_free ( struct AliasList *  a_list)

Free a List of Aliases.

Parameters
a_listAliasList to free

Definition at line 743 of file alias.c.

744 {
745  struct Alias *a = NULL, *tmp = NULL;
746  TAILQ_FOREACH_SAFE(a, a_list, entries, tmp)
747  {
748  TAILQ_REMOVE(a_list, a, entries);
749  mutt_alias_free(&a);
750  }
751  TAILQ_INIT(a_list);
752 }
A shortcut for an email address.
Definition: alias.h:37
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:729
#define TAILQ_INIT(head)
Definition: queue.h:759
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:821
void mutt_alias_free(struct Alias **p)
Free an Alias.
Definition: alias.c:728