NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
alias.c
Go to the documentation of this file.
1 
31 #include "config.h"
32 #include <stddef.h>
33 #include <pwd.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <wchar.h>
39 #include <wctype.h>
40 #include "mutt/lib.h"
41 #include "address/lib.h"
42 #include "config/lib.h"
43 #include "email/lib.h"
44 #include "core/lib.h"
45 #include "gui/lib.h"
46 #include "mutt.h"
47 #include "alias.h"
48 #include "lib.h"
49 #include "question/lib.h"
50 #include "send/lib.h"
51 #include "alternates.h"
52 #include "maillist.h"
53 #include "mutt_globals.h"
54 #include "muttlib.h"
55 #include "reverse.h"
56 
57 struct AliasList Aliases = TAILQ_HEAD_INITIALIZER(Aliases);
58 
83 static void write_safe_address(FILE *fp, char *s)
84 {
85  while (*s)
86  {
87  if ((*s == '\\') || (*s == '`') || (*s == '\'') || (*s == '"') || (*s == '$'))
88  fputc('\\', fp);
89  fputc(*s, fp);
90  s++;
91  }
92 }
93 
101 static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
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 }
179 
188 static void recode_buf(char *buf, size_t buflen)
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 }
203 
215 static int check_alias_name(const char *s, char *dest, size_t destlen)
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 }
255 
263 static bool string_is_address(const char *str, const char *user, const char *domain)
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 }
273 
282 struct AddressList *alias_lookup(const char *name)
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 }
293 
300 void mutt_expand_aliases(struct AddressList *al)
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 }
309 
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 }
323 
332 struct AddressList *mutt_get_address(struct Envelope *env, const char **prefix)
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 }
366 
372 void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
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 }
556 
562 bool mutt_addr_is_user(const struct Address *addr)
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 }
611 
618 struct Alias *alias_new(void)
619 {
620  struct Alias *a = mutt_mem_calloc(1, sizeof(struct Alias));
621  TAILQ_INIT(&a->addr);
622  return a;
623 }
624 
629 void alias_free(struct Alias **ptr)
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);
642  mutt_addrlist_clear(&(alias->addr));
643  FREE(ptr);
644 }
645 
650 void aliaslist_free(struct AliasList *al)
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 }
660 
664 void alias_init(void)
665 {
667 }
668 
672 void alias_shutdown(void)
673 {
674  struct Alias *np = NULL;
675  TAILQ_FOREACH(np, &Aliases, entries)
676  {
678  }
681 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
Convenience wrapper for the gui headers.
A shortcut for an email address or addresses.
Definition: alias.h:33
#define TAILQ_INSERT_BEFORE(listelm, elm, field)
Definition: queue.h:786
char * name
Short name.
Definition: alias.h:35
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:300
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:58
#define TAILQ_FIRST(head)
Definition: queue.h:723
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:63
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
Log of notifications.
Definition: logging.h:45
Structs that make up an email.
#define mutt_error(...)
Definition: logging.h:88
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
Convenience wrapper for the send headers.
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:169
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1388
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
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_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
Definition: alias.c:314
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
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
bool mutt_alternates_match(const char *addr)
Compare an Address to the Un/Alternates lists.
Definition: alternates.c:153
Alias has changed, NotifyAlias, EventAlias.
Definition: notify_type.h:35
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
void alias_init(void)
Set up the Alias globals.
Definition: alias.c:664
#define _(a)
Definition: message.h:28
An alias-change event.
Definition: alias.h:63
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:758
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: helpers.c:49
Alternate address handling.
void alias_reverse_shutdown(void)
Clear up the Reverse Alias Hash Table.
Definition: reverse.c:52
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
#define mutt_perror(...)
Definition: logging.h:89
Container for Accounts, Notifications.
Definition: neomutt.h:36
Representation of a single alias to an email address.
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
Convenience wrapper for the config headers.
void alias_reverse_init(void)
Set up the Reverse Alias Hash Table.
Definition: reverse.c:42
Email Address Handling.
WHERE char * Username
User&#39;s login name.
Definition: mutt_globals.h:48
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:105
Some miscellaneous functions.
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:122
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1407
Alias is about to be deleted.
Definition: alias.h:55
Many unsorted constants and some structs.
#define STAILQ_INIT(head)
Definition: queue.h:372
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:282
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
Convenience wrapper for the core headers.
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition: alias.c:372
struct Alias * alias_new(void)
Create a new Alias.
Definition: alias.c:618
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
#define TAILQ_INIT(head)
Definition: queue.h:765
void alias_reverse_add(struct Alias *alias)
Add an email address lookup for an Alias.
Definition: reverse.c:61
User aborted the question (with Ctrl-G)
Definition: quad.h:37
void alias_shutdown(void)
Clean up the Alias globals.
Definition: alias.c:672
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
struct AliasList Aliases
List of all the user&#39;s email aliases.
Definition: alias.c:57
A set of inherited config items.
Definition: subset.h:46
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition: alias.c:332
WHERE char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:46
static int check_alias_name(const char *s, char *dest, size_t destlen)
Sanity-check an alias name.
Definition: alias.c:215
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
char * comment
Free-form comment string.
Definition: alias.h:37
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
Ask the user a question.
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
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:795
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
Handle mailing lists.
void alias_free(struct Alias **ptr)
Free an Alias.
Definition: alias.c:629
#define MUTT_FILE
Do file completion.
Definition: mutt.h:54
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:180
static void write_safe_address(FILE *fp, char *s)
Defang malicious email addresses.
Definition: alias.c:83
char * personal
Real name of address.
Definition: address.h:37
void aliaslist_free(struct AliasList *al)
Free a List of Aliases.
Definition: alias.c:650
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:650
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:1187
char * data
String.
Definition: list.h:36
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1305
Log at debug level 1.
Definition: logging.h:40
bool group
Group mailbox?
Definition: address.h:39
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:361
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
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
Expand aliases, recursively.
Definition: alias.c:101
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:562
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
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
Hundreds of global variables to back the user variables.
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
#define TAILQ_EMPTY(head)
Definition: queue.h:721
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:36
Log at debug level 5.
Definition: logging.h:44
Convenience wrapper for the library headers.
void alias_reverse_delete(struct Alias *alias)
Remove an email address lookup for an Alias.
Definition: reverse.c:83
A List node for strings.
Definition: list.h:34
#define TAILQ_PREV(elm, headname, field)
Definition: queue.h:834
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
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
Manage alias reverse lookups.
The header of an Email.
Definition: envelope.h:54
static void recode_buf(char *buf, size_t buflen)
Convert some text between two character sets.
Definition: alias.c:188
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
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