NeoMutt  2024-02-01-23-g345d7b
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
alias.c File Reference

Representation of a single alias to an email address. More...

#include "config.h"
#include <stddef.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "alias.h"
#include "lib.h"
#include "browser/lib.h"
#include "editor/lib.h"
#include "history/lib.h"
#include "question/lib.h"
#include "send/lib.h"
#include "alternates.h"
#include "globals.h"
#include "maillist.h"
#include "muttlib.h"
#include "reverse.h"
+ Include dependency graph for alias.c:

Go to the source code of this file.

Functions

static void write_safe_address (FILE *fp, const char *s)
 Defang malicious email addresses.
 
static void expand_aliases_r (struct AddressList *al, struct ListHead *expn)
 Expand aliases, recursively.
 
static void recode_buf (struct Buffer *buf)
 Convert some text between two character sets.
 
static int check_alias_name (const char *s, char *dest, size_t destlen)
 Sanity-check an alias name.
 
static bool string_is_address (const char *str, const char *user, const char *domain)
 Does an email address match a user and domain?
 
struct AddressList * alias_lookup (const char *name)
 Find an Alias.
 
void mutt_expand_aliases (struct AddressList *al)
 Expand aliases in a List of Addresses.
 
void mutt_expand_aliases_env (struct Envelope *env)
 Expand aliases in all the fields of an Envelope.
 
struct AddressList * mutt_get_address (struct Envelope *env, const char **prefix)
 Get an Address from an Envelope.
 
void alias_create (struct AddressList *al, const struct ConfigSubset *sub)
 Create a new Alias from an Address.
 
bool mutt_addr_is_user (const struct Address *addr)
 Does the address belong to the user.
 
struct Aliasalias_new (void)
 Create a new Alias.
 
void alias_free (struct Alias **ptr)
 Free an Alias.
 
void aliaslist_clear (struct AliasList *al)
 Empty a List of Aliases.
 
void alias_init (void)
 Set up the Alias globals.
 
void alias_cleanup (void)
 Clean up the Alias globals.
 

Variables

struct AliasList Aliases = TAILQ_HEAD_INITIALIZER(Aliases)
 List of all the user's email aliases.
 

Detailed Description

Representation of a single alias to an email address.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Federico Kircheis
  • Anna Figueiredo Gomes
  • Dennis Schön

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file alias.c.

Function Documentation

◆ write_safe_address()

static void write_safe_address ( FILE *  fp,
const char *  s 
)
static

Defang malicious email addresses.

Parameters
fpFile to write to
sEmail address to defang

if someone has an address like From: John /bin/rm -f ~ Doe john..nosp@m.doe@.nosp@m.examp.nosp@m.le.c.nosp@m.om and the user creates an alias for this, NeoMutt could wind up executing the backticks because it writes aliases like alias me John /bin/rm -f ~ Doe john..nosp@m.doe@.nosp@m.examp.nosp@m.le.c.nosp@m.om 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: John `/bin/rm -f ~` Doe john..nosp@m.doe@.nosp@m.examp.nosp@m.le.c.nosp@m.om since that would get aliased as alias me John \`/bin/rm -f ~\` Doe john..nosp@m.doe@.nosp@m.examp.nosp@m.le.c.nosp@m.om 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 88 of file alias.c.

89{
90 while (*s)
91 {
92 if ((*s == '\\') || (*s == '`') || (*s == '\'') || (*s == '"') || (*s == '$'))
93 fputc('\\', fp);
94 fputc(*s, fp);
95 s++;
96 }
97}
+ Here is the caller graph for this function:

◆ expand_aliases_r()

static void expand_aliases_r ( struct AddressList *  al,
struct ListHead *  expn 
)
static

Expand aliases, recursively.

Parameters
[in]alAddress List
[out]expnAlias List

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

Definition at line 106 of file alias.c.

107{
108 struct Address *a = TAILQ_FIRST(al);
109 while (a)
110 {
111 if (!a->group && !a->personal && a->mailbox && !buf_find_char(a->mailbox, '@'))
112 {
113 struct AddressList *alias = alias_lookup(buf_string(a->mailbox));
114 if (alias)
115 {
116 bool duplicate = false;
117 struct ListNode *np = NULL;
118 STAILQ_FOREACH(np, expn, entries)
119 {
120 if (mutt_str_equal(buf_string(a->mailbox), np->data)) /* alias already found */
121 {
122 mutt_debug(LL_DEBUG1, "loop in alias found for '%s'\n", buf_string(a->mailbox));
123 duplicate = true;
124 break;
125 }
126 }
127
128 if (duplicate)
129 {
130 // We've already seen this alias, so drop it
131 struct Address *next = TAILQ_NEXT(a, entries);
132 TAILQ_REMOVE(al, a, entries);
133 mutt_addr_free(&a);
134 a = next;
135 continue;
136 }
137
138 // Keep a list of aliases that we've already seen
140
141 /* The alias may expand to several addresses,
142 * some of which may themselves be aliases.
143 * Create a copy and recursively expand any aliases within. */
144 struct AddressList copy = TAILQ_HEAD_INITIALIZER(copy);
145 mutt_addrlist_copy(&copy, alias, false);
146 expand_aliases_r(&copy, expn);
147
148 /* Next, move the expanded addresses
149 * from the copy into the original list (before the alias) */
150 struct Address *a2 = NULL, *tmp = NULL;
151 TAILQ_FOREACH_SAFE(a2, &copy, entries, tmp)
152 {
153 TAILQ_INSERT_BEFORE(a, a2, entries);
154 }
155 a = TAILQ_PREV(a, AddressList, entries);
156 // Finally, remove the alias itself
157 struct Address *next = TAILQ_NEXT(a, entries);
158 TAILQ_REMOVE(al, next, entries);
159 mutt_addr_free(&next);
160 }
161 else
162 {
163 struct passwd *pw = getpwnam(buf_string(a->mailbox));
164 if (pw)
165 {
166 char namebuf[256] = { 0 };
167
168 mutt_gecos_name(namebuf, sizeof(namebuf), pw);
169 a->personal = buf_new(namebuf);
170 }
171 }
172 }
173 a = TAILQ_NEXT(a, entries);
174 }
175
176 const char *fqdn = NULL;
177 const bool c_use_domain = cs_subset_bool(NeoMutt->sub, "use_domain");
178 if (c_use_domain && (fqdn = mutt_fqdn(true, NeoMutt->sub)))
179 {
180 /* now qualify all local addresses */
181 mutt_addrlist_qualify(al, fqdn);
182 }
183}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:765
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:680
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:462
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:282
static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
Expand aliases, recursively.
Definition: alias.c:106
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:321
const char * buf_find_char(const struct Buffer *buf, const char c)
Return a pointer to a char found in the buffer.
Definition: buffer.c:672
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:588
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:97
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:48
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:709
char * mutt_gecos_name(char *dest, size_t destlen, struct passwd *pw)
Lookup a user's real name in /etc/passwd.
Definition: muttlib.c:370
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
#define TAILQ_PREV(elm, headname, field)
Definition: queue.h:834
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:637
#define TAILQ_INSERT_BEFORE(listelm, elm, field)
Definition: queue.h:786
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:706
An email address.
Definition: address.h:36
struct Buffer * personal
Real name of address.
Definition: address.h:37
bool group
Group mailbox?
Definition: address.h:39
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
Container for Accounts, Notifications.
Definition: neomutt.h:41
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ recode_buf()

static void recode_buf ( struct Buffer buf)
static

Convert some text between two character sets.

Parameters
bufBuffer to convert

The 'from' charset is controlled by the 'charset' config variable. The 'to' charset is controlled by the 'config_charset' config variable.

Definition at line 192 of file alias.c.

193{
194 const char *const c_config_charset = cs_subset_string(NeoMutt->sub, "config_charset");
195 if (!c_config_charset || !cc_charset())
196 return;
197
198 char *s = buf_strdup(buf);
199 if (!s)
200 return;
201 if (mutt_ch_convert_string(&s, cc_charset(), c_config_charset, MUTT_ICONV_NO_FLAGS) == 0)
202 buf_strcpy(buf, s);
203 FREE(&s);
204}
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:412
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:292
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
#define FREE(x)
Definition: memory.h:45
int mutt_ch_convert_string(char **ps, const char *from, const char *to, uint8_t flags)
Convert a string between encodings.
Definition: charset.c:830
#define MUTT_ICONV_NO_FLAGS
No flags are set.
Definition: charset.h:72
+ 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 217 of file alias.c.

218{
219 wchar_t wc = 0;
220 mbstate_t mbstate = { 0 };
221 size_t l;
222 int rc = 0;
223 bool dry = !dest || !destlen;
224
225 if (!dry)
226 destlen--;
227 for (; s && *s && (dry || destlen) && (l = mbrtowc(&wc, s, MB_CUR_MAX, &mbstate)) != 0;
228 s += l, destlen -= l)
229 {
230 bool bad = (l == ICONV_ILLEGAL_SEQ) || (l == ICONV_BUF_TOO_SMALL); /* 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 == ICONV_ILLEGAL_SEQ)
241 memset(&mbstate, 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}
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition: charset.h:106
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:104
+ Here is the caller graph for this function:

◆ string_is_address()

static bool string_is_address ( const char *  str,
const char *  user,
const char *  domain 
)
static

Does an email address match a user and domain?

Parameters
strAddress string to test
userUser name
domainDomain name
Return values
trueThey match

Definition at line 263 of file alias.c.

264{
265 char buf[1024] = { 0 };
266
267 snprintf(buf, sizeof(buf), "%s@%s", NONULL(user), NONULL(domain));
268 if (mutt_istr_equal(str, buf))
269 return true;
270
271 return false;
272}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:721
#define NONULL(x)
Definition: string2.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_lookup()

struct AddressList * alias_lookup ( const char *  name)

Find an Alias.

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

Definition at line 282 of file alias.c.

283{
284 struct Alias *a = NULL;
285
286 TAILQ_FOREACH(a, &Aliases, entries)
287 {
288 if (mutt_istr_equal(name, a->name))
289 return &a->addr;
290 }
291 return NULL;
292}
struct AliasList Aliases
List of all the user's email aliases.
Definition: alias.c:62
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
A shortcut for an email address or addresses.
Definition: alias.h:35
char * name
Short name.
Definition: alias.h:36
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_expand_aliases()

void mutt_expand_aliases ( struct AddressList *  al)

Expand aliases in a List of Addresses.

Parameters
alAddressList

Duplicate addresses are dropped

Definition at line 300 of file alias.c.

301{
302 // previously expanded aliases to avoid loops
303 struct ListHead expn = STAILQ_HEAD_INITIALIZER(expn);
304
305 expand_aliases_r(al, &expn);
306 mutt_list_free(&expn);
308}
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1401
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_expand_aliases_env()

void mutt_expand_aliases_env ( struct Envelope env)

Expand aliases in all the fields of an Envelope.

Parameters
envEnvelope to expand

Definition at line 314 of file alias.c.

315{
317 mutt_expand_aliases(&env->to);
318 mutt_expand_aliases(&env->cc);
322}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:300
struct AddressList to
Email's 'To' list.
Definition: envelope.h: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
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_get_address()

struct AddressList * mutt_get_address ( struct Envelope env,
const char **  prefix 
)

Get an Address from an Envelope.

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

Definition at line 332 of file alias.c.

333{
334 struct AddressList *al = NULL;
335 const char *pfx = NULL;
336
338 {
339 if (!TAILQ_EMPTY(&env->to) && !mutt_is_mail_list(TAILQ_FIRST(&env->to)))
340 {
341 pfx = "To";
342 al = &env->to;
343 }
344 else
345 {
346 pfx = "Cc";
347 al = &env->cc;
348 }
349 }
350 else if (!TAILQ_EMPTY(&env->reply_to) && !mutt_is_mail_list(TAILQ_FIRST(&env->reply_to)))
351 {
352 pfx = "Reply-To";
353 al = &env->reply_to;
354 }
355 else
356 {
357 al = &env->from;
358 pfx = "From";
359 }
360
361 if (prefix)
362 *prefix = pfx;
363
364 return al;
365}
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:605
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:45
#define TAILQ_EMPTY(head)
Definition: queue.h:721
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_create()

void alias_create ( struct AddressList *  al,
const struct ConfigSubset sub 
)

Create a new Alias from an Address.

Parameters
alAddress to use
subConfig items

Definition at line 372 of file alias.c.

373{
374 struct Buffer *buf = buf_pool_get();
375 struct Buffer *fixed = buf_pool_get();
376 struct Buffer *prompt = NULL;
377 struct Buffer *tmp = buf_pool_get();
378
379 struct Address *addr = NULL;
380 char *pc = NULL;
381 char *err = NULL;
382 FILE *fp_alias = NULL;
383
384 if (al)
385 {
386 addr = TAILQ_FIRST(al);
387 if (addr && addr->mailbox)
388 {
389 buf_copy(tmp, addr->mailbox);
390 pc = strchr(buf_string(tmp), '@');
391 if (pc)
392 *pc = '\0';
393 }
394 }
395
396 /* Don't suggest a bad alias name in the event of a strange local part. */
397 check_alias_name(buf_string(tmp), buf->data, buf->dsize);
398
399retry_name:
400 /* L10N: prompt to add a new alias */
401 if ((mw_get_field(_("Alias as: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
402 buf_is_empty(buf))
403 {
404 goto done;
405 }
406
407 /* check to see if the user already has an alias defined */
408 if (alias_lookup(buf_string(buf)))
409 {
410 mutt_error(_("You already have an alias defined with that name"));
411 goto done;
412 }
413
414 if (check_alias_name(buf_string(buf), fixed->data, fixed->dsize))
415 {
416 switch (query_yesorno(_("Warning: This alias name may not work. Fix it?"), MUTT_YES))
417 {
418 case MUTT_YES:
419 buf_copy(buf, fixed);
420 goto retry_name;
421 case MUTT_ABORT:
422 goto done;
423 default:; // do nothing
424 }
425 }
426
427 struct Alias *alias = alias_new();
428 alias->name = buf_strdup(buf);
429
431
432 if (addr && addr->mailbox)
433 buf_copy(buf, addr->mailbox);
434 else
435 buf_reset(buf);
436
437 mutt_addrlist_to_intl(al, NULL);
438
439 do
440 {
441 if ((mw_get_field(_("Address: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
442 buf_is_empty(buf))
443 {
444 alias_free(&alias);
445 goto done;
446 }
447
448 mutt_addrlist_parse(&alias->addr, buf_string(buf));
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 buf_copy(buf, addr->personal);
461 else
462 buf_reset(buf);
463
464 if (mw_get_field(_("Personal name: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
465 {
466 alias_free(&alias);
467 goto done;
468 }
469
470 TAILQ_FIRST(&alias->addr)->personal = buf_new(buf_string(buf));
471
472 buf_reset(buf);
473 if (mw_get_field(_("Comment: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
474 {
475 mutt_str_replace(&alias->comment, buf_string(buf));
476 }
477
478 buf_reset(buf);
479 if (mw_get_field(_("Tags (comma-separated): "), buf, MUTT_COMP_NO_FLAGS,
480 HC_OTHER, NULL, NULL) == 0)
481 {
482 parse_alias_tags(buf_string(buf), &alias->tags);
483 }
484
485 buf_reset(buf);
486 mutt_addrlist_write(&alias->addr, buf, true);
487 prompt = buf_pool_get();
488
489 buf_printf(prompt, "alias %s %s", alias->name, buf_string(buf));
490
491 bool has_tags = STAILQ_FIRST(&alias->tags);
492
493 if (alias->comment || has_tags)
494 buf_addstr(prompt, " #");
495
496 if (alias->comment)
497 buf_add_printf(prompt, " %s", alias->comment);
498
499 if (has_tags)
500 {
501 if (STAILQ_FIRST(&alias->tags))
502 {
503 buf_addstr(prompt, " tags:");
504 alias_tags_to_buffer(&alias->tags, prompt);
505 }
506 }
507
508 buf_add_printf(prompt, "\n%s", _("Accept?"));
509
510 if (query_yesorno(buf_string(prompt), MUTT_YES) != MUTT_YES)
511 {
512 alias_free(&alias);
513 goto done;
514 }
515
516 alias_reverse_add(alias);
517 TAILQ_INSERT_TAIL(&Aliases, alias, entries);
518
519 const char *const c_alias_file = cs_subset_path(sub, "alias_file");
520 buf_strcpy(buf, c_alias_file);
521
522 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
523 if (mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
524 &CompleteFileOps, &cdata) != 0)
525 {
526 goto done;
527 }
528 mutt_expand_path(buf->data, buf->dsize);
529 fp_alias = mutt_file_fopen(buf_string(buf), "a+");
530 if (!fp_alias)
531 {
532 mutt_perror("%s", buf_string(buf));
533 goto done;
534 }
535
536 /* terminate existing file with \n if necessary */
537 if (!mutt_file_seek(fp_alias, 0, SEEK_END))
538 {
539 goto done;
540 }
541 if (ftell(fp_alias) > 0)
542 {
543 if (!mutt_file_seek(fp_alias, -1, SEEK_CUR))
544 {
545 goto done;
546 }
547 if (fread(buf->data, 1, 1, fp_alias) != 1)
548 {
549 mutt_perror(_("Error reading alias file"));
550 goto done;
551 }
552 if (!mutt_file_seek(fp_alias, 0, SEEK_END))
553 {
554 goto done;
555 }
556 if (buf->data[0] != '\n')
557 fputc('\n', fp_alias);
558 }
559
560 if (check_alias_name(alias->name, NULL, 0))
561 mutt_file_quote_filename(alias->name, buf->data, buf->dsize);
562 else
563 buf_strcpy(buf, alias->name);
564
565 recode_buf(buf);
566 fprintf(fp_alias, "alias %s ", buf_string(buf));
567 buf_reset(buf);
568
569 mutt_addrlist_write(&alias->addr, buf, false);
570 recode_buf(buf);
571 write_safe_address(fp_alias, buf_string(buf));
572 if (alias->comment)
573 fprintf(fp_alias, " # %s", alias->comment);
574 if (STAILQ_FIRST(&alias->tags))
575 {
576 fprintf(fp_alias, " tags:");
577
578 struct Tag *tag = NULL;
579 STAILQ_FOREACH(tag, &alias->tags, entries)
580 {
581 fprintf(fp_alias, "%s", tag->name);
582 if (STAILQ_NEXT(tag, entries))
583 fprintf(fp_alias, ",");
584 }
585 }
586 fputc('\n', fp_alias);
587 if (mutt_file_fsync_close(&fp_alias) != 0)
588 mutt_perror(_("Trouble adding alias"));
589 else
590 mutt_message(_("Alias added"));
591
592done:
593 mutt_file_fclose(&fp_alias);
594 buf_pool_release(&buf);
595 buf_pool_release(&fixed);
596 buf_pool_release(&prompt);
597 buf_pool_release(&tmp);
598}
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1382
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1210
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:480
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1297
void parse_alias_tags(const char *tags, struct TagList *tl)
Parse a comma-separated list of tags.
Definition: commands.c:65
void alias_tags_to_buffer(struct TagList *tl, struct Buffer *buf)
Write a comma-separated list of tags to a Buffer.
Definition: commands.c:49
void alias_free(struct Alias **ptr)
Free an Alias.
Definition: alias.c:677
static int check_alias_name(const char *s, char *dest, size_t destlen)
Sanity-check an alias name.
Definition: alias.c:217
static void recode_buf(struct Buffer *buf)
Convert some text between two character sets.
Definition: alias.c:192
struct Alias * alias_new(void)
Create a new Alias.
Definition: alias.c:665
static void write_safe_address(FILE *fp, const char *s)
Defang malicious email addresses.
Definition: alias.c:88
const struct CompleteOps CompleteFileOps
Auto-Completion of Files.
Definition: complete.c:153
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:178
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:221
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:93
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:308
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:243
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:618
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:169
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:68
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:929
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:771
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:188
#define mutt_file_fclose(FP)
Definition: file.h:148
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:147
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition: window.c:274
#define mutt_error(...)
Definition: logging2.h:92
#define mutt_message(...)
Definition: logging2.h:91
#define mutt_perror(...)
Definition: logging2.h:93
@ HC_FILE
Files.
Definition: lib.h:54
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:56
#define _(a)
Definition: message.h:28
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:329
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:57
char * mutt_expand_path(char *buf, size_t buflen)
Create the canonical path.
Definition: muttlib.c:126
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition: question.c:334
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:809
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
void alias_reverse_add(struct Alias *alias)
Add an email address lookup for an Alias.
Definition: reverse.c:61
struct TagList tags
Tags.
Definition: alias.h:39
char * comment
Free-form comment string.
Definition: alias.h:38
String manipulation buffer.
Definition: buffer.h:36
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
Input for the file completion function.
Definition: curs_lib.h:40
LinkedList Tag Element.
Definition: tags.h:42
char * name
Tag name.
Definition: tags.h:43
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_addr_is_user()

bool mutt_addr_is_user ( const struct Address addr)

Does the address belong to the user.

Parameters
addrAddress to check
Return values
trueThe given address belongs to the user

Definition at line 605 of file alias.c.

606{
607 if (!addr)
608 {
609 mutt_debug(LL_DEBUG5, "no, NULL address\n");
610 return false;
611 }
612 if (!addr->mailbox)
613 {
614 mutt_debug(LL_DEBUG5, "no, no mailbox\n");
615 return false;
616 }
617
619 {
620 mutt_debug(LL_DEBUG5, "#1 yes, %s = %s\n", buf_string(addr->mailbox), Username);
621 return true;
622 }
624 {
625 mutt_debug(LL_DEBUG5, "#2 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
627 return true;
628 }
629 const char *fqdn = mutt_fqdn(false, NeoMutt->sub);
630 if (string_is_address(buf_string(addr->mailbox), Username, fqdn))
631 {
632 mutt_debug(LL_DEBUG5, "#3 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
633 Username, NONULL(fqdn));
634 return true;
635 }
636 fqdn = mutt_fqdn(true, NeoMutt->sub);
637 if (string_is_address(buf_string(addr->mailbox), Username, fqdn))
638 {
639 mutt_debug(LL_DEBUG5, "#4 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
640 Username, NONULL(fqdn));
641 return true;
642 }
643
644 const struct Address *c_from = cs_subset_address(NeoMutt->sub, "from");
645 if (c_from && mutt_istr_equal(buf_string(c_from->mailbox), buf_string(addr->mailbox)))
646 {
647 mutt_debug(LL_DEBUG5, "#5 yes, %s = %s\n", buf_string(addr->mailbox),
648 buf_string(c_from->mailbox));
649 return true;
650 }
651
653 return true;
654
655 mutt_debug(LL_DEBUG5, "no, all failed\n");
656 return false;
657}
static bool string_is_address(const char *str, const char *user, const char *domain)
Does an email address match a user and domain?
Definition: alias.c:263
bool mutt_alternates_match(const char *addr)
Compare an Address to the Un/Alternates lists.
Definition: alternates.c:155
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: config_type.c:264
char * ShortHostname
Short version of the hostname.
Definition: globals.c:39
char * Username
User's login name.
Definition: globals.c:41
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_new()

struct Alias * alias_new ( void  )

Create a new Alias.

Return values
ptrNewly allocated Alias

Free the result with alias_free()

Definition at line 665 of file alias.c.

666{
667 struct Alias *a = mutt_mem_calloc(1, sizeof(struct Alias));
668 TAILQ_INIT(&a->addr);
669 STAILQ_INIT(&a->tags);
670 return a;
671}
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define STAILQ_INIT(head)
Definition: queue.h:372
#define TAILQ_INIT(head)
Definition: queue.h:765
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_free()

void alias_free ( struct Alias **  ptr)

Free an Alias.

Parameters
[out]ptrAlias to free

Definition at line 677 of file alias.c.

678{
679 if (!ptr || !*ptr)
680 return;
681
682 struct Alias *alias = *ptr;
683
684 mutt_debug(LL_NOTIFY, "NT_ALIAS_DELETE: %s\n", alias->name);
685 struct EventAlias ev_a = { alias };
687
688 FREE(&alias->name);
689 FREE(&alias->comment);
692
693 FREE(ptr);
694}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1464
@ NT_ALIAS_DELETE
Alias is about to be deleted.
Definition: alias.h:57
@ LL_NOTIFY
Log of notifications.
Definition: logging2.h:48
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition: notify.c:173
@ NT_ALIAS
Alias has changed, NotifyAlias, EventAlias.
Definition: notify_type.h:37
An alias-change event.
Definition: alias.h:66
struct Alias * alias
Alias that changed.
Definition: alias.h:67
struct Notify * notify
Notifications handler.
Definition: neomutt.h:42
void driver_tags_free(struct TagList *tl)
Free tags from a header.
Definition: tags.c:131
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ aliaslist_clear()

void aliaslist_clear ( struct AliasList *  al)

Empty a List of Aliases.

Parameters
alAliasList to empty

Each Alias will be freed and the AliasList will be left empty.

Definition at line 702 of file alias.c.

703{
704 if (!al)
705 return;
706
707 struct Alias *np = NULL, *tmp = NULL;
708 TAILQ_FOREACH_SAFE(np, al, entries, tmp)
709 {
710 TAILQ_REMOVE(al, np, entries);
711 alias_free(&np);
712 }
713 TAILQ_INIT(al);
714}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_init()

void alias_init ( void  )

Set up the Alias globals.

Definition at line 719 of file alias.c.

720{
722}
void alias_reverse_init(void)
Set up the Reverse Alias Hash Table.
Definition: reverse.c:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_cleanup()

void alias_cleanup ( void  )

Clean up the Alias globals.

Definition at line 727 of file alias.c.

728{
729 struct Alias *np = NULL;
730 TAILQ_FOREACH(np, &Aliases, entries)
731 {
733 }
736}
void aliaslist_clear(struct AliasList *al)
Empty a List of Aliases.
Definition: alias.c:702
void alias_reverse_shutdown(void)
Clear up the Reverse Alias Hash Table.
Definition: reverse.c:52
void alias_reverse_delete(struct Alias *alias)
Remove an email address lookup for an Alias.
Definition: reverse.c:83
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ Aliases

struct AliasList Aliases = TAILQ_HEAD_INITIALIZER(Aliases)

List of all the user's email aliases.

Definition at line 62 of file alias.c.