NeoMutt  2022-04-29-145-g9b6a0e
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 "enter/lib.h"
50 #include "question/lib.h"
51 #include "send/lib.h"
52 #include "alternates.h"
53 #include "maillist.h"
54 #include "mutt_globals.h"
55 #include "muttlib.h"
56 #include "reverse.h"
57 
58 struct AliasList Aliases = TAILQ_HEAD_INITIALIZER(Aliases);
59 
84 static void write_safe_address(FILE *fp, const char *s)
85 {
86  while (*s)
87  {
88  if ((*s == '\\') || (*s == '`') || (*s == '\'') || (*s == '"') || (*s == '$'))
89  fputc('\\', fp);
90  fputc(*s, fp);
91  s++;
92  }
93 }
94 
102 static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
103 {
104  struct Address *a = TAILQ_FIRST(al);
105  while (a)
106  {
107  if (!a->group && !a->personal && a->mailbox && !strchr(a->mailbox, '@'))
108  {
109  struct AddressList *alias = alias_lookup(a->mailbox);
110  if (alias)
111  {
112  bool duplicate = false;
113  struct ListNode *np = NULL;
114  STAILQ_FOREACH(np, expn, entries)
115  {
116  if (mutt_str_equal(a->mailbox, np->data)) /* alias already found */
117  {
118  mutt_debug(LL_DEBUG1, "loop in alias found for '%s'\n", a->mailbox);
119  duplicate = true;
120  break;
121  }
122  }
123 
124  if (duplicate)
125  {
126  // We've already seen this alias, so drop it
127  struct Address *next = TAILQ_NEXT(a, entries);
128  TAILQ_REMOVE(al, a, entries);
129  mutt_addr_free(&a);
130  a = next;
131  continue;
132  }
133 
134  // Keep a list of aliases that we've already seen
136 
137  /* The alias may expand to several addresses,
138  * some of which may themselves be aliases.
139  * Create a copy and recursively expand any aliases within. */
140  struct AddressList copy = TAILQ_HEAD_INITIALIZER(copy);
141  mutt_addrlist_copy(&copy, alias, false);
142  expand_aliases_r(&copy, expn);
143 
144  /* Next, move the expanded addresses
145  * from the copy into the original list (before the alias) */
146  struct Address *a2 = NULL, *tmp = NULL;
147  TAILQ_FOREACH_SAFE(a2, &copy, entries, tmp)
148  {
149  TAILQ_INSERT_BEFORE(a, a2, entries);
150  }
151  a = TAILQ_PREV(a, AddressList, entries);
152  // Finally, remove the alias itself
153  struct Address *next = TAILQ_NEXT(a, entries);
154  TAILQ_REMOVE(al, next, entries);
155  mutt_addr_free(&next);
156  }
157  else
158  {
159  struct passwd *pw = getpwnam(a->mailbox);
160  if (pw)
161  {
162  char namebuf[256];
163 
164  mutt_gecos_name(namebuf, sizeof(namebuf), pw);
165  mutt_str_replace(&a->personal, namebuf);
166  }
167  }
168  }
169  a = TAILQ_NEXT(a, entries);
170  }
171 
172  const char *fqdn = NULL;
173  const bool c_use_domain = cs_subset_bool(NeoMutt->sub, "use_domain");
174  if (c_use_domain && (fqdn = mutt_fqdn(true, NeoMutt->sub)))
175  {
176  /* now qualify all local addresses */
177  mutt_addrlist_qualify(al, fqdn);
178  }
179 }
180 
189 static void recode_buf(char *buf, size_t buflen)
190 {
191  const char *const c_config_charset = cs_subset_string(NeoMutt->sub, "config_charset");
192  const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
193  if (!c_config_charset || !c_charset)
194  return;
195 
196  char *s = mutt_str_dup(buf);
197  if (!s)
198  return;
199  if (mutt_ch_convert_string(&s, c_charset, c_config_charset, MUTT_ICONV_NO_FLAGS) == 0)
200  mutt_str_copy(buf, s, buflen);
201  FREE(&s);
202 }
203 
215 static int check_alias_name(const char *s, char *dest, size_t destlen)
216 {
217  wchar_t wc = 0;
218  mbstate_t mbstate = { 0 };
219  size_t l;
220  int rc = 0;
221  bool dry = !dest || !destlen;
222 
223  if (!dry)
224  destlen--;
225  for (; s && *s && (dry || destlen) && (l = mbrtowc(&wc, s, MB_CUR_MAX, &mbstate)) != 0;
226  s += l, destlen -= l)
227  {
228  bool bad = (l == (size_t) (-1)) || (l == (size_t) (-2)); /* conversion error */
229  bad = bad || (!dry && l > destlen); /* too few room for mb char */
230  if (l == 1)
231  bad = bad || (!strchr("-_+=.", *s) && !iswalnum(wc));
232  else
233  bad = bad || !iswalnum(wc);
234  if (bad)
235  {
236  if (dry)
237  return -1;
238  if (l == (size_t) (-1))
239  memset(&mbstate, 0, sizeof(mbstate_t));
240  *dest++ = '_';
241  rc = -1;
242  }
243  else if (!dry)
244  {
245  memcpy(dest, s, l);
246  dest += l;
247  }
248  }
249  if (!dry)
250  *dest = '\0';
251  return rc;
252 }
253 
261 static bool string_is_address(const char *str, const char *user, const char *domain)
262 {
263  char buf[1024];
264 
265  snprintf(buf, sizeof(buf), "%s@%s", NONULL(user), NONULL(domain));
266  if (mutt_istr_equal(str, buf))
267  return true;
268 
269  return false;
270 }
271 
280 struct AddressList *alias_lookup(const char *name)
281 {
282  struct Alias *a = NULL;
283 
284  TAILQ_FOREACH(a, &Aliases, entries)
285  {
286  if (mutt_istr_equal(name, a->name))
287  return &a->addr;
288  }
289  return NULL;
290 }
291 
298 void mutt_expand_aliases(struct AddressList *al)
299 {
300  struct ListHead expn; /* previously expanded aliases to avoid loops */
301 
302  STAILQ_INIT(&expn);
303  expand_aliases_r(al, &expn);
304  mutt_list_free(&expn);
306 }
307 
313 {
314  mutt_expand_aliases(&env->from);
315  mutt_expand_aliases(&env->to);
316  mutt_expand_aliases(&env->cc);
317  mutt_expand_aliases(&env->bcc);
320 }
321 
330 struct AddressList *mutt_get_address(struct Envelope *env, const char **prefix)
331 {
332  struct AddressList *al = NULL;
333  const char *pfx = NULL;
334 
335  if (mutt_addr_is_user(TAILQ_FIRST(&env->from)))
336  {
337  if (!TAILQ_EMPTY(&env->to) && !mutt_is_mail_list(TAILQ_FIRST(&env->to)))
338  {
339  pfx = "To";
340  al = &env->to;
341  }
342  else
343  {
344  pfx = "Cc";
345  al = &env->cc;
346  }
347  }
348  else if (!TAILQ_EMPTY(&env->reply_to) && !mutt_is_mail_list(TAILQ_FIRST(&env->reply_to)))
349  {
350  pfx = "Reply-To";
351  al = &env->reply_to;
352  }
353  else
354  {
355  al = &env->from;
356  pfx = "From";
357  }
358 
359  if (prefix)
360  *prefix = pfx;
361 
362  return al;
363 }
364 
370 void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
371 {
372  struct Buffer *buf = mutt_buffer_pool_get();
373  struct Buffer *fixed = mutt_buffer_pool_get();
374  struct Buffer *prompt = NULL;
375  struct Buffer *tmp = mutt_buffer_pool_get();
376 
377  struct Address *addr = NULL;
378  char *pc = NULL;
379  char *err = NULL;
380  FILE *fp_alias = NULL;
381 
382  if (al)
383  {
384  addr = TAILQ_FIRST(al);
385  if (addr && addr->mailbox)
386  {
387  mutt_buffer_strcpy(tmp, addr->mailbox);
388  pc = strchr(mutt_buffer_string(tmp), '@');
389  if (pc)
390  *pc = '\0';
391  }
392  }
393 
394  /* Don't suggest a bad alias name in the event of a strange local part. */
395  check_alias_name(mutt_buffer_string(tmp), buf->data, buf->dsize);
396 
397 retry_name:
398  /* L10N: prompt to add a new alias */
399  if ((mutt_buffer_get_field(_("Alias as: "), buf, MUTT_COMP_NO_FLAGS, false,
400  NULL, NULL, NULL) != 0) ||
402  {
403  goto done;
404  }
405 
406  /* check to see if the user already has an alias defined */
408  {
409  mutt_error(_("You already have an alias defined with that name"));
410  goto done;
411  }
412 
413  if (check_alias_name(mutt_buffer_string(buf), fixed->data, fixed->dsize))
414  {
415  switch (mutt_yesorno(_("Warning: This alias name may not work. Fix it?"), MUTT_YES))
416  {
417  case MUTT_YES:
418  mutt_buffer_copy(buf, fixed);
419  goto retry_name;
420  case MUTT_ABORT:
421  goto done;
422  default:; // do nothing
423  }
424  }
425 
426  struct Alias *alias = alias_new();
427  alias->name = mutt_buffer_strdup(buf);
428 
430 
431  if (addr && addr->mailbox)
432  mutt_buffer_strcpy(buf, addr->mailbox);
433  else
434  mutt_buffer_reset(buf);
435 
436  mutt_addrlist_to_intl(al, NULL);
437 
438  do
439  {
440  if ((mutt_buffer_get_field(_("Address: "), buf, MUTT_COMP_NO_FLAGS, false,
441  NULL, NULL, NULL) != 0) ||
443  {
444  alias_free(&alias);
445  goto done;
446  }
447 
449  if (TAILQ_EMPTY(&alias->addr))
450  mutt_beep(false);
451  if (mutt_addrlist_to_intl(&alias->addr, &err))
452  {
453  mutt_error(_("Bad IDN: '%s'"), err);
454  FREE(&err);
455  continue;
456  }
457  } while (TAILQ_EMPTY(&alias->addr));
458 
459  if (addr && addr->personal && !mutt_is_mail_list(addr))
460  mutt_buffer_strcpy(buf, addr->personal);
461  else
462  mutt_buffer_reset(buf);
463 
464  if (mutt_buffer_get_field(_("Personal name: "), buf, MUTT_COMP_NO_FLAGS,
465  false, NULL, NULL, NULL) != 0)
466  {
467  alias_free(&alias);
468  goto done;
469  }
470  mutt_str_replace(&TAILQ_FIRST(&alias->addr)->personal, mutt_buffer_string(buf));
471 
472  mutt_buffer_reset(buf);
473  if (mutt_buffer_get_field(_("Comment: "), buf, MUTT_COMP_NO_FLAGS, false,
474  NULL, NULL, NULL) == 0)
475  {
477  }
478 
479  mutt_buffer_reset(buf);
480  mutt_addrlist_write(&alias->addr, buf->data, buf->dsize, true);
481  prompt = mutt_buffer_pool_get();
482  if (alias->comment)
483  {
484  mutt_buffer_printf(prompt, "[%s = %s # %s] %s", alias->name,
485  mutt_buffer_string(buf), alias->comment, _("Accept?"));
486  }
487  else
488  {
489  mutt_buffer_printf(prompt, "[%s = %s] %s", alias->name,
490  mutt_buffer_string(buf), _("Accept?"));
491  }
493  {
494  alias_free(&alias);
495  goto done;
496  }
497 
498  alias_reverse_add(alias);
499  TAILQ_INSERT_TAIL(&Aliases, alias, entries);
500 
501  const char *const alias_file = cs_subset_path(sub, "alias_file");
502  mutt_buffer_strcpy(buf, alias_file);
503 
504  if (mutt_buffer_get_field(_("Save to file: "), buf, MUTT_COMP_FILE | MUTT_COMP_CLEAR,
505  false, NULL, NULL, NULL) != 0)
506  {
507  goto done;
508  }
509  mutt_expand_path(buf->data, buf->dsize);
510  fp_alias = fopen(mutt_buffer_string(buf), "a+");
511  if (!fp_alias)
512  {
514  goto done;
515  }
516 
517  /* terminate existing file with \n if necessary */
518  if (!mutt_file_seek(fp_alias, 0, SEEK_END))
519  {
520  goto done;
521  }
522  if (ftell(fp_alias) > 0)
523  {
524  if (!mutt_file_seek(fp_alias, -1, SEEK_CUR))
525  {
526  goto done;
527  }
528  if (fread(buf->data, 1, 1, fp_alias) != 1)
529  {
530  mutt_perror(_("Error reading alias file"));
531  goto done;
532  }
533  if (!mutt_file_seek(fp_alias, 0, SEEK_END))
534  {
535  goto done;
536  }
537  if (buf->data[0] != '\n')
538  fputc('\n', fp_alias);
539  }
540 
541  if (check_alias_name(alias->name, NULL, 0))
542  mutt_file_quote_filename(alias->name, buf->data, buf->dsize);
543  else
544  mutt_buffer_strcpy(buf, alias->name);
545 
546  recode_buf(buf->data, buf->dsize);
547  fprintf(fp_alias, "alias %s ", mutt_buffer_string(buf));
548  mutt_buffer_reset(buf);
549 
550  mutt_addrlist_write(&alias->addr, buf->data, buf->dsize, false);
551  recode_buf(buf->data, buf->dsize);
552  write_safe_address(fp_alias, mutt_buffer_string(buf));
553  if (alias->comment)
554  fprintf(fp_alias, " # %s", alias->comment);
555  fputc('\n', fp_alias);
556  if (mutt_file_fsync_close(&fp_alias) != 0)
557  mutt_perror(_("Trouble adding alias"));
558  else
559  mutt_message(_("Alias added"));
560 
561 done:
562  mutt_file_fclose(&fp_alias);
564  mutt_buffer_pool_release(&fixed);
565  mutt_buffer_pool_release(&prompt);
567 }
568 
574 bool mutt_addr_is_user(const struct Address *addr)
575 {
576  if (!addr)
577  {
578  mutt_debug(LL_DEBUG5, "no, NULL address\n");
579  return false;
580  }
581  if (!addr->mailbox)
582  {
583  mutt_debug(LL_DEBUG5, "no, no mailbox\n");
584  return false;
585  }
586 
587  if (mutt_istr_equal(addr->mailbox, Username))
588  {
589  mutt_debug(LL_DEBUG5, "#1 yes, %s = %s\n", addr->mailbox, Username);
590  return true;
591  }
593  {
594  mutt_debug(LL_DEBUG5, "#2 yes, %s = %s @ %s\n", addr->mailbox, Username, ShortHostname);
595  return true;
596  }
597  const char *fqdn = mutt_fqdn(false, NeoMutt->sub);
598  if (string_is_address(addr->mailbox, Username, fqdn))
599  {
600  mutt_debug(LL_DEBUG5, "#3 yes, %s = %s @ %s\n", addr->mailbox, Username, NONULL(fqdn));
601  return true;
602  }
603  fqdn = mutt_fqdn(true, NeoMutt->sub);
604  if (string_is_address(addr->mailbox, Username, fqdn))
605  {
606  mutt_debug(LL_DEBUG5, "#4 yes, %s = %s @ %s\n", addr->mailbox, Username, NONULL(fqdn));
607  return true;
608  }
609 
610  const struct Address *c_from = cs_subset_address(NeoMutt->sub, "from");
611  if (c_from && mutt_istr_equal(c_from->mailbox, addr->mailbox))
612  {
613  mutt_debug(LL_DEBUG5, "#5 yes, %s = %s\n", addr->mailbox, c_from->mailbox);
614  return true;
615  }
616 
617  if (mutt_alternates_match(addr->mailbox))
618  return true;
619 
620  mutt_debug(LL_DEBUG5, "no, all failed\n");
621  return false;
622 }
623 
630 struct Alias *alias_new(void)
631 {
632  struct Alias *a = mutt_mem_calloc(1, sizeof(struct Alias));
633  TAILQ_INIT(&a->addr);
634  return a;
635 }
636 
641 void alias_free(struct Alias **ptr)
642 {
643  if (!ptr || !*ptr)
644  return;
645 
646  struct Alias *alias = *ptr;
647 
648  mutt_debug(LL_NOTIFY, "NT_ALIAS_DELETE: %s\n", alias->name);
649  struct EventAlias ev_a = { alias };
651 
652  FREE(&alias->name);
653  FREE(&alias->comment);
655  FREE(ptr);
656 }
657 
662 void aliaslist_free(struct AliasList *al)
663 {
664  if (!al)
665  return;
666 
667  struct Alias *np = NULL, *tmp = NULL;
668  TAILQ_FOREACH_SAFE(np, al, entries, tmp)
669  {
670  TAILQ_REMOVE(al, np, entries);
671  alias_free(&np);
672  }
673  TAILQ_INIT(al);
674 }
675 
679 void alias_init(void)
680 {
682 }
683 
687 void alias_shutdown(void)
688 {
689  struct Alias *np = NULL;
690  TAILQ_FOREACH(np, &Aliases, entries)
691  {
693  }
696 }
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:737
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:650
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
size_t mutt_addrlist_write(const struct AddressList *al, char *buf, size_t buflen, bool display)
Write an Address to a buffer.
Definition: address.c:1150
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1388
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1305
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1407
Email Address Handling.
void alias_free(struct Alias **ptr)
Free an Alias.
Definition: alias.c:641
struct AliasList Aliases
List of all the user's email aliases.
Definition: alias.c:58
static bool string_is_address(const char *str, const char *user, const char *domain)
Does an email address match a user and domain?
Definition: alias.c:261
static int check_alias_name(const char *s, char *dest, size_t destlen)
Sanity-check an alias name.
Definition: alias.c:215
struct Alias * alias_new(void)
Create a new Alias.
Definition: alias.c:630
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:298
void alias_create(struct AddressList *al, const struct ConfigSubset *sub)
Create a new Alias from an Address.
Definition: alias.c:370
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:574
void alias_init(void)
Set up the Alias globals.
Definition: alias.c:679
struct AddressList * mutt_get_address(struct Envelope *env, const char **prefix)
Get an Address from an Envelope.
Definition: alias.c:330
void mutt_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
Definition: alias.c:312
static void recode_buf(char *buf, size_t buflen)
Convert some text between two character sets.
Definition: alias.c:189
void aliaslist_free(struct AliasList *al)
Free a List of Aliases.
Definition: alias.c:662
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:280
void alias_shutdown(void)
Clean up the Alias globals.
Definition: alias.c:687
static void write_safe_address(FILE *fp, const char *s)
Defang malicious email addresses.
Definition: alias.c:84
static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
Expand aliases, recursively.
Definition: alias.c:102
Representation of a single alias to an email address.
@ NT_ALIAS_DELETE
Alias is about to be deleted.
Definition: alias.h:55
bool mutt_alternates_match(const char *addr)
Compare an Address to the Un/Alternates lists.
Definition: alternates.c:152
Alternate address handling.
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:250
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:430
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:158
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:445
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:81
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: helpers.c:49
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:130
Structs that make up an email.
Enter a string.
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
size_t mutt_file_quote_filename(const char *filename, char *buf, size_t buflen)
Quote a filename to survive the shell's quoting rules.
Definition: file.c:848
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:690
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:168
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t -.
Definition: maillist.c:44
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
Convenience wrapper for the gui headers.
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
@ LL_NOTIFY
Log of notifications.
Definition: logging.h:45
Handle mailing lists.
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:43
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:752
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:71
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
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
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:629
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
Many unsorted constants and some structs.
#define MUTT_COMP_FILE
File completion (in browser)
Definition: mutt.h:55
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
Hundreds of global variables to back the user variables.
char * ShortHostname
Short version of the hostname.
Definition: mutt_globals.h:50
char * Username
User's login name.
Definition: mutt_globals.h:52
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:123
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user's real name in /etc/passwd.
Definition: muttlib.c:361
Some miscellaneous functions.
@ NT_ALIAS
Alias has changed, NotifyAlias, EventAlias.
Definition: notify_type.h:37
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:194
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
#define STAILQ_INIT(head)
Definition: queue.h:372
#define TAILQ_INIT(head)
Definition: queue.h:765
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
#define TAILQ_PREV(elm, headname, field)
Definition: queue.h:834
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_EMPTY(head)
Definition: queue.h:721
#define TAILQ_INSERT_BEFORE(listelm, elm, field)
Definition: queue.h:786
void alias_reverse_add(struct Alias *alias)
Add an email address lookup for an Alias.
Definition: reverse.c:61
void alias_reverse_shutdown(void)
Clear up the Reverse Alias Hash Table.
Definition: reverse.c:52
void alias_reverse_delete(struct Alias *alias)
Remove an email address lookup for an Alias.
Definition: reverse.c:83
void alias_reverse_init(void)
Set up the Reverse Alias Hash Table.
Definition: reverse.c:42
Manage alias reverse lookups.
Convenience wrapper for the send headers.
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:698
Key value store.
#define NONULL(x)
Definition: string2.h:37
An email address.
Definition: address.h:36
bool group
Group mailbox?
Definition: address.h:39
char * mailbox
Mailbox and host address.
Definition: address.h:38
char * personal
Real name of address.
Definition: address.h:37
A shortcut for an email address or addresses.
Definition: alias.h:34
char * comment
Free-form comment string.
Definition: alias.h:37
char * name
Short name.
Definition: alias.h:35
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:36
String manipulation buffer.
Definition: buffer.h:34
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
A set of inherited config items.
Definition: subset.h:47
The header of an Email.
Definition: envelope.h:57
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:64
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition: envelope.h:65
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
An alias-change event.
Definition: alias.h:64
struct Alias * alias
Alias that changed.
Definition: alias.h:65
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct Notify * notify
Notifications handler.
Definition: neomutt.h:38
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39