NeoMutt  2024-11-14-138-ge5ca67
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
lib.h File Reference

Email Aliases. More...

#include <stdbool.h>
#include <stdint.h>
#include "core/lib.h"
#include "expando.h"
+ Include dependency graph for lib.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void alias_init (void)
 Set up the Alias globals.
 
void alias_cleanup (void)
 Clean up the Alias globals.
 
void alias_create (struct AddressList *al, const struct ConfigSubset *sub)
 Create a new Alias from an Address.
 
struct AddressList * alias_lookup (const char *name)
 Find an Alias.
 
bool mutt_addr_is_user (const struct Address *addr)
 Does the address belong to the user.
 
void mutt_expand_aliases_env (struct Envelope *env)
 Expand aliases in all the fields of an Envelope.
 
void mutt_expand_aliases (struct AddressList *al)
 Expand aliases in a List of Addresses.
 
struct AddressList * mutt_get_address (struct Envelope *env, const char **prefix)
 Get an Address from an Envelope.
 
enum CommandResult parse_alias (struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
 Parse the 'alias' command - Implements Command::parse() -.
 
enum CommandResult parse_unalias (struct Buffer *buf, struct Buffer *s, intptr_t data, struct Buffer *err)
 Parse the 'unalias' command - Implements Command::parse() -.
 
void alias_tags_to_buffer (struct TagList *tl, struct Buffer *buf)
 Write a comma-separated list of tags to a Buffer.
 
void parse_alias_comments (struct Alias *alias, const char *com)
 Parse the alias/query comment field.
 
void parse_alias_tags (const char *tags, struct TagList *tl)
 Parse a comma-separated list of tags.
 
int alias_complete (struct Buffer *buf, struct ConfigSubset *sub)
 Alias completion routine.
 
void alias_dialog (struct Mailbox *m, struct ConfigSubset *sub)
 Open the aliases dialog.
 
int query_complete (struct Buffer *buf, struct ConfigSubset *sub)
 Perform auto-complete using an Address Query.
 
void query_index (struct Mailbox *m, struct ConfigSubset *sub)
 Perform an Alias Query and display the results.
 
struct Addressalias_reverse_lookup (const struct Address *addr)
 Does the user have an alias for the given address.
 

Variables

const struct CompleteOps CompleteAliasOps
 Auto-Completion of Aliases.
 

Detailed Description

Email Aliases.

Authors
  • Richard Russon

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 lib.h.

Function Documentation

◆ alias_init()

void alias_init ( void  )

Set up the Alias globals.

Definition at line 714 of file alias.c.

715{
717}
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 722 of file alias.c.

723{
724 struct Alias *np = NULL;
725 TAILQ_FOREACH(np, &Aliases, entries)
726 {
728 }
731}
struct AliasList Aliases
List of all the user's email aliases.
Definition: alias.c:62
void aliaslist_clear(struct AliasList *al)
Empty a List of Aliases.
Definition: alias.c:697
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:743
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
A shortcut for an email address or addresses.
Definition: alias.h:35
+ 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 367 of file alias.c.

368{
369 struct Buffer *buf = buf_pool_get();
370 struct Buffer *fixed = buf_pool_get();
371 struct Buffer *prompt = NULL;
372 struct Buffer *tmp = buf_pool_get();
373
374 struct Address *addr = NULL;
375 char *pc = NULL;
376 char *err = NULL;
377 FILE *fp_alias = NULL;
378
379 if (al)
380 {
381 addr = TAILQ_FIRST(al);
382 if (addr && addr->mailbox)
383 {
384 buf_copy(tmp, addr->mailbox);
385 pc = strchr(buf_string(tmp), '@');
386 if (pc)
387 *pc = '\0';
388 }
389 }
390
391 /* Don't suggest a bad alias name in the event of a strange local part. */
392 check_alias_name(buf_string(tmp), buf);
393
394retry_name:
395 /* L10N: prompt to add a new alias */
396 if ((mw_get_field(_("Alias as: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
397 buf_is_empty(buf))
398 {
399 goto done;
400 }
401
402 /* check to see if the user already has an alias defined */
403 if (alias_lookup(buf_string(buf)))
404 {
405 mutt_error(_("You already have an alias defined with that name"));
406 goto done;
407 }
408
409 if (check_alias_name(buf_string(buf), fixed))
410 {
411 switch (query_yesorno(_("Warning: This alias name may not work. Fix it?"), MUTT_YES))
412 {
413 case MUTT_YES:
414 buf_copy(buf, fixed);
415 goto retry_name;
416 case MUTT_ABORT:
417 goto done;
418 default:; // do nothing
419 }
420 }
421
422 struct Alias *alias = alias_new();
423 alias->name = buf_strdup(buf);
424
426
427 if (addr && addr->mailbox)
428 buf_copy(buf, addr->mailbox);
429 else
430 buf_reset(buf);
431
432 mutt_addrlist_to_intl(al, NULL);
433
434 do
435 {
436 if ((mw_get_field(_("Address: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
437 buf_is_empty(buf))
438 {
439 alias_free(&alias);
440 goto done;
441 }
442
443 mutt_addrlist_parse(&alias->addr, buf_string(buf));
444 if (TAILQ_EMPTY(&alias->addr))
445 mutt_beep(false);
446 if (mutt_addrlist_to_intl(&alias->addr, &err))
447 {
448 mutt_error(_("Bad IDN: '%s'"), err);
449 FREE(&err);
450 continue;
451 }
452 } while (TAILQ_EMPTY(&alias->addr));
453
454 if (addr && addr->personal && !mutt_is_mail_list(addr))
455 buf_copy(buf, addr->personal);
456 else
457 buf_reset(buf);
458
459 if (mw_get_field(_("Personal name: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
460 {
461 alias_free(&alias);
462 goto done;
463 }
464
465 TAILQ_FIRST(&alias->addr)->personal = buf_new(buf_string(buf));
466
467 buf_reset(buf);
468 if (mw_get_field(_("Comment: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0)
469 {
470 mutt_str_replace(&alias->comment, buf_string(buf));
471 }
472
473 buf_reset(buf);
474 if (mw_get_field(_("Tags (comma-separated): "), buf, MUTT_COMP_NO_FLAGS,
475 HC_OTHER, NULL, NULL) == 0)
476 {
477 parse_alias_tags(buf_string(buf), &alias->tags);
478 }
479
480 buf_reset(buf);
481 mutt_addrlist_write(&alias->addr, buf, true);
482 prompt = buf_pool_get();
483
484 buf_printf(prompt, "alias %s %s", alias->name, buf_string(buf));
485
486 bool has_tags = STAILQ_FIRST(&alias->tags);
487
488 if (alias->comment || has_tags)
489 buf_addstr(prompt, " #");
490
491 if (alias->comment)
492 buf_add_printf(prompt, " %s", alias->comment);
493
494 if (has_tags)
495 {
496 if (STAILQ_FIRST(&alias->tags))
497 {
498 buf_addstr(prompt, " tags:");
499 alias_tags_to_buffer(&alias->tags, prompt);
500 }
501 }
502
503 buf_add_printf(prompt, "\n%s", _("Accept?"));
504
505 if (query_yesorno(buf_string(prompt), MUTT_YES) != MUTT_YES)
506 {
507 alias_free(&alias);
508 goto done;
509 }
510
511 alias_reverse_add(alias);
512 TAILQ_INSERT_TAIL(&Aliases, alias, entries);
513
514 const char *const c_alias_file = cs_subset_path(sub, "alias_file");
515 buf_strcpy(buf, c_alias_file);
516
517 struct FileCompletionData cdata = { false, NULL, NULL, NULL };
518 if (mw_get_field(_("Save to file: "), buf, MUTT_COMP_CLEAR, HC_FILE,
519 &CompleteFileOps, &cdata) != 0)
520 {
521 goto done;
522 }
523 buf_expand_path(buf);
524 fp_alias = mutt_file_fopen(buf_string(buf), "a+");
525 if (!fp_alias)
526 {
527 mutt_perror("%s", buf_string(buf));
528 goto done;
529 }
530
531 /* terminate existing file with \n if necessary */
532 if (!mutt_file_seek(fp_alias, 0, SEEK_END))
533 {
534 goto done;
535 }
536 if (ftell(fp_alias) > 0)
537 {
538 if (!mutt_file_seek(fp_alias, -1, SEEK_CUR))
539 {
540 goto done;
541 }
542 if (fread(buf->data, 1, 1, fp_alias) != 1)
543 {
544 mutt_perror(_("Error reading alias file"));
545 goto done;
546 }
547 if (!mutt_file_seek(fp_alias, 0, SEEK_END))
548 {
549 goto done;
550 }
551 if (buf->data[0] != '\n')
552 fputc('\n', fp_alias);
553 }
554
555 if (check_alias_name(alias->name, NULL))
556 buf_quote_filename(buf, alias->name, true);
557 else
558 buf_strcpy(buf, alias->name);
559
560 recode_buf(buf);
561 fprintf(fp_alias, "alias %s ", buf_string(buf));
562 buf_reset(buf);
563
564 mutt_addrlist_write(&alias->addr, buf, false);
565 recode_buf(buf);
566 write_safe_address(fp_alias, buf_string(buf));
567 if (alias->comment)
568 fprintf(fp_alias, " # %s", alias->comment);
569 if (STAILQ_FIRST(&alias->tags))
570 {
571 fprintf(fp_alias, " tags:");
572
573 struct Tag *tag = NULL;
574 STAILQ_FOREACH(tag, &alias->tags, entries)
575 {
576 fprintf(fp_alias, "%s", tag->name);
577 if (STAILQ_NEXT(tag, entries))
578 fprintf(fp_alias, ",");
579 }
580 }
581 fputc('\n', fp_alias);
582 if (mutt_file_fsync_close(&fp_alias) != 0)
583 mutt_perror(_("Trouble adding alias"));
584 else
585 mutt_message(_("Alias added"));
586
587done:
588 mutt_file_fclose(&fp_alias);
589 buf_pool_release(&buf);
590 buf_pool_release(&fixed);
591 buf_pool_release(&prompt);
592 buf_pool_release(&tmp);
593}
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1378
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1206
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:1293
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:672
static int check_alias_name(const char *s, struct Buffer *dest)
Sanity-check an alias name.
Definition: alias.c:216
struct AddressList * alias_lookup(const char *name)
Find an Alias.
Definition: alias.c:277
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:660
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:161
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:204
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:304
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:601
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:168
void mutt_beep(bool force)
Irritate the user.
Definition: curs_lib.c:68
void buf_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
Definition: file.c:933
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:778
int mutt_file_fsync_close(FILE **fp)
Flush the data, before closing a file (and NULL the pointer)
Definition: file.c:193
#define mutt_file_fclose(FP)
Definition: file.h:138
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:137
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
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:56
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:58
#define FREE(x)
Definition: memory.h:55
#define _(a)
Definition: message.h:28
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:280
#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
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
@ 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:327
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:827
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TAILQ_FIRST(head)
Definition: queue.h:741
#define TAILQ_EMPTY(head)
Definition: queue.h:739
#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
An email address.
Definition: address.h:36
struct Buffer * mailbox
Mailbox and host address.
Definition: address.h:38
struct TagList tags
Tags.
Definition: alias.h:39
char * comment
Free-form comment string.
Definition: alias.h:38
char * name
Short name.
Definition: alias.h:36
struct AddressList addr
List of Addresses the Alias expands to.
Definition: alias.h:37
String manipulation buffer.
Definition: buffer.h:36
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:

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

278{
279 struct Alias *a = NULL;
280
281 TAILQ_FOREACH(a, &Aliases, entries)
282 {
283 if (mutt_istr_equal(name, a->name))
284 return &a->addr;
285 }
286 return NULL;
287}
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:672
+ 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 600 of file alias.c.

601{
602 if (!addr)
603 {
604 mutt_debug(LL_DEBUG5, "no, NULL address\n");
605 return false;
606 }
607 if (!addr->mailbox)
608 {
609 mutt_debug(LL_DEBUG5, "no, no mailbox\n");
610 return false;
611 }
612
614 {
615 mutt_debug(LL_DEBUG5, "#1 yes, %s = %s\n", buf_string(addr->mailbox), Username);
616 return true;
617 }
619 {
620 mutt_debug(LL_DEBUG5, "#2 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
622 return true;
623 }
624 const char *fqdn = mutt_fqdn(false, NeoMutt->sub);
625 if (string_is_address(buf_string(addr->mailbox), Username, fqdn))
626 {
627 mutt_debug(LL_DEBUG5, "#3 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
628 Username, NONULL(fqdn));
629 return true;
630 }
631 fqdn = mutt_fqdn(true, NeoMutt->sub);
632 if (string_is_address(buf_string(addr->mailbox), Username, fqdn))
633 {
634 mutt_debug(LL_DEBUG5, "#4 yes, %s = %s @ %s\n", buf_string(addr->mailbox),
635 Username, NONULL(fqdn));
636 return true;
637 }
638
639 const struct Address *c_from = cs_subset_address(NeoMutt->sub, "from");
640 if (c_from && mutt_istr_equal(buf_string(c_from->mailbox), buf_string(addr->mailbox)))
641 {
642 mutt_debug(LL_DEBUG5, "#5 yes, %s = %s\n", buf_string(addr->mailbox),
643 buf_string(c_from->mailbox));
644 return true;
645 }
646
648 return true;
649
650 mutt_debug(LL_DEBUG5, "no, all failed\n");
651 return false;
652}
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: config_type.c:272
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:258
bool mutt_alternates_match(const char *addr)
Compare an Address to the Un/Alternates lists.
Definition: alternates.c:155
char * ShortHostname
Short version of the hostname.
Definition: globals.c:38
char * Username
User's login name.
Definition: globals.c:40
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:707
#define NONULL(x)
Definition: string2.h:37
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
+ 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 309 of file alias.c.

310{
312 mutt_expand_aliases(&env->to);
313 mutt_expand_aliases(&env->cc);
317}
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:295
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_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 295 of file alias.c.

296{
297 // previously expanded aliases to avoid loops
298 struct ListHead expn = STAILQ_HEAD_INITIALIZER(expn);
299
300 expand_aliases_r(al, &expn);
301 mutt_list_free(&expn);
303}
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1397
static void expand_aliases_r(struct AddressList *al, struct ListHead *expn)
Expand aliases, recursively.
Definition: alias.c:106
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
#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_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 327 of file alias.c.

328{
329 struct AddressList *al = NULL;
330 const char *pfx = NULL;
331
333 {
334 if (!TAILQ_EMPTY(&env->to) && !mutt_is_mail_list(TAILQ_FIRST(&env->to)))
335 {
336 pfx = "To";
337 al = &env->to;
338 }
339 else
340 {
341 pfx = "Cc";
342 al = &env->cc;
343 }
344 }
345 else if (!TAILQ_EMPTY(&env->reply_to) && !mutt_is_mail_list(TAILQ_FIRST(&env->reply_to)))
346 {
347 pfx = "Reply-To";
348 al = &env->reply_to;
349 }
350 else
351 {
352 al = &env->from;
353 pfx = "From";
354 }
355
356 if (prefix)
357 *prefix = pfx;
358
359 return al;
360}
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:600
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_tags_to_buffer()

void alias_tags_to_buffer ( struct TagList *  tl,
struct Buffer buf 
)

Write a comma-separated list of tags to a Buffer.

Parameters
tlTags
bufBuffer for the result

Definition at line 49 of file commands.c.

50{
51 struct Tag *tag = NULL;
52 STAILQ_FOREACH(tag, tl, entries)
53 {
54 buf_addstr(buf, tag->name);
55 if (STAILQ_NEXT(tag, entries))
56 buf_addch(buf, ',');
57 }
58}
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_alias_comments()

void parse_alias_comments ( struct Alias alias,
const char *  com 
)

Parse the alias/query comment field.

Parameters
aliasAlias for the result
comComment string

If the comment contains a 'tags:' field, the result will be put in alias.tags

Definition at line 95 of file commands.c.

96{
97 if (!com || (com[0] == '\0'))
98 return;
99
100 const regmatch_t *match = mutt_prex_capture(PREX_ALIAS_TAGS, com);
101 if (match)
102 {
103 const regmatch_t *pre = &match[PREX_ALIAS_TAGS_MATCH_PRE];
104 const regmatch_t *tags = &match[PREX_ALIAS_TAGS_MATCH_TAGS];
105 const regmatch_t *post = &match[PREX_ALIAS_TAGS_MATCH_POST];
106
107 struct Buffer *tmp = buf_pool_get();
108
109 // Extract the tags
110 buf_addstr_n(tmp, com + mutt_regmatch_start(tags),
112 parse_alias_tags(buf_string(tmp), &alias->tags);
113 buf_reset(tmp);
114
115 // Collect all the other text as "comments"
116 buf_addstr_n(tmp, com + mutt_regmatch_start(pre),
118 buf_addstr_n(tmp, com + mutt_regmatch_start(post),
120 alias->comment = buf_strdup(tmp);
121
122 buf_pool_release(&tmp);
123 }
124 else
125 {
126 alias->comment = mutt_str_dup(com);
127 }
128}
size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition: buffer.c:96
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
regmatch_t * mutt_prex_capture(enum Prex which, const char *str)
Match a precompiled regex against a string.
Definition: prex.c:298
@ PREX_ALIAS_TAGS
tags:a,b,c
Definition: prex.h:43
@ PREX_ALIAS_TAGS_MATCH_POST
... tags:a,b,c[ ...]
Definition: prex.h:240
@ PREX_ALIAS_TAGS_MATCH_PRE
[... ]tags:a,b,c ...
Definition: prex.h:237
@ PREX_ALIAS_TAGS_MATCH_TAGS
... tags:[a,b,c] ...
Definition: prex.h:239
static regoff_t mutt_regmatch_end(const regmatch_t *match)
Return the end of a match.
Definition: regex3.h:67
static regoff_t mutt_regmatch_start(const regmatch_t *match)
Return the start of a match.
Definition: regex3.h:57
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_alias_tags()

void parse_alias_tags ( const char *  tags,
struct TagList *  tl 
)

Parse a comma-separated list of tags.

Parameters
tagsComma-separated string
tlTagList for the results

Definition at line 65 of file commands.c.

66{
67 if (!tags || !tl)
68 return;
69
70 struct Slist *sl = slist_parse(tags, D_SLIST_SEP_COMMA);
71 if (slist_is_empty(sl))
72 {
73 slist_free(&sl);
74 return;
75 }
76
77 struct ListNode *np = NULL;
78 STAILQ_FOREACH(np, &sl->head, entries)
79 {
80 struct Tag *tag = tag_new();
81 tag->name = np->data; // Transfer string
82 np->data = NULL;
83 STAILQ_INSERT_TAIL(tl, tag, entries);
84 }
85 slist_free(&sl);
86}
struct Slist * slist_parse(const char *str, uint32_t flags)
Parse a list of strings into a list.
Definition: slist.c:175
bool slist_is_empty(const struct Slist *list)
Is the slist empty?
Definition: slist.c:138
void slist_free(struct Slist **ptr)
Free an Slist object.
Definition: slist.c:122
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:389
A List node for strings.
Definition: list.h:37
char * data
String.
Definition: list.h:38
String list.
Definition: slist.h:37
struct ListHead head
List containing values.
Definition: slist.h:38
struct Tag * tag_new(void)
Create a new Tag.
Definition: tags.c:64
#define D_SLIST_SEP_COMMA
Slist items are comma-separated.
Definition: types.h:111
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_complete()

int alias_complete ( struct Buffer buf,
struct ConfigSubset sub 
)

Alias completion routine.

Parameters
bufPartial Alias to complete
subConfig items
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 335 of file dlg_alias.c.

336{
337 struct Alias *np = NULL;
338 char bestname[8192] = { 0 };
339
340 struct AliasMenuData mdata = { ARRAY_HEAD_INITIALIZER, NULL, sub };
341 mdata.limit = buf_strdup(buf);
342 mdata.search_state = search_state_new();
343
344 if (buf_at(buf, 0) != '\0')
345 {
346 TAILQ_FOREACH(np, &Aliases, entries)
347 {
348 if (np->name && mutt_strn_equal(np->name, buf_string(buf), buf_len(buf)))
349 {
350 if (bestname[0] == '\0') /* init */
351 {
352 mutt_str_copy(bestname, np->name,
353 MIN(mutt_str_len(np->name) + 1, sizeof(bestname)));
354 }
355 else
356 {
357 int i;
358 for (i = 0; np->name[i] && (np->name[i] == bestname[i]); i++)
359 ; // do nothing
360
361 bestname[i] = '\0';
362 }
363 }
364 }
365
366 if (bestname[0] == '\0')
367 {
368 // Create a View Array of all the Aliases
369 FREE(&mdata.limit);
370 TAILQ_FOREACH(np, &Aliases, entries)
371 {
373 }
374 }
375 else
376 {
377 /* fake the pattern for menu title */
378 char *mtitle = NULL;
379 mutt_str_asprintf(&mtitle, "~f ^%s", buf_string(buf));
380 FREE(&mdata.limit);
381 mdata.limit = mtitle;
382
383 if (!mutt_str_equal(bestname, buf_string(buf)))
384 {
385 /* we are adding something to the completion */
386 buf_strcpy_n(buf, bestname, mutt_str_len(bestname) + 1);
387 FREE(&mdata.limit);
388 search_state_free(&mdata.search_state);
389 return 1;
390 }
391
392 /* build alias list and show it */
393 TAILQ_FOREACH(np, &Aliases, entries)
394 {
395 int aasize = alias_array_alias_add(&mdata.ava, np);
396
397 struct AliasView *av = ARRAY_GET(&mdata.ava, aasize - 1);
398
399 if (np->name && !mutt_strn_equal(np->name, buf_string(buf), buf_len(buf)))
400 {
401 av->is_visible = false;
402 }
403 }
404 }
405 }
406
407 if (ARRAY_EMPTY(&mdata.ava))
408 {
409 TAILQ_FOREACH(np, &Aliases, entries)
410 {
411 alias_array_alias_add(&mdata.ava, np);
412 }
413
414 mutt_pattern_alias_func(NULL, &mdata, PAA_VISIBLE, NULL);
415 }
416
417 if (!dlg_alias(&mdata))
418 goto done;
419
420 buf_reset(buf);
421
422 // Extract the selected aliases
423 struct Buffer *tmpbuf = buf_pool_get();
424 struct AliasView *avp = NULL;
425 ARRAY_FOREACH(avp, &mdata.ava)
426 {
427 if (!avp->is_tagged)
428 continue;
429
430 mutt_addrlist_write(&avp->alias->addr, tmpbuf, true);
431 buf_addstr(tmpbuf, ", ");
432 }
433 buf_copy(buf, tmpbuf);
434 buf_pool_release(&tmpbuf);
435
436done:
437 // Process any deleted aliases
438 ARRAY_FOREACH(avp, &mdata.ava)
439 {
440 if (!avp->is_deleted)
441 continue;
442
443 TAILQ_REMOVE(&Aliases, avp->alias, entries);
444 alias_free(&avp->alias);
445 }
446
447 ARRAY_FREE(&mdata.ava);
448 FREE(&mdata.limit);
449 FREE(&mdata.title);
451
452 return 0;
453}
int alias_array_alias_add(struct AliasViewArray *ava, struct Alias *alias)
Add an Alias to the AliasViewArray.
Definition: array.c:47
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:212
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:74
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:204
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:109
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition: array.h:58
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:491
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition: buffer.c:670
size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition: buffer.c:416
static bool dlg_alias(struct AliasMenuData *mdata)
Display a menu of Aliases -.
Definition: dlg_alias.c:266
#define MIN(a, b)
Definition: memory.h:32
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:803
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:425
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
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:581
@ PAA_VISIBLE
Set AliasView.is_visible and hide the rest.
Definition: lib.h:190
int mutt_pattern_alias_func(char *prompt, struct AliasMenuData *mdata, enum PatternAlias action, struct Menu *menu)
Perform some Pattern matching for Alias.
Definition: pattern.c:191
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:862
void search_state_free(struct SearchState **ptr)
Free a SearchState.
Definition: search_state.c:51
struct SearchState * search_state_new(void)
Create a new SearchState.
Definition: search_state.c:39
AliasView array wrapper with Pattern information -.
Definition: gui.h:54
char * limit
Limit being used.
Definition: gui.h:60
struct AliasViewArray ava
All Aliases/Queries.
Definition: gui.h:55
struct SearchState * search_state
State of the current search.
Definition: gui.h:63
char * title
Title for the status bar.
Definition: gui.h:62
struct ConfigSubset * sub
Config items.
Definition: gui.h:57
GUI data wrapping an Alias.
Definition: gui.h:38
bool is_visible
Is visible?
Definition: gui.h:45
struct Alias * alias
Alias.
Definition: gui.h:46
bool is_deleted
Is it deleted?
Definition: gui.h:44
bool is_tagged
Is it tagged?
Definition: gui.h:43
void * mdata
Private data.
Definition: lib.h:147
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_dialog()

void alias_dialog ( struct Mailbox m,
struct ConfigSubset sub 
)

Open the aliases dialog.

Parameters
mMailbox
subConfig item

Definition at line 460 of file dlg_alias.c.

461{
462 struct Alias *np = NULL;
463
464 struct AliasMenuData mdata = { ARRAY_HEAD_INITIALIZER, NULL, sub };
465 mdata.search_state = search_state_new();
466
467 // Create a View Array of all the Aliases
468 TAILQ_FOREACH(np, &Aliases, entries)
469 {
471 }
472
473 if (!dlg_alias(&mdata))
474 goto done;
475
476 // Prepare the "To:" field of a new email
477 struct Email *e = email_new();
478 e->env = mutt_env_new();
479
480 struct AliasView *avp = NULL;
481 ARRAY_FOREACH(avp, &mdata.ava)
482 {
483 if (!avp->is_tagged)
484 continue;
485
486 struct AddressList al_copy = TAILQ_HEAD_INITIALIZER(al_copy);
487 if (alias_to_addrlist(&al_copy, avp->alias))
488 {
489 mutt_addrlist_copy(&e->env->to, &al_copy, false);
490 mutt_addrlist_clear(&al_copy);
491 }
492 }
493
494 mutt_send_message(SEND_REVIEW_TO, e, NULL, m, NULL, sub);
495
496done:
497 // Process any deleted aliases
498 ARRAY_FOREACH(avp, &mdata.ava)
499 {
500 if (avp->is_deleted)
501 {
502 TAILQ_REMOVE(&Aliases, avp->alias, entries);
503 alias_free(&avp->alias);
504 }
505 }
506
507 ARRAY_FREE(&mdata.ava);
508 FREE(&mdata.limit);
509 FREE(&mdata.title);
511}
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_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1460
bool alias_to_addrlist(struct AddressList *al, struct Alias *alias)
Turn an Alias into an AddressList.
Definition: dlg_query.c:120
struct Email * email_new(void)
Create a new Email.
Definition: email.c:77
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:46
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:655
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
Send an email.
Definition: send.c:2033
#define SEND_REVIEW_TO
Allow the user to edit the To field.
Definition: send.h:56
The envelope/body of an email.
Definition: email.h:39
struct Envelope * env
Envelope information.
Definition: email.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_complete()

int query_complete ( struct Buffer buf,
struct ConfigSubset sub 
)

Perform auto-complete using an Address Query.

Parameters
bufBuffer for completion
subConfig item
Return values
0Always

Definition at line 400 of file dlg_query.c.

401{
402 struct AliasMenuData mdata = { ARRAY_HEAD_INITIALIZER, NULL, sub };
403 mdata.search_state = search_state_new();
404
405 struct AliasList al = TAILQ_HEAD_INITIALIZER(al);
406 const char *const c_query_command = cs_subset_string(sub, "query_command");
407 if (!c_query_command)
408 {
409 mutt_warning(_("Query command not defined"));
410 goto done;
411 }
412
413 query_run(buf_string(buf), true, &al, sub);
414 if (TAILQ_EMPTY(&al))
415 goto done;
416
417 mdata.al = &al;
418
419 struct Alias *a_first = TAILQ_FIRST(&al);
420 if (!TAILQ_NEXT(a_first, entries)) // only one response?
421 {
422 struct AddressList addr = TAILQ_HEAD_INITIALIZER(addr);
423 if (alias_to_addrlist(&addr, a_first))
424 {
426 buf_reset(buf);
427 mutt_addrlist_write(&addr, buf, false);
428 mutt_addrlist_clear(&addr);
430 }
431 goto done;
432 }
433
434 struct Alias *np = NULL;
435 TAILQ_FOREACH(np, mdata.al, entries)
436 {
437 alias_array_alias_add(&mdata.ava, np);
438 }
439
440 /* multiple results, choose from query menu */
441 if (!dlg_query(buf, &mdata))
442 goto done;
443
444 buf_reset(buf);
445 buf_alloc(buf, 8192);
446 struct AliasView *avp = NULL;
447 ARRAY_FOREACH(avp, &mdata.ava)
448 {
449 if (!avp->is_tagged)
450 continue;
451
452 struct AddressList al_copy = TAILQ_HEAD_INITIALIZER(al_copy);
453 if (alias_to_addrlist(&al_copy, avp->alias))
454 {
455 mutt_addrlist_to_local(&al_copy);
456 mutt_addrlist_write(&al_copy, buf, false);
457 mutt_addrlist_clear(&al_copy);
458 }
459 buf_addstr(buf, ", ");
460 }
461
462done:
463 ARRAY_FREE(&mdata.ava);
464 FREE(&mdata.title);
465 FREE(&mdata.limit);
467 aliaslist_clear(&al);
468 return 0;
469}
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:337
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
int query_run(const char *s, bool verbose, struct AliasList *al, const struct ConfigSubset *sub)
Run an external program to find Addresses.
Definition: dlg_query.c:189
static bool dlg_query(struct Buffer *buf, struct AliasMenuData *mdata)
Get the user to enter an Address Query -.
Definition: dlg_query.c:343
#define mutt_warning(...)
Definition: logging2.h:90
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
#define TAILQ_NEXT(elm, field)
Definition: queue.h:850
struct AliasList * al
Alias data.
Definition: gui.h:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ query_index()

void query_index ( struct Mailbox m,
struct ConfigSubset sub 
)

Perform an Alias Query and display the results.

Parameters
mMailbox
subConfig item

Definition at line 476 of file dlg_query.c.

477{
478 const char *const c_query_command = cs_subset_string(sub, "query_command");
479 if (!c_query_command)
480 {
481 mutt_warning(_("Query command not defined"));
482 return;
483 }
484
485 struct AliasList al = TAILQ_HEAD_INITIALIZER(al);
486 struct AliasMenuData mdata = { ARRAY_HEAD_INITIALIZER, NULL, sub };
487 mdata.al = &al;
488 mdata.search_state = search_state_new();
489
490 struct Buffer *buf = buf_pool_get();
491 if ((mw_get_field(_("Query: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0) ||
492 buf_is_empty(buf))
493 {
494 goto done;
495 }
496
497 query_run(buf_string(buf), false, &al, sub);
498 if (TAILQ_EMPTY(&al))
499 goto done;
500
501 struct Alias *np = NULL;
502 TAILQ_FOREACH(np, mdata.al, entries)
503 {
504 alias_array_alias_add(&mdata.ava, np);
505 }
506
507 if (!dlg_query(buf, &mdata))
508 goto done;
509
510 // Prepare the "To:" field of a new email
511 struct Email *e = email_new();
512 e->env = mutt_env_new();
513
514 struct AliasView *avp = NULL;
515 ARRAY_FOREACH(avp, &mdata.ava)
516 {
517 if (!avp->is_tagged)
518 continue;
519
520 struct AddressList al_copy = TAILQ_HEAD_INITIALIZER(al_copy);
521 if (alias_to_addrlist(&al_copy, avp->alias))
522 {
523 mutt_addrlist_copy(&e->env->to, &al_copy, false);
524 mutt_addrlist_clear(&al_copy);
525 }
526 }
527
528 mutt_send_message(SEND_REVIEW_TO, e, NULL, m, NULL, sub);
529
530done:
531 ARRAY_FREE(&mdata.ava);
532 FREE(&mdata.title);
533 FREE(&mdata.limit);
535 aliaslist_clear(&al);
536 buf_pool_release(&buf);
537}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ alias_reverse_lookup()

struct Address * alias_reverse_lookup ( const struct Address addr)

Does the user have an alias for the given address.

Parameters
addrAddress to lookup
Return values
ptrMatching Address

Definition at line 105 of file reverse.c.

106{
107 if (!addr || !addr->mailbox)
108 return NULL;
109
111}
void * mutt_hash_find(const struct HashTable *table, const char *strkey)
Find the HashElem data in a Hash Table element using a key.
Definition: hash.c:362
static struct HashTable * ReverseAliases
Hash Table of aliases (email address -> alias)
Definition: reverse.c:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ CompleteAliasOps

const struct CompleteOps CompleteAliasOps
extern

Auto-Completion of Aliases.

Definition at line 108 of file complete.c.