NeoMutt  2022-04-29-178-g3b62e6
Teaching an old dog new tricks
DOXYGEN
send.h File Reference

Prepare and send an email. More...

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
+ Include dependency graph for send.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define SEND_NO_FLAGS   0
 No flags are set. More...
 
#define SEND_REPLY   (1 << 0)
 Reply to sender. More...
 
#define SEND_GROUP_REPLY   (1 << 1)
 Reply to all. More...
 
#define SEND_LIST_REPLY   (1 << 2)
 Reply to mailing list. More...
 
#define SEND_FORWARD   (1 << 3)
 Forward email. More...
 
#define SEND_POSTPONED   (1 << 4)
 Recall a postponed email. More...
 
#define SEND_BATCH   (1 << 5)
 Send email in batch mode (without user interaction) More...
 
#define SEND_KEY   (1 << 6)
 Mail a PGP public key. More...
 
#define SEND_RESEND   (1 << 7)
 Reply using the current email as a template. More...
 
#define SEND_POSTPONED_FCC   (1 << 8)
 Used by mutt_get_postponed() to signal that the x-mutt-fcc header field was present. More...
 
#define SEND_NO_FREE_HEADER   (1 << 9)
 Used by the -E flag. More...
 
#define SEND_DRAFT_FILE   (1 << 10)
 Used by the -H flag. More...
 
#define SEND_TO_SENDER   (1 << 11)
 Compose new email to sender. More...
 
#define SEND_GROUP_CHAT_REPLY   (1 << 12)
 Reply to all recipients preserving To/Cc. More...
 
#define SEND_NEWS   (1 << 13)
 Reply to a news article. More...
 
#define SEND_REVIEW_TO   (1 << 14)
 Allow the user to edit the To field. More...
 

Typedefs

typedef uint16_t SendFlags
 Flags for mutt_send_message(), e.g. SEND_REPLY. More...
 

Functions

void mutt_add_to_reference_headers (struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
 Generate references for a reply email. More...
 
struct Addressmutt_default_from (struct ConfigSubset *sub)
 Get a default 'from' Address. More...
 
int mutt_edit_address (struct AddressList *al, const char *field, bool expand_aliases)
 Edit an email address. More...
 
void mutt_encode_descriptions (struct Body *b, bool recurse, struct ConfigSubset *sub)
 RFC2047 encode the content-descriptions. More...
 
int mutt_fetch_recips (struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
 Generate recpients for a reply email. More...
 
void mutt_fix_reply_recipients (struct Envelope *env, struct ConfigSubset *sub)
 Remove duplicate recipients. More...
 
void mutt_forward_intro (struct Email *e, FILE *fp, struct ConfigSubset *sub)
 Add the "start of forwarded message" text. More...
 
void mutt_forward_trailer (struct Email *e, FILE *fp, struct ConfigSubset *sub)
 Add a "end of forwarded message" text. More...
 
void mutt_make_attribution (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add "on DATE, PERSON wrote" header. More...
 
void mutt_make_forward_subject (struct Envelope *env, struct Email *e, struct ConfigSubset *sub)
 Create a subject for a forwarded email. More...
 
void mutt_make_misc_reply_headers (struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
 Set subject for a reply. More...
 
void mutt_make_post_indent (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add suffix to replied email text. More...
 
int mutt_resend_message (FILE *fp, struct Mailbox *m, struct Email *e_cur, struct ConfigSubset *sub)
 Resend an email. More...
 
int mutt_send_message (SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailList *el, struct ConfigSubset *sub)
 Send an email. More...
 
void mutt_set_followup_to (struct Envelope *env, struct ConfigSubset *sub)
 Set followup-to field. More...
 
bool mutt_send_list_subscribe (struct Mailbox *m, struct Email *e)
 Send a mailing-list subscription email. More...
 
bool mutt_send_list_unsubscribe (struct Mailbox *m, struct Email *e)
 Send a mailing-list unsubscription email. More...
 

Detailed Description

Prepare and send an email.

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

Macro Definition Documentation

◆ SEND_NO_FLAGS

#define SEND_NO_FLAGS   0

No flags are set.

Definition at line 39 of file send.h.

◆ SEND_REPLY

#define SEND_REPLY   (1 << 0)

Reply to sender.

Definition at line 40 of file send.h.

◆ SEND_GROUP_REPLY

#define SEND_GROUP_REPLY   (1 << 1)

Reply to all.

Definition at line 41 of file send.h.

◆ SEND_LIST_REPLY

#define SEND_LIST_REPLY   (1 << 2)

Reply to mailing list.

Definition at line 42 of file send.h.

◆ SEND_FORWARD

#define SEND_FORWARD   (1 << 3)

Forward email.

Definition at line 43 of file send.h.

◆ SEND_POSTPONED

#define SEND_POSTPONED   (1 << 4)

Recall a postponed email.

Definition at line 44 of file send.h.

◆ SEND_BATCH

#define SEND_BATCH   (1 << 5)

Send email in batch mode (without user interaction)

Definition at line 45 of file send.h.

◆ SEND_KEY

#define SEND_KEY   (1 << 6)

Mail a PGP public key.

Definition at line 46 of file send.h.

◆ SEND_RESEND

#define SEND_RESEND   (1 << 7)

Reply using the current email as a template.

Definition at line 47 of file send.h.

◆ SEND_POSTPONED_FCC

#define SEND_POSTPONED_FCC   (1 << 8)

Used by mutt_get_postponed() to signal that the x-mutt-fcc header field was present.

Definition at line 48 of file send.h.

◆ SEND_NO_FREE_HEADER

#define SEND_NO_FREE_HEADER   (1 << 9)

Used by the -E flag.

Definition at line 49 of file send.h.

◆ SEND_DRAFT_FILE

#define SEND_DRAFT_FILE   (1 << 10)

Used by the -H flag.

Definition at line 50 of file send.h.

◆ SEND_TO_SENDER

#define SEND_TO_SENDER   (1 << 11)

Compose new email to sender.

Definition at line 51 of file send.h.

◆ SEND_GROUP_CHAT_REPLY

#define SEND_GROUP_CHAT_REPLY   (1 << 12)

Reply to all recipients preserving To/Cc.

Definition at line 52 of file send.h.

◆ SEND_NEWS

#define SEND_NEWS   (1 << 13)

Reply to a news article.

Definition at line 53 of file send.h.

◆ SEND_REVIEW_TO

#define SEND_REVIEW_TO   (1 << 14)

Allow the user to edit the To field.

Definition at line 54 of file send.h.

Typedef Documentation

◆ SendFlags

typedef uint16_t SendFlags

Flags for mutt_send_message(), e.g. SEND_REPLY.

Definition at line 38 of file send.h.

Function Documentation

◆ mutt_add_to_reference_headers()

void mutt_add_to_reference_headers ( struct Envelope env,
struct Envelope curenv,
struct ConfigSubset sub 
)

Generate references for a reply email.

Parameters
envEnvelope for result
curenvEnvelope of source email
subConfig Subset

Definition at line 1090 of file send.c.

1092{
1093 add_references(&env->references, curenv);
1094 add_message_id(&env->references, curenv);
1095 add_message_id(&env->in_reply_to, curenv);
1096
1097#ifdef USE_NNTP
1098 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
1099 if (OptNewsSend && c_x_comment_to && !TAILQ_EMPTY(&curenv->from))
1101#endif
1102}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:51
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_EMPTY(head)
Definition: queue.h:721
static void add_message_id(struct ListHead *head, struct Envelope *env)
Add the email's message ID to a list.
Definition: send.c:1000
static void add_references(struct ListHead *head, struct Envelope *env)
Add the email's references to a list.
Definition: send.c:984
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition: sort.c:136
char * x_comment_to
List of 'X-comment-to' fields.
Definition: envelope.h:82
struct ListHead references
message references (in reverse order)
Definition: envelope.h:85
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:86
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_default_from()

struct Address * mutt_default_from ( struct ConfigSubset sub)

Get a default 'from' Address.

Return values
ptrNewly allocated Address

Definition at line 1459 of file send.c.

1460{
1461 /* Note: We let $from override $real_name here.
1462 * Is this the right thing to do?
1463 */
1464
1465 const struct Address *c_from = cs_subset_address(sub, "from");
1466 const bool c_use_domain = cs_subset_bool(sub, "use_domain");
1467 if (c_from)
1468 {
1469 return mutt_addr_copy(c_from);
1470 }
1471 else if (c_use_domain)
1472 {
1473 struct Address *addr = mutt_addr_new();
1474 mutt_str_asprintf(&addr->mailbox, "%s@%s", NONULL(Username),
1475 NONULL(mutt_fqdn(true, sub)));
1476 return addr;
1477 }
1478 else
1479 {
1480 return mutt_addr_create(NULL, Username);
1481 }
1482}
struct Address * mutt_addr_create(const char *personal, const char *mailbox)
Create and populate a new Address.
Definition: address.c:398
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:716
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: helpers.c:49
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1008
char * Username
User's login name.
Definition: mutt_globals.h:52
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:698
#define NONULL(x)
Definition: string2.h:37
An email address.
Definition: address.h:36
char * mailbox
Mailbox and host address.
Definition: address.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_edit_address()

int mutt_edit_address ( struct AddressList *  al,
const char *  field,
bool  expand_aliases 
)

Edit an email address.

Parameters
[in,out]alAddressList to edit
[in]fieldPrompt for user
[in]expand_aliasesIf true, expand Address aliases
Return values
0Success
-1Failure

Definition at line 178 of file send.c.

179{
180 int rc = 0;
181 struct Buffer *buf = mutt_buffer_pool_get();
182 mutt_buffer_alloc(buf, 8192);
183 char *err = NULL;
184 int idna_ok = 0;
185
186 do
187 {
190 mutt_addrlist_write(al, buf->data, buf->dsize, false);
191 if (mutt_buffer_get_field(field, buf, MUTT_COMP_ALIAS, false, NULL, NULL, NULL) != 0)
192 {
193 rc = -1;
194 goto done;
195 }
198 if (expand_aliases)
200 idna_ok = mutt_addrlist_to_intl(al, &err);
201 if (idna_ok != 0)
202 {
203 mutt_error(_("Bad IDN: '%s'"), err);
204 FREE(&err);
205 }
206 } while (idna_ok != 0);
207
208done:
210 return rc;
211}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
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_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:616
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1305
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:298
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
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
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
#define mutt_error(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:43
#define _(a)
Definition: message.h:28
#define MUTT_COMP_ALIAS
Alias completion (in alias dialog)
Definition: mutt.h:53
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
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
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_encode_descriptions()

void mutt_encode_descriptions ( struct Body b,
bool  recurse,
struct ConfigSubset sub 
)

RFC2047 encode the content-descriptions.

Parameters
bBody of email
recurseIf true, encode children parts
subConfig Subset

Definition at line 1578 of file send.c.

1579{
1580 for (struct Body *t = b; t; t = t->next)
1581 {
1582 if (t->description)
1583 {
1584 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
1585 rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), c_send_charset);
1586 }
1587 if (recurse && t->parts)
1588 mutt_encode_descriptions(t->parts, recurse, sub);
1589 }
1590}
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:268
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:619
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
RFC2047 encode the content-descriptions.
Definition: send.c:1578
The body of an email.
Definition: body.h:36
struct Body * next
next attachment in the list
Definition: body.h:71
String list.
Definition: slist.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_fetch_recips()

int mutt_fetch_recips ( struct Envelope out,
struct Envelope in,
SendFlags  flags,
struct ConfigSubset sub 
)

Generate recpients for a reply email.

Parameters
outEnvelope to populate
inEnvelope of source email
flagsFlags, see SendFlags
subConfig Subset
Return values
0Success
-1Failure

Definition at line 925 of file send.c.

927{
928 enum QuadOption hmfupto = MUTT_ABORT;
929 const struct Address *followup_to = TAILQ_FIRST(&in->mail_followup_to);
930
931 if ((flags & (SEND_LIST_REPLY | SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) && followup_to)
932 {
933 char prompt[256] = { 0 };
934 snprintf(prompt, sizeof(prompt), _("Follow-up to %s%s?"), followup_to->mailbox,
935 TAILQ_NEXT(TAILQ_FIRST(&in->mail_followup_to), entries) ? ",..." : "");
936
937 const enum QuadOption c_honor_followup_to = cs_subset_quad(sub, "honor_followup_to");
938 hmfupto = query_quadoption(c_honor_followup_to, prompt);
939 if (hmfupto == MUTT_ABORT)
940 return -1;
941 }
942
943 if (flags & SEND_LIST_REPLY)
944 {
945 add_mailing_lists(&out->to, &in->to, &in->cc);
946
947 if (followup_to && (hmfupto == MUTT_YES) &&
948 (default_to(&out->cc, in, flags & SEND_LIST_REPLY, (hmfupto == MUTT_YES), sub) == MUTT_ABORT))
949 {
950 return -1; /* abort */
951 }
952 }
953 else if (flags & SEND_TO_SENDER)
954 {
955 mutt_addrlist_copy(&out->to, &in->from, false);
956 }
957 else
958 {
959 if (default_to(&out->to, in, flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY),
960 (hmfupto == MUTT_YES), sub) == -1)
961 {
962 return -1; /* abort */
963 }
964
965 if ((flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) &&
966 (!followup_to || (hmfupto != MUTT_YES)))
967 {
968 /* if(!mutt_addr_is_user(in->to)) */
969 if (flags & SEND_GROUP_REPLY)
970 mutt_addrlist_copy(&out->cc, &in->to, true);
971 else
972 mutt_addrlist_copy(&out->to, &in->to, true);
973 mutt_addrlist_copy(&out->cc, &in->cc, true);
974 }
975 }
976 return 0;
977}
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
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ 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_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:386
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
static void add_mailing_lists(struct AddressList *out, const struct AddressList *t, const struct AddressList *c)
Search Address lists for mailing lists.
Definition: send.c:151
static int default_to(struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
Generate default email addresses.
Definition: send.c:839
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:52
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:41
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:42
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:51
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
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
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_fix_reply_recipients()

void mutt_fix_reply_recipients ( struct Envelope env,
struct ConfigSubset sub 
)

Remove duplicate recipients.

Parameters
envEnvelope to fix
subConfig Subset

Definition at line 1013 of file send.c.

1014{
1015 const bool c_me_too = cs_subset_bool(sub, "me_too");
1016 if (!c_me_too)
1017 {
1018 const bool c_reply_self = cs_subset_bool(sub, "reply_self");
1019
1020 /* the order is important here. do the CC: first so that if the
1021 * the user is the only recipient, it ends up on the TO: field */
1022 remove_user(&env->cc, TAILQ_EMPTY(&env->to));
1023 remove_user(&env->to, TAILQ_EMPTY(&env->cc) || c_reply_self);
1024 }
1025
1026 /* the CC field can get cluttered, especially with lists */
1027 mutt_addrlist_dedupe(&env->to);
1028 mutt_addrlist_dedupe(&env->cc);
1029 mutt_addrlist_remove_xrefs(&env->to, &env->cc);
1030
1031 if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
1032 {
1033 TAILQ_SWAP(&env->to, &env->cc, Address, entries);
1034 }
1035}
void mutt_addrlist_remove_xrefs(const struct AddressList *a, struct AddressList *b)
Remove cross-references.
Definition: address.c:1443
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1407
#define TAILQ_SWAP(head1, head2, type, field)
Definition: queue.h:859
static void remove_user(struct AddressList *al, bool leave_only)
Remove any address which matches the current user.
Definition: send.c:132
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_forward_intro()

void mutt_forward_intro ( struct Email e,
FILE *  fp,
struct ConfigSubset sub 
)

Add the "start of forwarded message" text.

Parameters
eEmail
subConfig Subset
fpFile to write to

Definition at line 449 of file send.c.

450{
451 const char *const c_forward_attribution_intro = cs_subset_string(sub, "forward_attribution_intro");
452 if (!c_forward_attribution_intro || !fp)
453 return;
454
455 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
456
457 char buf[1024] = { 0 };
458 setlocale(LC_TIME, NONULL(c_attribution_locale));
459 mutt_make_string(buf, sizeof(buf), 0, c_forward_attribution_intro, NULL, -1,
460 e, MUTT_FORMAT_NO_FLAGS, NULL);
461 setlocale(LC_TIME, "");
462 fputs(buf, fp);
463 fputs("\n\n", fp);
464}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
void mutt_make_string(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1405
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_forward_trailer()

void mutt_forward_trailer ( struct Email e,
FILE *  fp,
struct ConfigSubset sub 
)

Add a "end of forwarded message" text.

Parameters
eEmail
subConfig Subset
fpFile to write to

Definition at line 472 of file send.c.

473{
474 const char *const c_forward_attribution_trailer = cs_subset_string(sub, "forward_attribution_trailer");
475 if (!c_forward_attribution_trailer || !fp)
476 return;
477
478 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
479
480 char buf[1024] = { 0 };
481 setlocale(LC_TIME, NONULL(c_attribution_locale));
482 mutt_make_string(buf, sizeof(buf), 0, c_forward_attribution_trailer, NULL, -1,
483 e, MUTT_FORMAT_NO_FLAGS, NULL);
484 setlocale(LC_TIME, "");
485 fputc('\n', fp);
486 fputs(buf, fp);
487 fputc('\n', fp);
488}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_attribution()

void mutt_make_attribution ( struct Email e,
FILE *  fp_out,
struct ConfigSubset sub 
)

Add "on DATE, PERSON wrote" header.

Parameters
eEmail
fp_outFile to write to
subConfig Subset

Definition at line 633 of file send.c.

634{
635 const char *const c_attribution = cs_subset_string(sub, "attribution");
636 if (!c_attribution || !fp_out)
637 return;
638
639 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
640
641 char buf[1024] = { 0 };
642 setlocale(LC_TIME, NONULL(c_attribution_locale));
643 mutt_make_string(buf, sizeof(buf), 0, c_attribution, NULL, -1, e,
645 setlocale(LC_TIME, "");
646 fputs(buf, fp_out);
647 fputc('\n', fp_out);
648}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_forward_subject()

void mutt_make_forward_subject ( struct Envelope env,
struct Email e,
struct ConfigSubset sub 
)

Create a subject for a forwarded email.

Parameters
envEnvelope for result
eEmail
subConfig Subset

Definition at line 1043 of file send.c.

1044{
1045 if (!env)
1046 return;
1047
1048 const char *const c_forward_format = cs_subset_string(sub, "forward_format");
1049
1050 char buf[256] = { 0 };
1051 /* set the default subject for the message. */
1052 mutt_make_string(buf, sizeof(buf), 0, NONULL(c_forward_format), NULL, -1, e,
1053 MUTT_FORMAT_NO_FLAGS, NULL);
1054 mutt_str_replace(&env->subject, buf);
1055}
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
char * subject
Email's subject.
Definition: envelope.h:70
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_misc_reply_headers()

void mutt_make_misc_reply_headers ( struct Envelope env,
struct Envelope curenv,
struct ConfigSubset sub 
)

Set subject for a reply.

Parameters
envEnvelope for result
curenvEnvelope of source email
subConfig Subset

Definition at line 1063 of file send.c.

1065{
1066 if (!env || !curenv)
1067 return;
1068
1069 /* This takes precedence over a subject that might have
1070 * been taken from a List-Post header. Is that correct? */
1071 if (curenv->real_subj)
1072 {
1073 FREE(&env->subject);
1074 env->subject = mutt_mem_malloc(mutt_str_len(curenv->real_subj) + 5);
1075 sprintf(env->subject, "Re: %s", curenv->real_subj);
1076 }
1077 else if (!env->subject)
1078 {
1079 const char *const c_empty_subject = cs_subset_string(sub, "empty_subject");
1080 env->subject = mutt_str_dup(c_empty_subject);
1081 }
1082}
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
char * real_subj
Offset of the real subject.
Definition: envelope.h:71
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_post_indent()

void mutt_make_post_indent ( struct Email e,
FILE *  fp_out,
struct ConfigSubset sub 
)

Add suffix to replied email text.

Parameters
eEmail
fp_outFile to write to
subConfig Subset

Definition at line 742 of file send.c.

743{
744 const char *const c_post_indent_string = cs_subset_string(sub, "post_indent_string");
745 if (!c_post_indent_string || !fp_out)
746 return;
747
748 char buf[256] = { 0 };
749 mutt_make_string(buf, sizeof(buf), 0, c_post_indent_string, NULL, -1, e,
751 fputs(buf, fp_out);
752 fputc('\n', fp_out);
753}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_resend_message()

int mutt_resend_message ( FILE *  fp,
struct Mailbox m,
struct Email e_cur,
struct ConfigSubset sub 
)

Resend an email.

Parameters
fpFile containing email
mMailbox
e_curEmail to resend
subConfig Subset
Return values
0Message was successfully sent
-1Message was aborted or an error occurred
1Message was postponed

Definition at line 1638 of file send.c.

1640{
1641 struct Email *e_new = email_new();
1642
1643 if (mutt_prepare_template(fp, m, e_new, e_cur, true) < 0)
1644 {
1645 email_free(&e_new);
1646 return -1;
1647 }
1648
1649 if (WithCrypto)
1650 {
1651 /* mutt_prepare_template doesn't always flip on an application bit.
1652 * so fix that here */
1653 if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1654 {
1655 const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
1656 if (((WithCrypto & APPLICATION_SMIME) != 0) && c_smime_is_default)
1657 e_new->security |= APPLICATION_SMIME;
1658 else if (WithCrypto & APPLICATION_PGP)
1659 e_new->security |= APPLICATION_PGP;
1660 else
1661 e_new->security |= APPLICATION_SMIME;
1662 }
1663
1664 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
1665 if (c_crypt_opportunistic_encrypt)
1666 {
1667 e_new->security |= SEC_OPPENCRYPT;
1669 }
1670 }
1671
1672 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1673 emaillist_add_email(&el, e_cur);
1674 int rc = mutt_send_message(SEND_RESEND, e_new, NULL, m, &el, sub);
1675 emaillist_clear(&el);
1676
1677 return rc;
1678}
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1025
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:159
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:138
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define WithCrypto
Definition: lib.h:116
int mutt_prepare_template(FILE *fp, struct Mailbox *m, struct Email *e_new, struct Email *e, bool resend)
Prepare a message template.
Definition: postpone.c:503
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailList *el, struct ConfigSubset *sub)
Send an email.
Definition: send.c:2126
#define SEND_RESEND
Reply using the current email as a template.
Definition: send.h:47
The envelope/body of an email.
Definition: email.h:37
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_send_message()

int mutt_send_message ( SendFlags  flags,
struct Email e_templ,
const char *  tempfile,
struct Mailbox m,
struct EmailList *  el,
struct ConfigSubset sub 
)

Send an email.

Parameters
flagsSend mode, see SendFlags
e_templTemplate to use for new message
tempfileFile specified by -i or -H
mCurrent mailbox
elList of Emails to send
subConfig Subset
Return values
0Message was successfully sent
-1Message was aborted or an error occurred
1Message was postponed

Definition at line 2126 of file send.c.

2128{
2129 struct Buffer fcc = mutt_buffer_make(0); /* where to copy this message */
2130 FILE *fp_tmp = NULL;
2131 struct Body *pbody = NULL;
2132 int i;
2133 bool free_clear_content = false;
2134
2135 struct Body *clear_content = NULL;
2136 char *pgpkeylist = NULL;
2137 /* save current value of "pgp_sign_as" and "smime_default_key" */
2138 char *pgp_sign_as = NULL;
2139 char *smime_sign_as = NULL;
2140 const char *tag = NULL;
2141 char *err = NULL;
2142 const char *ctype = NULL;
2143 char *finalpath = NULL;
2144 struct EmailNode *en = NULL;
2145 struct Email *e_cur = NULL;
2146
2147 if (el)
2148 en = STAILQ_FIRST(el);
2149 if (en)
2150 e_cur = STAILQ_NEXT(en, entries) ? NULL : en->email;
2151
2152 int rc = -1;
2153
2154#ifdef USE_NNTP
2155 if (flags & SEND_NEWS)
2156 OptNewsSend = true;
2157 else
2158 OptNewsSend = false;
2159#endif
2160
2161 const enum QuadOption c_recall = cs_subset_quad(sub, "recall");
2162
2163 if (!flags && !e_templ && (c_recall != MUTT_NO) && mutt_num_postponed(m, true))
2164 {
2165 /* If the user is composing a new message, check to see if there
2166 * are any postponed messages first. */
2167 enum QuadOption ans = query_quadoption(c_recall, _("Recall postponed message?"));
2168 if (ans == MUTT_ABORT)
2169 return rc;
2170
2171 if (ans == MUTT_YES)
2172 flags |= SEND_POSTPONED;
2173 }
2174
2175 /* Allocate the buffer due to the long lifetime, but
2176 * pre-resize it to ensure there are no NULL data field issues */
2177 mutt_buffer_alloc(&fcc, 1024);
2178
2179 if (flags & SEND_POSTPONED)
2180 {
2182 {
2183 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
2184 pgp_sign_as = mutt_str_dup(c_pgp_sign_as);
2185 }
2187 {
2188 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
2189 smime_sign_as = mutt_str_dup(c_smime_sign_as);
2190 }
2191 }
2192
2193 /* Delay expansion of aliases until absolutely necessary--shouldn't
2194 * be necessary unless we are prompting the user or about to execute a
2195 * send-hook. */
2196
2197 if (!e_templ)
2198 {
2199 e_templ = email_new();
2200
2201 if (flags == SEND_POSTPONED)
2202 {
2203 rc = mutt_get_postponed(m, e_templ, &e_cur, &fcc);
2204 if (rc < 0)
2205 {
2206 flags = SEND_POSTPONED;
2207 goto cleanup;
2208 }
2209 flags = rc;
2210#ifdef USE_NNTP
2211 /* If postponed message is a news article, it have
2212 * a "Newsgroups:" header line, then set appropriate flag. */
2213 if (e_templ->env->newsgroups)
2214 {
2215 flags |= SEND_NEWS;
2216 OptNewsSend = true;
2217 }
2218 else
2219 {
2220 flags &= ~SEND_NEWS;
2221 OptNewsSend = false;
2222 }
2223#endif
2224 }
2225
2226 if (flags & (SEND_POSTPONED | SEND_RESEND))
2227 {
2228 struct Body *b = e_templ->body;
2229 while (b->parts)
2230 b = b->parts;
2231 fp_tmp = mutt_file_fopen(b->filename, "a+");
2232 if (!fp_tmp)
2233 {
2235 goto cleanup;
2236 }
2237 }
2238
2239 if (!e_templ->env)
2240 e_templ->env = mutt_env_new();
2241 }
2242
2243 /* Parse and use an eventual list-post header */
2244 if ((flags & SEND_LIST_REPLY) && e_cur && e_cur->env && e_cur->env->list_post)
2245 {
2246 /* Use any list-post header as a template */
2247 mutt_parse_mailto(e_templ->env, NULL, e_cur->env->list_post);
2248 /* We don't let them set the sender's address. */
2249 mutt_addrlist_clear(&e_templ->env->from);
2250 }
2251
2252 if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND)))
2253 {
2254 /* When SEND_DRAFT_FILE is set, the caller has already
2255 * created the "parent" body structure. */
2256 if (!(flags & SEND_DRAFT_FILE))
2257 {
2258 pbody = mutt_body_new();
2259 pbody->next = e_templ->body; /* don't kill command-line attachments */
2260 e_templ->body = pbody;
2261
2262 const char *const c_content_type = cs_subset_string(sub, "content_type");
2263 ctype = c_content_type;
2264 if (!ctype)
2265 ctype = "text/plain";
2266 mutt_parse_content_type(ctype, e_templ->body);
2267 e_templ->body->unlink = true;
2268 e_templ->body->use_disp = false;
2269 e_templ->body->disposition = DISP_INLINE;
2270
2271 if (tempfile)
2272 {
2273 fp_tmp = mutt_file_fopen(tempfile, "a+");
2274 e_templ->body->filename = mutt_str_dup(tempfile);
2275 if (flags & SEND_NO_FREE_HEADER)
2276 e_templ->body->unlink = false;
2277 }
2278 else
2279 {
2280 char buf[1024] = { 0 };
2281 mutt_mktemp(buf, sizeof(buf));
2282 fp_tmp = mutt_file_fopen(buf, "w+");
2283 e_templ->body->filename = mutt_str_dup(buf);
2284 }
2285 }
2286 else
2287 {
2288 struct Body *b = e_templ->body;
2289 while (b->parts)
2290 b = b->parts;
2291 fp_tmp = mutt_file_fopen(b->filename, "a+");
2292 }
2293
2294 if (!fp_tmp)
2295 {
2296 mutt_debug(LL_DEBUG1, "can't create tempfile %s (errno=%d)\n",
2297 e_templ->body->filename, errno);
2298 mutt_perror(e_templ->body->filename);
2299 goto cleanup;
2300 }
2301 }
2302
2303 const bool c_reverse_name = cs_subset_bool(sub, "reverse_name");
2304 /* this is handled here so that the user can match ~f in send-hook */
2305 if (e_cur && c_reverse_name && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2306 {
2307 /* We shouldn't have to worry about alias expansion here since we are
2308 * either replying to a real or postponed message, therefore no aliases
2309 * should exist since the user has not had the opportunity to add
2310 * addresses to the list. We just have to ensure the postponed messages
2311 * have their aliases expanded. */
2312
2313 if (!TAILQ_EMPTY(&e_templ->env->from))
2314 {
2315 mutt_debug(LL_DEBUG5, "e_templ->env->from before set_reverse_name: %s\n",
2316 TAILQ_FIRST(&e_templ->env->from)->mailbox);
2317 mutt_addrlist_clear(&e_templ->env->from);
2318 }
2319 set_reverse_name(&e_templ->env->from, e_cur->env, sub);
2320 }
2321
2322 const bool c_reply_with_xorig = cs_subset_bool(sub, "reply_with_xorig");
2323 if (e_cur && c_reply_with_xorig && !(flags & (SEND_POSTPONED | SEND_RESEND | SEND_FORWARD)))
2324 {
2325 /* We shouldn't have to worry about freeing 'e_templ->env->from' before
2326 * setting it here since this code will only execute when doing some
2327 * sort of reply. The pointer will only be set when using the -H command
2328 * line option.
2329 *
2330 * If there is already a from address recorded in 'e_templ->env->from',
2331 * then it theoretically comes from `$reverse_name` handling, and we don't use
2332 * the 'X-Orig-To header'. */
2333 if (!TAILQ_EMPTY(&e_cur->env->x_original_to) && TAILQ_EMPTY(&e_templ->env->from))
2334 {
2335 mutt_addrlist_copy(&e_templ->env->from, &e_cur->env->x_original_to, false);
2336 mutt_debug(LL_DEBUG5, "e_templ->env->from extracted from X-Original-To: header: %s\n",
2337 TAILQ_FIRST(&e_templ->env->from)->mailbox);
2338 }
2339 }
2340
2341 const bool c_resume_draft_files = cs_subset_bool(sub, "resume_draft_files");
2342 if (!(flags & (SEND_POSTPONED | SEND_RESEND)) &&
2343 !((flags & SEND_DRAFT_FILE) && c_resume_draft_files))
2344 {
2345 if ((flags & (SEND_REPLY | SEND_FORWARD | SEND_TO_SENDER)) &&
2346 (envelope_defaults(e_templ->env, el, flags, sub) == -1))
2347 {
2348 goto cleanup;
2349 }
2350
2351 const bool c_hdrs = cs_subset_bool(sub, "hdrs");
2352 if (c_hdrs)
2353 process_user_recips(e_templ->env);
2354
2355 /* Expand aliases and remove duplicates/crossrefs */
2356 mutt_expand_aliases_env(e_templ->env);
2357
2358 if (flags & SEND_REPLY)
2359 mutt_fix_reply_recipients(e_templ->env, sub);
2360
2361#ifdef USE_NNTP
2362 if ((flags & SEND_NEWS) && (m && m->type == MUTT_NNTP) && !e_templ->env->newsgroups)
2363 {
2364 e_templ->env->newsgroups = mutt_str_dup(((struct NntpMboxData *) m->mdata)->group);
2365 }
2366#endif
2367
2368 const bool c_auto_edit = cs_subset_bool(sub, "auto_edit");
2369 const bool c_edit_headers = cs_subset_bool(sub, "edit_headers");
2370 const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
2371 if (!(flags & SEND_BATCH) && !(c_auto_edit && c_edit_headers) &&
2372 !((flags & SEND_REPLY) && c_fast_reply))
2373 {
2374 if (edit_envelope(e_templ->env, flags, sub) == -1)
2375 goto cleanup;
2376 }
2377
2378 /* the from address must be set here regardless of whether or not
2379 * $use_from is set so that the '~P' (from you) operator in send-hook
2380 * patterns will work. if $use_from is unset, the from address is killed
2381 * after send-hooks are evaluated */
2382
2383 const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2384 if (killfrom)
2385 {
2387 }
2388
2389 if ((flags & SEND_REPLY) && e_cur)
2390 {
2391 /* change setting based upon message we are replying to */
2393
2394 /* set the replied flag for the message we are generating so that the
2395 * user can use ~Q in a send-hook to know when reply-hook's are also
2396 * being used. */
2397 e_templ->replied = true;
2398 }
2399
2400 /* change settings based upon recipients */
2401
2402 mutt_message_hook(NULL, e_templ, MUTT_SEND_HOOK);
2403
2404 /* Unset the replied flag from the message we are composing since it is
2405 * no longer required. This is done here because the FCC'd copy of
2406 * this message was erroneously get the 'R'eplied flag when stored in
2407 * a maildir-style mailbox. */
2408 e_templ->replied = false;
2409
2410 /* $use_from and/or $from might have changed in a send-hook */
2411 if (killfrom)
2412 {
2413 mutt_addrlist_clear(&e_templ->env->from);
2414
2415 const bool c_use_from = cs_subset_bool(sub, "use_from");
2416 if (c_use_from && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2418 }
2419
2420 if (c_hdrs)
2421 process_user_header(e_templ->env);
2422
2423 if (flags & SEND_BATCH)
2424 {
2425 if (mutt_file_copy_stream(stdin, fp_tmp) < 1)
2426 {
2427 mutt_error(_("Refusing to send an empty email"));
2428 mutt_message(_("Try: echo | neomutt -s 'subject' user@example.com"));
2429 goto cleanup;
2430 }
2431 }
2432
2433 if (!(flags & SEND_BATCH))
2434 mutt_make_greeting(e_templ, fp_tmp, sub);
2435
2436 const bool c_sig_on_top = cs_subset_bool(sub, "sig_on_top");
2437 const char *const c_editor = cs_subset_string(sub, "editor");
2438 if (c_sig_on_top && !(flags & (SEND_KEY | SEND_BATCH)) && c_editor)
2439 {
2440 append_signature(fp_tmp, sub);
2441 }
2442
2443 /* include replies/forwarded messages, unless we are given a template */
2444 if (!tempfile && (m || !(flags & (SEND_REPLY | SEND_FORWARD))) &&
2445 (generate_body(fp_tmp, e_templ, flags, m, el, sub) == -1))
2446 {
2447 goto cleanup;
2448 }
2449
2450 if (!c_sig_on_top && !(flags & (SEND_KEY | SEND_BATCH)) && c_editor)
2451 {
2452 append_signature(fp_tmp, sub);
2453 }
2454 }
2455
2456 /* Only set format=flowed for new messages. postponed/resent/draftfiles
2457 * should respect the original email.
2458 *
2459 * This is set here so that send-hook can be used to turn the option on. */
2460 if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND | SEND_DRAFT_FILE)))
2461 {
2462 const bool c_text_flowed = cs_subset_bool(sub, "text_flowed");
2463 if (c_text_flowed && is_text_plain(e_templ->body))
2464 {
2465 mutt_param_set(&e_templ->body->parameter, "format", "flowed");
2466 }
2467 }
2468
2469 /* This hook is even called for postponed messages, and can, e.g., be used
2470 * for setting the editor, the sendmail path, or the envelope sender. */
2471 mutt_message_hook(NULL, e_templ, MUTT_SEND2_HOOK);
2472
2473 /* wait until now to set the real name portion of our return address so
2474 * that $real_name can be set in a send-hook */
2475 {
2476 struct Address *from = TAILQ_FIRST(&e_templ->env->from);
2477 if (from && !from->personal && !(flags & (SEND_RESEND | SEND_POSTPONED)))
2478 {
2479 const char *const c_real_name = cs_subset_string(sub, "real_name");
2480 from->personal = mutt_str_dup(c_real_name);
2481 }
2482 }
2483
2484 if (!(((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY)))
2485 mutt_file_fclose(&fp_tmp);
2486
2487 if (!(flags & SEND_BATCH))
2488 {
2489 struct stat st = { 0 };
2490 time_t mtime;
2491 struct Body *b = e_templ->body;
2492 while (b->parts)
2493 b = b->parts;
2494 mtime = mutt_file_decrease_mtime(b->filename, NULL);
2495 if (mtime == (time_t) -1)
2496 {
2498 goto cleanup;
2499 }
2500
2501 mutt_update_encoding(b, sub);
2502
2503 const bool c_edit_headers = cs_subset_bool(sub, "edit_headers");
2504 const bool c_auto_edit = cs_subset_bool(sub, "auto_edit");
2505 const enum QuadOption c_forward_edit = cs_subset_quad(sub, "forward_edit");
2506
2507 /* Select whether or not the user's editor should be called now. We
2508 * don't want to do this when:
2509 * 1) we are sending a key/cert
2510 * 2) we are forwarding a message and the user doesn't want to edit it.
2511 * This is controlled by the quadoption $forward_edit. However, if
2512 * both $edit_headers and $auto_edit are set, we want to ignore the
2513 * setting of $forward_edit because the user probably needs to add the
2514 * recipients. */
2515 if (!(flags & SEND_KEY) &&
2516 (((flags & SEND_FORWARD) == 0) || (c_edit_headers && c_auto_edit) ||
2517 (query_quadoption(c_forward_edit, _("Edit forwarded message?")) == MUTT_YES)))
2518 {
2519 /* If the this isn't a text message, look for a mailcap edit command */
2520 const char *const c_editor = cs_subset_string(sub, "editor");
2521 b = e_templ->body;
2522 while (b->parts)
2523 b = b->parts;
2524 if (mutt_needs_mailcap(b))
2525 {
2526 if (!mutt_edit_attachment(b))
2527 goto cleanup;
2528 }
2529 else if (c_edit_headers)
2530 {
2531 mutt_env_to_local(e_templ->env);
2532 mutt_edit_headers(c_editor, b->filename, e_templ, &fcc);
2533 mutt_env_to_intl(e_templ->env, NULL, NULL);
2534 }
2535 else
2536 {
2537 mutt_edit_file(c_editor, b->filename);
2538 if (stat(b->filename, &st) == 0)
2539 {
2540 if (mtime != st.st_mtime)
2542 }
2543 else
2544 {
2546 }
2547 }
2548
2549 mutt_message_hook(NULL, e_templ, MUTT_SEND2_HOOK);
2550 }
2551
2553 {
2554 if (stat(e_templ->body->filename, &st) == 0)
2555 {
2556 const enum QuadOption c_abort_unmodified = cs_subset_quad(sub, "abort_unmodified");
2557
2558 /* if the file was not modified, bail out now */
2559 if ((mtime == st.st_mtime) && !e_templ->body->next &&
2560 (query_quadoption(c_abort_unmodified, _("Abort unmodified message?")) == MUTT_YES))
2561 {
2562 mutt_message(_("Aborted unmodified message"));
2563 goto cleanup;
2564 }
2565 }
2566 else
2567 mutt_perror(e_templ->body->filename);
2568 }
2569 }
2570
2571 /* Set the message security unless:
2572 * 1) crypto support is not enabled (WithCrypto==0)
2573 * 2) pgp: header field was present during message editing with $edit_headers (e_templ->security != 0)
2574 * 3) we are resending a message
2575 * 4) we are recalling a postponed message (don't override the user's saved settings)
2576 * 5) we are in batch mode
2577 *
2578 * This is done after allowing the user to edit the message so that security
2579 * settings can be configured with send2-hook and $edit_headers. */
2580 if ((WithCrypto != 0) && (e_templ->security == 0) &&
2581 !(flags & (SEND_BATCH | SEND_POSTPONED | SEND_RESEND)))
2582 {
2583 bool c_autocrypt = false;
2584 bool c_autocrypt_reply = false;
2585
2586#ifdef USE_AUTOCRYPT
2587 c_autocrypt = cs_subset_bool(sub, "autocrypt");
2588 c_autocrypt_reply = cs_subset_bool(sub, "autocrypt_reply");
2589#endif
2590
2591 if (c_autocrypt && c_autocrypt_reply && e_cur && (e_cur->security & SEC_AUTOCRYPT))
2592 {
2594 }
2595 else
2596 {
2597 const bool c_crypt_auto_sign = cs_subset_bool(sub, "crypt_auto_sign");
2598 const bool c_crypt_auto_encrypt = cs_subset_bool(sub, "crypt_auto_encrypt");
2599 const bool c_crypt_reply_encrypt = cs_subset_bool(sub, "crypt_reply_encrypt");
2600 const bool c_crypt_reply_sign = cs_subset_bool(sub, "crypt_reply_sign");
2601 const bool c_crypt_reply_sign_encrypted = cs_subset_bool(sub, "crypt_reply_sign_encrypted");
2602
2603 if (c_crypt_auto_sign)
2604 e_templ->security |= SEC_SIGN;
2605 if (c_crypt_auto_encrypt)
2606 e_templ->security |= SEC_ENCRYPT;
2607 if (c_crypt_reply_encrypt && e_cur && (e_cur->security & SEC_ENCRYPT))
2608 e_templ->security |= SEC_ENCRYPT;
2609 if (c_crypt_reply_sign && e_cur && (e_cur->security & SEC_SIGN))
2610 e_templ->security |= SEC_SIGN;
2611 if (c_crypt_reply_sign_encrypted && e_cur && (e_cur->security & SEC_ENCRYPT))
2612 e_templ->security |= SEC_SIGN;
2613
2614 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
2615
2616 if (((WithCrypto & APPLICATION_PGP) != 0) &&
2617 ((e_templ->security & (SEC_ENCRYPT | SEC_SIGN)) || c_crypt_opportunistic_encrypt))
2618 {
2619 const bool c_pgp_auto_inline = cs_subset_bool(sub, "pgp_auto_inline");
2620 const bool c_pgp_reply_inline = cs_subset_bool(sub, "pgp_reply_inline");
2621
2622 if (c_pgp_auto_inline)
2623 e_templ->security |= SEC_INLINE;
2624 if (c_pgp_reply_inline && e_cur && (e_cur->security & SEC_INLINE))
2625 e_templ->security |= SEC_INLINE;
2626 }
2627 }
2628
2629 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
2630
2631 if (e_templ->security || c_crypt_opportunistic_encrypt)
2632 {
2633 const bool c_crypt_auto_pgp = cs_subset_bool(sub, "crypt_auto_pgp");
2634 const bool c_crypt_auto_smime = cs_subset_bool(sub, "crypt_auto_smime");
2635
2636 /* When replying / forwarding, use the original message's
2637 * crypto system. According to the documentation,
2638 * smime_is_default should be disregarded here.
2639 *
2640 * Problem: At least with forwarding, this doesn't really
2641 * make much sense. Should we have an option to completely
2642 * disable individual mechanisms at run-time? */
2643 if (e_cur)
2644 {
2645 if (((WithCrypto & APPLICATION_PGP) != 0) && c_crypt_auto_pgp &&
2646 (e_cur->security & APPLICATION_PGP))
2647 {
2648 e_templ->security |= APPLICATION_PGP;
2649 }
2650 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
2651 c_crypt_auto_smime && (e_cur->security & APPLICATION_SMIME))
2652 {
2653 e_templ->security |= APPLICATION_SMIME;
2654 }
2655 }
2656
2657 const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
2658
2659 /* No crypto mechanism selected? Use availability + smime_is_default
2660 * for the decision. */
2661 if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2662 {
2663 if (((WithCrypto & APPLICATION_SMIME) != 0) && c_crypt_auto_smime && c_smime_is_default)
2664 {
2665 e_templ->security |= APPLICATION_SMIME;
2666 }
2667 else if (((WithCrypto & APPLICATION_PGP) != 0) && c_crypt_auto_pgp)
2668 {
2669 e_templ->security |= APPLICATION_PGP;
2670 }
2671 else if (((WithCrypto & APPLICATION_SMIME) != 0) && c_crypt_auto_smime)
2672 {
2673 e_templ->security |= APPLICATION_SMIME;
2674 }
2675 }
2676 }
2677
2678 /* opportunistic encrypt relies on SMIME or PGP already being selected */
2679 if (c_crypt_opportunistic_encrypt)
2680 {
2681 /* If something has already enabled encryption, e.g. `$crypt_auto_encrypt`
2682 * or `$crypt_reply_encrypt`, then don't enable opportunistic encrypt for
2683 * the message. */
2684 if (!(e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
2685 {
2686 e_templ->security |= SEC_OPPENCRYPT;
2688 }
2689 }
2690
2691 /* No permissible mechanisms found. Don't sign or encrypt. */
2692 if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2693 e_templ->security = SEC_NO_FLAGS;
2694 }
2695
2696 /* Deal with the corner case where the crypto module backend is not available.
2697 * This can happen if configured without PGP/SMIME and with GPGME, but
2698 * $crypt_use_gpgme is unset. */
2699 if (e_templ->security && !crypt_has_module_backend(e_templ->security))
2700 {
2701 mutt_error(_("No crypto backend configured. Disabling message security setting."));
2702 e_templ->security = SEC_NO_FLAGS;
2703 }
2704
2705 /* specify a default fcc. if we are in batchmode, only save a copy of
2706 * the message if the value of $copy is yes or ask-yes */
2707
2708 const enum QuadOption c_copy = cs_subset_quad(sub, "copy");
2709
2710 if (mutt_buffer_is_empty(&fcc) && !(flags & SEND_POSTPONED_FCC) &&
2711 (!(flags & SEND_BATCH) || (c_copy & 0x1)))
2712 {
2713 /* set the default FCC */
2714 const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2715 if (killfrom)
2716 {
2718 }
2719 mutt_select_fcc(&fcc, e_templ);
2720 if (killfrom)
2721 {
2722 mutt_addrlist_clear(&e_templ->env->from);
2723 }
2724 }
2725
2726 mutt_rfc3676_space_stuff(e_templ);
2727
2728 mutt_update_encoding(e_templ->body, sub);
2729
2730 if (!(flags & SEND_BATCH))
2731 {
2732 main_loop:
2733
2735 i = mutt_compose_menu(e_templ, &fcc,
2737 sub);
2738 if (i == -1)
2739 {
2740/* abort */
2741#ifdef USE_NNTP
2742 if (flags & SEND_NEWS)
2743 mutt_message(_("Article not posted"));
2744 else
2745#endif
2746 mutt_message(_("Mail not sent"));
2747 goto cleanup;
2748 }
2749 else if (i == 1)
2750 {
2751 if (postpone_message(e_templ, e_cur, mutt_buffer_string(&fcc), flags, sub) != 0)
2752 goto main_loop;
2753 mutt_message(_("Message postponed"));
2754 rc = 1;
2755 goto cleanup;
2756 }
2757 }
2758
2759#ifdef USE_NNTP
2760 if (!(flags & SEND_NEWS))
2761#endif
2762 if ((mutt_addrlist_count_recips(&e_templ->env->to) == 0) &&
2763 (mutt_addrlist_count_recips(&e_templ->env->cc) == 0) &&
2764 (mutt_addrlist_count_recips(&e_templ->env->bcc) == 0))
2765 {
2766 if (flags & SEND_BATCH)
2767 {
2768 puts(_("No recipients specified"));
2769 goto cleanup;
2770 }
2771
2772 mutt_warning(_("No recipients specified"));
2773 goto main_loop;
2774 }
2775
2776 if (mutt_env_to_intl(e_templ->env, &tag, &err))
2777 {
2778 mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
2779 FREE(&err);
2780 if (flags & SEND_BATCH)
2781 goto cleanup;
2782 goto main_loop;
2783 }
2784
2785 const enum QuadOption c_abort_nosubject = cs_subset_quad(sub, "abort_nosubject");
2786
2787 if (!e_templ->env->subject && !(flags & SEND_BATCH) &&
2788 (query_quadoption(c_abort_nosubject, _("No subject, abort sending?")) != MUTT_NO))
2789 {
2790 /* if the abort is automatic, print an error message */
2791 if (c_abort_nosubject == MUTT_YES)
2792 mutt_error(_("No subject specified"));
2793 goto main_loop;
2794 }
2795#ifdef USE_NNTP
2796 if ((flags & SEND_NEWS) && !e_templ->env->subject)
2797 {
2798 mutt_error(_("No subject specified"));
2799 goto main_loop;
2800 }
2801
2802 if ((flags & SEND_NEWS) && !e_templ->env->newsgroups)
2803 {
2804 mutt_error(_("No newsgroup specified"));
2805 goto main_loop;
2806 }
2807#endif
2808
2809 if (!(flags & SEND_BATCH) && abort_for_missing_attachments(e_templ->body, sub))
2810 {
2811 goto main_loop;
2812 }
2813
2814 if (e_templ->body->next)
2815 e_templ->body = mutt_make_multipart(e_templ->body);
2816
2817 /* Ok, we need to do it this way instead of handling all fcc stuff in
2818 * one place in order to avoid going to main_loop with encoded "env"
2819 * in case of error. Ugh. */
2820
2821 mutt_encode_descriptions(e_templ->body, true, sub);
2822
2823 /* Make sure that clear_content and free_clear_content are
2824 * properly initialized -- we may visit this particular place in
2825 * the code multiple times, including after a failed call to
2826 * mutt_protect(). */
2827
2828 clear_content = NULL;
2829 free_clear_content = false;
2830
2831 if (WithCrypto)
2832 {
2833 if (e_templ->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT))
2834 {
2835 /* save the decrypted attachments */
2836 clear_content = e_templ->body;
2837
2838 if ((crypt_get_keys(e_templ, &pgpkeylist, 0) == -1) ||
2839 (mutt_protect(e_templ, pgpkeylist, false) == -1))
2840 {
2841 if (mutt_istr_equal(e_templ->body->subtype, "mixed"))
2842 e_templ->body = mutt_remove_multipart(e_templ->body);
2843
2844 FREE(&pgpkeylist);
2845
2846 decode_descriptions(e_templ->body);
2847 goto main_loop;
2848 }
2849 mutt_encode_descriptions(e_templ->body, false, sub);
2850 }
2851
2852 /* at this point, e_templ->body is one of the following three things:
2853 * - multipart/signed. In this case, clear_content is a child
2854 * - multipart/encrypted. In this case, clear_content exists independently
2855 * - application/pgp. In this case, clear_content exists independently
2856 * - something else. In this case, it's the same as clear_content */
2857
2858 /* This is ugly -- lack of "reporting back" from mutt_protect(). */
2859
2860 if (clear_content && (e_templ->body != clear_content) &&
2861 (e_templ->body->parts != clear_content))
2862 free_clear_content = true;
2863 }
2864
2865 if (!OptNoCurses)
2866 mutt_message(_("Sending message..."));
2867
2868 mutt_prepare_envelope(e_templ->env, true, sub);
2869
2870 const bool c_fcc_before_send = cs_subset_bool(sub, "fcc_before_send");
2871 if (c_fcc_before_send)
2872 save_fcc(m, e_templ, &fcc, clear_content, pgpkeylist, flags, &finalpath, sub);
2873
2874 i = invoke_mta(m, e_templ, sub);
2875 if (i < 0)
2876 {
2877 if (!(flags & SEND_BATCH))
2878 {
2879 if (!WithCrypto)
2880 ; // do nothing
2881 else if ((e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) ||
2882 ((e_templ->security & SEC_SIGN) && (e_templ->body->type == TYPE_APPLICATION)))
2883 {
2884 if (e_templ->body != clear_content)
2885 {
2886 mutt_body_free(&e_templ->body); /* destroy PGP data */
2887 e_templ->body = clear_content; /* restore clear text. */
2888 }
2889 }
2890 else if ((e_templ->security & SEC_SIGN) && (e_templ->body->type == TYPE_MULTIPART))
2891 {
2892 mutt_body_free(&e_templ->body->parts->next); /* destroy sig */
2893 if (mutt_istr_equal(e_templ->body->subtype, "mixed"))
2894 e_templ->body = mutt_remove_multipart(e_templ->body);
2895 }
2896
2897 FREE(&pgpkeylist);
2898 mutt_env_free(&e_templ->body->mime_headers); /* protected headers */
2899 mutt_param_delete(&e_templ->body->parameter, "protected-headers");
2900 if (mutt_istr_equal(e_templ->body->subtype, "mixed"))
2901 e_templ->body = mutt_remove_multipart(e_templ->body);
2902 decode_descriptions(e_templ->body);
2903 mutt_unprepare_envelope(e_templ->env);
2904 FREE(&finalpath);
2905 goto main_loop;
2906 }
2907 else
2908 {
2909 puts(_("Could not send the message"));
2910 goto cleanup;
2911 }
2912 }
2913
2914 if (!c_fcc_before_send)
2915 save_fcc(m, e_templ, &fcc, clear_content, pgpkeylist, flags, &finalpath, sub);
2916
2917 if (!OptNoCurses)
2918 {
2919 mutt_message((i != 0) ? _("Sending in background") :
2920 (flags & SEND_NEWS) ? _("Article posted") : /* USE_NNTP */
2921 _("Mail sent"));
2922#ifdef USE_NOTMUCH
2923 const bool c_nm_record = cs_subset_bool(sub, "nm_record");
2924 if (c_nm_record)
2925 nm_record_message(m, finalpath, e_cur);
2926#endif
2927 mutt_sleep(0);
2928 }
2929
2930 if (WithCrypto)
2931 FREE(&pgpkeylist);
2932
2933 if ((WithCrypto != 0) && free_clear_content)
2934 mutt_body_free(&clear_content);
2935
2936 /* set 'replied' flag only if the user didn't change/remove
2937 * In-Reply-To: and References: headers during edit */
2938 if (flags & SEND_REPLY)
2939 {
2940 if (!(flags & SEND_POSTPONED) && m)
2941 {
2942 STAILQ_FOREACH(en, el, entries)
2943 {
2944 mutt_set_flag(m, en->email, MUTT_REPLIED, is_reply(en->email, e_templ));
2945 }
2946 }
2947 }
2948
2949 rc = 0;
2950
2951cleanup:
2952 mutt_buffer_dealloc(&fcc);
2953
2954 if (flags & SEND_POSTPONED)
2955 {
2957 {
2958 cs_subset_str_string_set(sub, "pgp_sign_as", pgp_sign_as, NULL);
2959 FREE(&pgp_sign_as);
2960 }
2962 {
2963 cs_subset_str_string_set(sub, "smime_sign_as", smime_sign_as, NULL);
2964 FREE(&smime_sign_as);
2965 }
2966 }
2967
2968 mutt_file_fclose(&fp_tmp);
2969 if (!(flags & SEND_NO_FREE_HEADER))
2970 email_free(&e_templ);
2971
2972 FREE(&finalpath);
2973 return rc;
2974}
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1490
int mutt_addrlist_count_recips(const struct AddressList *al)
Count the number of Addresses with valid recipients.
Definition: address.c:844
void mutt_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
Definition: alias.c:312
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:63
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:250
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:292
#define MUTT_COMPOSE_NOFREEHEADER
Definition: lib.h:50
int mutt_compose_menu(struct Email *e, struct Buffer *fcc, uint8_t flags, struct ConfigSubset *sub)
Allow the user to edit the message envelope.
Definition: compose.c:307
int mutt_protect(struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
Definition: crypt.c:159
int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
Check we have all the keys we need.
Definition: crypt.c:941
bool crypt_has_module_backend(SecurityFlags type)
Is there a crypto backend for a given type?
Definition: cryptglue.c:171
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:313
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
int mutt_env_to_intl(struct Envelope *env, const char **tag, char **err)
Convert an Envelope's Address fields to Punycode format.
Definition: envelope.c:326
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:43
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope's Address fields to local format.
Definition: envelope.c:288
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:260
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
time_t mutt_file_decrease_mtime(const char *fp, struct stat *st)
Decrease a file's modification time by 1 second.
Definition: file.c:1019
#define mutt_warning(...)
Definition: logging.h:85
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
void mutt_select_fcc(struct Buffer *path, struct Email *e)
Select the FCC path for an email.
Definition: hook.c:776
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:658
#define MUTT_SEND_HOOK
send-hook: when composing a new email
Definition: hook.h:40
#define MUTT_SEND2_HOOK
send2-hook: when changing fields in the compose menu
Definition: hook.h:49
#define MUTT_REPLY_HOOK
reply-hook: when replying to an email
Definition: hook.h:48
@ LL_DEBUG5
Log at debug level 5.
Definition: logging.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition: mailbox.h:49
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition: multipart.c:126
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: multipart.c:100
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
@ MUTT_REPLIED
Messages that have been replied to.
Definition: mutt.h:92
int mutt_edit_attachment(struct Body *a)
Edit an attachment.
Definition: mutt_attach.c:260
void mutt_edit_headers(const char *editor, const char *body, struct Email *e, struct Buffer *fcc)
Let the user edit the message header and body.
Definition: mutt_header.c:172
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition: muttlib.c:599
bool mutt_needs_mailcap(struct Body *m)
Does this type need a mailcap entry do display.
Definition: muttlib.c:405
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1455
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:71
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:85
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:87
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:77
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:88
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
int nm_record_message(struct Mailbox *m, char *path, struct Email *e)
Add a message to the Notmuch database.
Definition: notmuch.c:1868
bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:53
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:142
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:424
bool mutt_parse_mailto(struct Envelope *env, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1671
int mutt_num_postponed(struct Mailbox *m, bool force)
Return the number of postponed messages.
Definition: postpone.c:69
int mutt_get_postponed(struct Mailbox *m_cur, struct Email *hdr, struct Email **cur, struct Buffer *fcc)
Recall a postponed message.
Definition: postpone.c:667
#define mutt_set_flag(m, e, flag, bf)
Definition: protos.h:64
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
void mutt_rfc3676_space_stuff(struct Email *e)
Perform RFC3676 space stuffing on an Email.
Definition: rfc3676.c:481
static int postpone_message(struct Email *e_post, struct Email *e_cur, const char *fcc, SendFlags flags, struct ConfigSubset *sub)
Save an Email for another day.
Definition: send.c:1949
static int generate_body(FILE *fp_tmp, struct Email *e, SendFlags flags, struct Mailbox *m, struct EmailList *el, struct ConfigSubset *sub)
Create a new email body.
Definition: send.c:1220
static bool is_reply(struct Email *reply, struct Email *orig)
Is one email a reply to another?
Definition: send.c:1687
static int save_fcc(struct Mailbox *m, struct Email *e, struct Buffer *fcc, struct Body *clear_content, char *pgpkeylist, SendFlags flags, char **finalpath, struct ConfigSubset *sub)
Save an Email to a 'sent mail' folder.
Definition: send.c:1752
void mutt_fix_reply_recipients(struct Envelope *env, struct ConfigSubset *sub)
Remove duplicate recipients.
Definition: send.c:1013
static int envelope_defaults(struct Envelope *env, struct EmailList *el, SendFlags flags, struct ConfigSubset *sub)
Fill in some defaults for a new email.
Definition: send.c:1148
static void mutt_make_greeting(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add greetings string.
Definition: send.c:721
static int invoke_mta(struct Mailbox *m, struct Email *e, struct ConfigSubset *sub)
Send an email.
Definition: send.c:1492
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1459
static void process_user_recips(struct Envelope *env)
Process the user headers.
Definition: send.c:371
static void process_user_header(struct Envelope *env)
Process the user headers.
Definition: send.c:398
static int edit_envelope(struct Envelope *en, SendFlags flags, struct ConfigSubset *sub)
Edit Envelope fields.
Definition: send.c:221
static bool abort_for_missing_attachments(const struct Body *b, struct ConfigSubset *sub)
Should we abort sending because of missing attachments?
Definition: send.c:2074
static void set_reverse_name(struct AddressList *al, struct Envelope *env, struct ConfigSubset *sub)
Try to set the 'from' field from the recipients.
Definition: send.c:1407
static void fix_end_of_file(const char *data)
Ensure a file ends with a linefeed.
Definition: send.c:1613
static bool is_text_plain(const struct Body *b)
Is a Body a text/plain MIME part?
Definition: send.c:2063
static void decode_descriptions(struct Body *b)
RFC2047 decode them in case of an error.
Definition: send.c:1596
static void append_signature(FILE *fp, struct ConfigSubset *sub)
Append a signature to an email.
Definition: send.c:95
#define SEND_POSTPONED_FCC
Used by mutt_get_postponed() to signal that the x-mutt-fcc header field was present.
Definition: send.h:48
#define SEND_BATCH
Send email in batch mode (without user interaction)
Definition: send.h:45
#define SEND_NO_FREE_HEADER
Used by the -E flag.
Definition: send.h:49
#define SEND_DRAFT_FILE
Used by the -H flag.
Definition: send.h:50
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:46
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:44
#define SEND_REPLY
Reply to sender.
Definition: send.h:40
#define SEND_NEWS
Reply to a news article.
Definition: send.h:53
#define SEND_FORWARD
Forward email.
Definition: send.h:43
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:793
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:754
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:413
char * personal
Real name of address.
Definition: address.h:37
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:67
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:75
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:47
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
char * subtype
content-type subtype
Definition: body.h:60
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
List of Emails.
Definition: email.h:131
struct Email * email
Email in the list.
Definition: email.h:132
struct Envelope * env
Envelope information.
Definition: email.h:66
struct Body * body
List of MIME parts.
Definition: email.h:67
bool replied
Email has been replied to.
Definition: email.h:49
struct AddressList x_original_to
Email's 'X-Orig-to'.
Definition: envelope.h:66
char * newsgroups
List of newsgroups.
Definition: envelope.h:79
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
char * list_post
This stores a mailto URL, or nothing.
Definition: envelope.h:67
enum MailboxType type
Mailbox type.
Definition: mailbox.h:102
void * mdata
Driver specific data.
Definition: mailbox.h:133
NNTP-specific Mailbox data -.
Definition: mdata.h:33
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:408
+ Here is the caller graph for this function:

◆ mutt_set_followup_to()

void mutt_set_followup_to ( struct Envelope env,
struct ConfigSubset sub 
)

Set followup-to field.

Parameters
envEnvelope to modify
subConfig Subset

Definition at line 1334 of file send.c.

1335{
1336 /* Only generate the Mail-Followup-To if the user has requested it, and
1337 * it hasn't already been set */
1338
1339 const bool c_followup_to = cs_subset_bool(sub, "followup_to");
1340 if (!c_followup_to)
1341 return;
1342#ifdef USE_NNTP
1343 if (OptNewsSend)
1344 {
1345 if (!env->followup_to && env->newsgroups && (strrchr(env->newsgroups, ',')))
1346 env->followup_to = mutt_str_dup(env->newsgroups);
1347 return;
1348 }
1349#endif
1350
1351 if (TAILQ_EMPTY(&env->mail_followup_to))
1352 {
1353 if (mutt_is_list_recipient(false, env))
1354 {
1355 /* this message goes to known mailing lists, so create a proper
1356 * mail-followup-to header */
1357
1358 mutt_addrlist_copy(&env->mail_followup_to, &env->to, false);
1359 mutt_addrlist_copy(&env->mail_followup_to, &env->cc, true);
1360 }
1361
1362 /* remove ourselves from the mail-followup-to header */
1363 remove_user(&env->mail_followup_to, false);
1364
1365 /* If we are not subscribed to any of the lists in question, re-add
1366 * ourselves to the mail-followup-to header. The mail-followup-to header
1367 * generated is a no-op with group-reply, but makes sure list-reply has the
1368 * desired effect. */
1369
1370 if (!TAILQ_EMPTY(&env->mail_followup_to) &&
1372 {
1373 struct AddressList *al = NULL;
1374 if (!TAILQ_EMPTY(&env->reply_to))
1375 al = &env->reply_to;
1376 else if (!TAILQ_EMPTY(&env->from))
1377 al = &env->from;
1378
1379 if (al)
1380 {
1381 struct Address *a = NULL;
1382 TAILQ_FOREACH_REVERSE(a, al, AddressList, entries)
1383 {
1385 }
1386 }
1387 else
1388 {
1390 }
1391 }
1392
1394 }
1395}
void mutt_addrlist_prepend(struct AddressList *al, struct Address *a)
Prepend an Address to an AddressList.
Definition: address.c:1501
int mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *env)
Matches subscribed mailing lists.
Definition: exec.c:459
int mutt_is_list_recipient(bool all_addr, struct Envelope *env)
Matches known mailing lists.
Definition: exec.c:472
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
Definition: queue.h:745
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h:81
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:64
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_send_list_subscribe()

bool mutt_send_list_subscribe ( struct Mailbox m,
struct Email e 
)

Send a mailing-list subscription email.

Parameters
mMailbox
eEmail carrying mailing-list subscription headers
Return values
trueSuccess
falseFailure

Definition at line 3035 of file send.c.

3036{
3037 if (!e || !e->env)
3038 {
3039 return false;
3040 }
3041
3042 const char *mailto = e->env->list_subscribe;
3043 if (!mailto)
3044 {
3045 mutt_warning(_("No List-Subscribe header found"));
3046 return false;
3047 }
3048
3049 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3050 emaillist_add_email(&el, e);
3051 bool rc = send_simple_email(m, &el, mailto, "Subscribe", "subscribe");
3052 emaillist_clear(&el);
3053
3054 return rc;
3055}
static bool send_simple_email(struct Mailbox *m, struct EmailList *el, const char *mailto, const char *subj, const char *body)
Compose an email given a few basic ingredients.
Definition: send.c:2986
char * list_subscribe
This stores a mailto URL, or nothing.
Definition: envelope.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_send_list_unsubscribe()

bool mutt_send_list_unsubscribe ( struct Mailbox m,
struct Email e 
)

Send a mailing-list unsubscription email.

Parameters
mMailbox
eEmail carrying mailing-list unsubscription headers
Return values
trueSuccess
falseFailure

Definition at line 3064 of file send.c.

3065{
3066 if (!e || !e->env)
3067 {
3068 return false;
3069 }
3070
3071 const char *mailto = e->env->list_unsubscribe;
3072 if (!mailto)
3073 {
3074 mutt_warning(_("No List-Unsubscribe header found"));
3075 return false;
3076 }
3077
3078 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3079 emaillist_add_email(&el, e);
3080 bool rc = send_simple_email(m, &el, mailto, "Unsubscribe", "unsubscribe");
3081 emaillist_clear(&el);
3082
3083 return rc;
3084}
char * list_unsubscribe
This stores a mailto URL, or nothing.
Definition: envelope.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function: