NeoMutt  2025-12-11-1039-g550ac6
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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.

Typedefs

typedef uint32_t SendFlags

Enumerations

enum  SendFlag {
  SEND_NONE = 0 , SEND_REPLY = 1U << 0 , SEND_GROUP_REPLY = 1U << 1 , SEND_LIST_REPLY = 1U << 2 ,
  SEND_FORWARD = 1U << 3 , SEND_POSTPONED = 1U << 4 , SEND_BATCH = 1U << 5 , SEND_KEY = 1U << 6 ,
  SEND_RESEND = 1U << 7 , SEND_POSTPONED_FCC = 1U << 8 , SEND_NO_FREE_HEADER = 1U << 9 , SEND_DRAFT_FILE = 1U << 10 ,
  SEND_TO_SENDER = 1U << 11 , SEND_GROUP_CHAT_REPLY = 1U << 12 , SEND_NEWS = 1U << 13 , SEND_REVIEW_TO = 1U << 14 ,
  SEND_CONSUMED_STDIN = 1U << 15 , SEND_CLI_CRYPTO = 1U << 16
}
 Flags for mutt_send_message(), e.g. More...

Functions

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

Detailed Description

Prepare and send an email.

Authors
  • Richard Russon
  • Pietro Cerutti
  • Alejandro Colomar

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.

Typedef Documentation

◆ SendFlags

typedef uint32_t SendFlags

Definition at line 64 of file send.h.

Enumeration Type Documentation

◆ SendFlag

enum SendFlag

Flags for mutt_send_message(), e.g.

SEND_REPLY

Enumerator
SEND_NONE 

No flags are set.

SEND_REPLY 

Reply to sender.

SEND_GROUP_REPLY 

Reply to all.

SEND_LIST_REPLY 

Reply to mailing list.

SEND_FORWARD 

Forward email.

SEND_POSTPONED 

Recall a postponed email.

SEND_BATCH 

Send email in batch mode (without user interaction).

SEND_KEY 

Mail a PGP public key.

SEND_RESEND 

Reply using the current email as a template.

SEND_POSTPONED_FCC 

Used by mutt_get_postponed() to signal that the Mutt-Fcc header field was present.

SEND_NO_FREE_HEADER 

Used by the -E flag.

SEND_DRAFT_FILE 

Used by the -H flag.

SEND_TO_SENDER 

Compose new email to sender.

SEND_GROUP_CHAT_REPLY 

Reply to all recipients preserving To/Cc.

SEND_NEWS 

Reply to a news article.

SEND_REVIEW_TO 

Allow the user to edit the To field.

SEND_CONSUMED_STDIN 

stdin has been read; don't read it twice

SEND_CLI_CRYPTO 

Enable message security in modes that by default don't enable it.

Definition at line 43 of file send.h.

44{
45 SEND_NONE = 0,
46 SEND_REPLY = 1U << 0,
47 SEND_GROUP_REPLY = 1U << 1,
48 SEND_LIST_REPLY = 1U << 2,
49 SEND_FORWARD = 1U << 3,
50 SEND_POSTPONED = 1U << 4,
51 SEND_BATCH = 1U << 5,
52 SEND_KEY = 1U << 6,
53 SEND_RESEND = 1U << 7,
54 SEND_POSTPONED_FCC = 1U << 8,
55 SEND_NO_FREE_HEADER = 1U << 9,
56 SEND_DRAFT_FILE = 1U << 10,
57 SEND_TO_SENDER = 1U << 11,
58 SEND_GROUP_CHAT_REPLY = 1U << 12,
59 SEND_NEWS = 1U << 13,
60 SEND_REVIEW_TO = 1U << 14,
61 SEND_CONSUMED_STDIN = 1U << 15,
62 SEND_CLI_CRYPTO = 1U << 16,
63};
@ SEND_RESEND
Reply using the current email as a template.
Definition send.h:53
@ SEND_CONSUMED_STDIN
stdin has been read; don't read it twice
Definition send.h:61
@ SEND_KEY
Mail a PGP public key.
Definition send.h:52
@ SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition send.h:58
@ SEND_NO_FREE_HEADER
Used by the -E flag.
Definition send.h:55
@ SEND_REPLY
Reply to sender.
Definition send.h:46
@ SEND_NONE
No flags are set.
Definition send.h:45
@ SEND_BATCH
Send email in batch mode (without user interaction).
Definition send.h:51
@ SEND_FORWARD
Forward email.
Definition send.h:49
@ SEND_GROUP_REPLY
Reply to all.
Definition send.h:47
@ SEND_CLI_CRYPTO
Enable message security in modes that by default don't enable it.
Definition send.h:62
@ SEND_REVIEW_TO
Allow the user to edit the To field.
Definition send.h:60
@ SEND_DRAFT_FILE
Used by the -H flag.
Definition send.h:56
@ SEND_TO_SENDER
Compose new email to sender.
Definition send.h:57
@ SEND_LIST_REPLY
Reply to mailing list.
Definition send.h:48
@ SEND_NEWS
Reply to a news article.
Definition send.h:59
@ SEND_POSTPONED_FCC
Used by mutt_get_postponed() to signal that the Mutt-Fcc header field was present.
Definition send.h:54
@ SEND_POSTPONED
Recall a postponed email.
Definition send.h:50

Function Documentation

◆ mutt_add_to_reference_headers()

void mutt_add_to_reference_headers ( struct Envelope * env,
struct Envelope * env_cur,
struct ConfigSubset * sub )

Generate references for a reply email.

Parameters
envEnvelope for result
env_curEnvelope of source email
subConfig Subset

Definition at line 1040 of file send.c.

1042{
1043 add_references(&env->references, env_cur);
1044 add_message_id(&env->references, env_cur);
1045 add_message_id(&env->in_reply_to, env_cur);
1046
1047 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
1048 if (OptNewsSend && c_x_comment_to && !TAILQ_EMPTY(&env_cur->from))
1050}
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition sort.c:138
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition globals.c:54
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
#define TAILQ_FIRST(head)
Definition queue.h:780
#define TAILQ_EMPTY(head)
Definition queue.h:778
static void add_message_id(struct ListHead *head, struct Envelope *env)
Add the email's message ID to a list.
Definition send.c:949
static void add_references(struct ListHead *head, struct Envelope *env)
Add the email's references to a list.
Definition send.c:938
char * x_comment_to
List of 'X-comment-to' fields.
Definition envelope.h:81
struct ListHead references
message references (in reverse order)
Definition envelope.h:83
struct ListHead in_reply_to
in-reply-to header content
Definition envelope.h:84
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.

Parameters
subConfig Subset
Return values
ptrNewly allocated Address

Definition at line 1405 of file send.c.

1406{
1407 /* Note: We let $from override $real_name here.
1408 * Is this the right thing to do?
1409 */
1410
1411 const struct Address *c_from = cs_subset_address(sub, "from");
1412 if (c_from)
1413 {
1414 return mutt_addr_copy(c_from);
1415 }
1416
1417 char domain[1024] = { 0 };
1418 const char *mailbox = NeoMutt->username;
1419 const bool c_use_domain = cs_subset_bool(sub, "use_domain");
1420 if (c_use_domain)
1421 {
1422 snprintf(domain, sizeof(domain), "%s@%s", NONULL(NeoMutt->username),
1423 NONULL(mutt_fqdn(true, sub)));
1424 mailbox = domain;
1425 }
1426
1427 return mutt_addr_create(NULL, mailbox);
1428}
struct Address * mutt_addr_create(const char *personal, const char *mailbox)
Create and populate a new Address.
Definition address.c:414
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition address.c:756
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition sendlib.c:718
#define NONULL(x)
Definition string2.h:44
An email address.
Definition address.h:35
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
Container for Accounts, Notifications.
Definition neomutt.h:41
char * username
User's login name.
Definition neomutt.h:56
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 184 of file send.c.

185{
186 int rc = 0;
187 struct Buffer *buf = buf_pool_get();
188 buf_alloc(buf, 8192);
189 char *err = NULL;
190 int idna_ok = 0;
191
192 do
193 {
195 buf_reset(buf);
196 mutt_addrlist_write(al, buf, false);
197 if (!buf_is_empty(buf))
198 buf_addstr(buf, ", ");
199
200 if (mw_get_field(field, buf, MUTT_COMP_NONE, HC_ALIAS, &CompleteAliasOps, NULL) != 0)
201 {
202 rc = -1;
203 goto done;
204 }
207 if (expand_aliases)
209 idna_ok = mutt_addrlist_to_intl(al, &err);
210 if (idna_ok != 0)
211 {
212 mutt_error(_("Bad IDN: '%s'"), err);
213 FREE(&err);
214 }
215 } while (idna_ok != 0);
216
217done:
218 buf_pool_release(&buf);
219 return rc;
220}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition address.c:1473
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition address.c:1389
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition address.c:1217
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition address.c:651
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition address.c:1304
const struct CompleteOps CompleteAliasOps
Auto-Completion of Aliases.
Definition complete.c:108
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition alias.c:297
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:342
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
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:502
#define mutt_error(...)
Definition logging2.h:94
@ HC_ALIAS
Aliases.
Definition lib.h:57
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define _(a)
Definition message.h:28
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
String manipulation buffer.
Definition buffer.h:36
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 1501 of file send.c.

1502{
1503 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
1504 for (struct Body *t = b; t; t = t->next)
1505 {
1506 if (t->description)
1507 {
1508 rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), c_send_charset);
1509 }
1510 if (recurse && t->parts)
1511 mutt_encode_descriptions(t->parts, recurse, sub);
1512 }
1513}
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition helpers.c:242
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition rfc2047.c:646
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
RFC2047 encode the content-descriptions.
Definition send.c:1501
The body of an email.
Definition body.h:36
struct Body * next
next attachment in the list
Definition body.h:72
String list.
Definition slist.h:37
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 879 of file send.c.

881{
882 enum QuadOption hmfupto = MUTT_ABORT;
883 const struct Address *followup_to = TAILQ_FIRST(&in->mail_followup_to);
884
885 if ((flags & (SEND_LIST_REPLY | SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) && followup_to)
886 {
887 char prompt[256] = { 0 };
888 snprintf(prompt, sizeof(prompt), _("Follow-up to %s%s?"),
889 buf_string(followup_to->mailbox),
890 TAILQ_NEXT(TAILQ_FIRST(&in->mail_followup_to), entries) ? ",..." : "");
891
892 hmfupto = query_quadoption(prompt, sub, "honor_followup_to");
893 if (hmfupto == MUTT_ABORT)
894 return -1;
895 }
896
897 if (flags & SEND_LIST_REPLY)
898 {
899 add_mailing_lists(&out->to, &in->to, &in->cc);
900
901 if (followup_to && (hmfupto == MUTT_YES) &&
902 (default_to(&out->cc, in, flags & SEND_LIST_REPLY, (hmfupto == MUTT_YES), sub) == MUTT_ABORT))
903 {
904 return -1; /* abort */
905 }
906 }
907 else if (flags & SEND_TO_SENDER)
908 {
909 mutt_addrlist_copy(&out->to, &in->from, false);
910 }
911 else
912 {
913 if (default_to(&out->to, in, flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY),
914 (hmfupto == MUTT_YES), sub) == -1)
915 {
916 return -1; /* abort */
917 }
918
919 if ((flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) &&
920 (!followup_to || (hmfupto != MUTT_YES)))
921 {
922 /* if(!mutt_addr_is_user(in->to)) */
923 if (flags & SEND_GROUP_REPLY)
924 mutt_addrlist_copy(&out->cc, &in->to, true);
925 else
926 mutt_addrlist_copy(&out->to, &in->to, true);
927 mutt_addrlist_copy(&out->cc, &in->cc, true);
928 }
929 }
930 return 0;
931}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition address.c:776
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(const char *prompt, struct ConfigSubset *sub, const char *name)
Ask the user a quad-question.
Definition question.c:384
#define TAILQ_NEXT(elm, field)
Definition queue.h:889
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:157
static int default_to(struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
Generate default email addresses.
Definition send.c:793
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 962 of file send.c.

963{
964 const bool c_me_too = cs_subset_bool(sub, "me_too");
965 if (!c_me_too)
966 {
967 const bool c_reply_self = cs_subset_bool(sub, "reply_self");
968
969 /* the order is important here. do the CC: first so that if the
970 * the user is the only recipient, it ends up on the TO: field */
971 remove_user(&env->cc, TAILQ_EMPTY(&env->to));
972 remove_user(&env->to, TAILQ_EMPTY(&env->cc) || c_reply_self);
973 }
974
975 /* the CC field can get cluttered, especially with lists */
978 mutt_addrlist_remove_xrefs(&env->to, &env->cc);
979
980 if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
981 {
982 TAILQ_SWAP(&env->to, &env->cc, Address, entries);
983 }
984}
void mutt_addrlist_remove_xrefs(const struct AddressList *a, struct AddressList *b)
Remove cross-references.
Definition address.c:1444
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition address.c:1408
#define TAILQ_SWAP(head1, head2, type, field)
Definition queue.h:937
static void remove_user(struct AddressList *al, bool leave_only)
Remove any address which matches the current user.
Definition send.c:137
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 461 of file send.c.

462{
463 const struct Expando *c_forward_attribution_intro = cs_subset_expando(sub, "forward_attribution_intro");
464 if (!c_forward_attribution_intro || !fp)
465 return;
466
467 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
468
469 struct Buffer *buf = buf_pool_get();
470 setlocale(LC_TIME, NONULL(c_attribution_locale));
471 mutt_make_string(buf, -1, c_forward_attribution_intro, NULL, -1, e, MUTT_FORMAT_NONE, NULL);
472 setlocale(LC_TIME, "");
473 fputs(buf_string(buf), fp);
474 fputs("\n\n", fp);
475 buf_pool_release(&buf);
476}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
int mutt_make_string(struct Buffer *buf, size_t max_cols, const struct Expando *exp, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition dlg_index.c:824
@ MUTT_FORMAT_NONE
No flags are set.
Definition render.h:37
Parsed Expando trees.
Definition expando.h:41
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 484 of file send.c.

485{
486 const struct Expando *c_forward_attribution_trailer = cs_subset_expando(sub, "forward_attribution_trailer");
487 if (!c_forward_attribution_trailer || !fp)
488 return;
489
490 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
491
492 struct Buffer *buf = buf_pool_get();
493 setlocale(LC_TIME, NONULL(c_attribution_locale));
494 mutt_make_string(buf, -1, c_forward_attribution_trailer, NULL, -1, e,
495 MUTT_FORMAT_NONE, NULL);
496 setlocale(LC_TIME, "");
497 fputc('\n', fp);
498 fputs(buf_string(buf), fp);
499 fputc('\n', fp);
500 buf_pool_release(&buf);
501}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mutt_make_attribution_intro()

void mutt_make_attribution_intro ( 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 669 of file send.c.

670{
671 format_attribution(cs_subset_expando(sub, "attribution_intro"), e, fp_out, sub);
672}
static void format_attribution(const struct Expando *exp, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Format an attribution prefix/suffix.
Definition send.c:646
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mutt_make_attribution_trailer()

void mutt_make_attribution_trailer ( 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 680 of file send.c.

681{
682 format_attribution(cs_subset_expando(sub, "attribution_trailer"), e, fp_out, sub);
683}
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 992 of file send.c.

993{
994 if (!env)
995 return;
996
997 const struct Expando *c_forward_format = cs_subset_expando(sub, "forward_format");
998
999 struct Buffer *buf = buf_pool_get();
1000 /* set the default subject for the message. */
1001 mutt_make_string(buf, -1, c_forward_format, NULL, -1, e, MUTT_FORMAT_NONE, NULL);
1003 buf_pool_release(&buf);
1004}
void mutt_env_set_subject(struct Envelope *env, const char *subj)
Set both subject and real_subj to subj.
Definition envelope.c:68
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 * env_cur,
struct ConfigSubset * sub )

Set subject for a reply.

Parameters
envEnvelope for result
env_curEnvelope of source email
subConfig Subset

Definition at line 1012 of file send.c.

1014{
1015 if (!env || !env_cur)
1016 return;
1017
1018 /* This takes precedence over a subject that might have
1019 * been taken from a List-Post header. Is that correct? */
1020 if (env_cur->real_subj)
1021 {
1022 char *subj = NULL;
1023 mutt_str_asprintf(&subj, "Re: %s", env_cur->real_subj);
1024 mutt_env_set_subject(env, subj);
1025 FREE(&subj);
1026 }
1027 else if (!env->subject)
1028 {
1029 const char *const c_empty_subject = cs_subset_string(sub, "empty_subject");
1030 mutt_env_set_subject(env, c_empty_subject);
1031 }
1032}
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:809
char *const subject
Email's subject.
Definition envelope.h:70
char *const 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_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 1561 of file send.c.

1563{
1564 struct Email *e_new = email_new();
1565
1566 if (mutt_prepare_template(fp, m, e_new, e_cur, true) < 0)
1567 {
1568 email_free(&e_new);
1569 return -1;
1570 }
1571
1572 if (WithCrypto)
1573 {
1574 /* mutt_prepare_template doesn't always flip on an application bit.
1575 * so fix that here */
1576 if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1577 {
1578 const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
1579 if (((WithCrypto & APPLICATION_SMIME) != 0) && c_smime_is_default)
1580 e_new->security |= APPLICATION_SMIME;
1581 else if (WithCrypto & APPLICATION_PGP)
1582 e_new->security |= APPLICATION_PGP;
1583 else
1584 e_new->security |= APPLICATION_SMIME;
1585 }
1586
1587 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
1588 if (c_crypt_opportunistic_encrypt)
1589 {
1590 e_new->security |= SEC_OPPENCRYPT;
1592 }
1593 }
1594
1595 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
1596 ARRAY_ADD(&ea, e_cur);
1597 int rc = mutt_send_message(SEND_RESEND, e_new, NULL, m, &ea, sub);
1598 ARRAY_FREE(&ea);
1599
1600 return rc;
1601}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
#define ARRAY_HEAD_INITIALIZER
Static initializer for arrays.
Definition array.h:58
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition crypt.c:1052
struct Email * email_new(void)
Create a new Email.
Definition email.c:77
void email_free(struct Email **ptr)
Free an Email.
Definition email.c:46
@ SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:100
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition lib.h:106
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
#define WithCrypto
Definition lib.h:132
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:490
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:2035
The envelope/body of an email.
Definition email.h:39
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
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 EmailArray * ea,
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
eaArray 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 2035 of file send.c.

2037{
2038 struct Buffer *fcc = buf_pool_get(); /* where to copy this message */
2039 FILE *fp_tmp = NULL;
2040 struct Body *pbody = NULL;
2041 int i;
2042 bool free_clear_content = false;
2043
2044 struct Body *clear_content = NULL;
2045 char *pgpkeylist = NULL;
2046 /* save current value of "pgp_sign_as" and "smime_default_key" */
2047 char *pgp_sign_as = NULL;
2048 char *smime_sign_as = NULL;
2049 const char *tag = NULL;
2050 char *err = NULL;
2051 char *finalpath = NULL;
2052 struct Email *e_cur = NULL;
2053
2054 if (ea && (ARRAY_SIZE(ea) == 1))
2055 e_cur = *ARRAY_GET(ea, 0);
2056
2057 int rc = -1;
2058
2059 if (flags & SEND_NEWS)
2060 OptNewsSend = true;
2061 else
2062 OptNewsSend = false;
2063
2064 const enum QuadOption c_recall = cs_subset_quad(sub, "recall");
2065
2066 if (!flags && !e_templ && (c_recall != MUTT_NO) && mutt_num_postponed(m, true))
2067 {
2068 /* If the user is composing a new message, check to see if there
2069 * are any postponed messages first. */
2070 enum QuadOption ans = query_quadoption(_("Recall postponed message?"), sub, "recall");
2071 if (ans == MUTT_ABORT)
2072 return rc;
2073
2074 if (ans == MUTT_YES)
2075 flags |= SEND_POSTPONED;
2076 }
2077
2078 if (flags & SEND_POSTPONED)
2079 {
2081 {
2082 const char *const c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
2083 pgp_sign_as = mutt_str_dup(c_pgp_sign_as);
2084 }
2086 {
2087 const char *const c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
2088 smime_sign_as = mutt_str_dup(c_smime_sign_as);
2089 }
2090 }
2091
2092 /* Delay expansion of aliases until absolutely necessary--shouldn't
2093 * be necessary unless we are prompting the user or about to execute a
2094 * send-hook. */
2095
2096 if (!e_templ)
2097 {
2098 e_templ = email_new();
2099
2100 if (flags == SEND_POSTPONED)
2101 {
2102 rc = mutt_get_postponed(m, e_templ, &e_cur, fcc);
2103 if (rc < 0)
2104 {
2105 flags = SEND_POSTPONED;
2106 goto cleanup;
2107 }
2108 flags = rc;
2109 /* If postponed message is a news article, it have
2110 * a "Newsgroups:" header line, then set appropriate flag. */
2111 if (e_templ->env->newsgroups)
2112 {
2113 flags |= SEND_NEWS;
2114 OptNewsSend = true;
2115 }
2116 else
2117 {
2118 flags &= ~SEND_NEWS;
2119 OptNewsSend = false;
2120 }
2121 }
2122
2123 if (flags & (SEND_POSTPONED | SEND_RESEND))
2124 {
2125 struct Body *b = e_templ->body;
2126 while (b->parts)
2127 b = b->parts;
2128 fp_tmp = mutt_file_fopen(b->filename, "a+");
2129 if (!fp_tmp)
2130 {
2131 mutt_perror("%s", b->filename);
2132 goto cleanup;
2133 }
2134 }
2135
2136 if (!e_templ->env)
2137 e_templ->env = mutt_env_new();
2138 }
2139
2140 /* Parse and use an eventual list-post header */
2141 if ((flags & SEND_LIST_REPLY) && e_cur && e_cur->env && e_cur->env->list_post)
2142 {
2143 /* Use any list-post header as a template */
2144 mutt_parse_mailto(e_templ->env, NULL, e_cur->env->list_post);
2145 /* We don't let them set the sender's address. */
2146 mutt_addrlist_clear(&e_templ->env->from);
2147 }
2148
2149 if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND)))
2150 {
2151 /* When SEND_DRAFT_FILE is set, the caller has already
2152 * created the "parent" body structure. */
2153 if (!(flags & SEND_DRAFT_FILE))
2154 {
2155 pbody = mutt_body_new();
2156 pbody->next = e_templ->body; /* don't kill command-line attachments */
2157 e_templ->body = pbody;
2158
2159 const char *const c_content_type = cs_subset_string(sub, "content_type");
2160 const char *ctype = mutt_str_dup(c_content_type ? c_content_type : "text/plain");
2161 mutt_parse_content_type(ctype, e_templ->body);
2162 FREE(&ctype);
2163 e_templ->body->unlink = true;
2164 e_templ->body->use_disp = false;
2165 e_templ->body->disposition = DISP_INLINE;
2166
2167 if (tempfile)
2168 {
2169 fp_tmp = mutt_file_fopen(tempfile, "a+");
2170 e_templ->body->filename = mutt_str_dup(tempfile);
2171 if (flags & SEND_NO_FREE_HEADER)
2172 e_templ->body->unlink = false;
2173 }
2174 else
2175 {
2176 struct Buffer *buf = buf_pool_get();
2177 buf_mktemp_draft(buf);
2178 fp_tmp = mutt_file_fopen(buf_string(buf), "w+");
2179 e_templ->body->filename = buf_strdup(buf);
2180 buf_pool_release(&buf);
2181 }
2182 }
2183 else
2184 {
2185 struct Body *b = e_templ->body;
2186 while (b->parts)
2187 b = b->parts;
2188 fp_tmp = mutt_file_fopen(b->filename, "a+");
2189 }
2190
2191 if (!fp_tmp)
2192 {
2193 mutt_debug(LL_DEBUG1, "can't create tempfile %s (errno=%d)\n",
2194 e_templ->body->filename, errno);
2195 mutt_perror("%s", e_templ->body->filename);
2196 goto cleanup;
2197 }
2198 }
2199
2200 const bool c_reverse_name = cs_subset_bool(sub, "reverse_name");
2201 /* this is handled here so that the user can match ~f in send-hook */
2202 if (e_cur && c_reverse_name && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2203 {
2204 /* We shouldn't have to worry about alias expansion here since we are
2205 * either replying to a real or postponed message, therefore no aliases
2206 * should exist since the user has not had the opportunity to add
2207 * addresses to the list. We just have to ensure the postponed messages
2208 * have their aliases expanded. */
2209
2210 if (!TAILQ_EMPTY(&e_templ->env->from))
2211 {
2212 mutt_debug(LL_DEBUG5, "e_templ->env->from before set_reverse_name: %s\n",
2213 buf_string(TAILQ_FIRST(&e_templ->env->from)->mailbox));
2214 mutt_addrlist_clear(&e_templ->env->from);
2215 }
2216 set_reverse_name(&e_templ->env->from, e_cur->env, sub);
2217 }
2218
2219 const bool c_reply_with_xorig = cs_subset_bool(sub, "reply_with_xorig");
2220 if (e_cur && c_reply_with_xorig && !(flags & (SEND_POSTPONED | SEND_RESEND | SEND_FORWARD)))
2221 {
2222 /* We shouldn't have to worry about freeing 'e_templ->env->from' before
2223 * setting it here since this code will only execute when doing some
2224 * sort of reply. The pointer will only be set when using the -H command
2225 * line option.
2226 *
2227 * If there is already a from address recorded in 'e_templ->env->from',
2228 * then it theoretically comes from `$reverse_name` handling, and we don't use
2229 * the 'X-Original-To header'. */
2230 if (!TAILQ_EMPTY(&e_cur->env->x_original_to) && TAILQ_EMPTY(&e_templ->env->from))
2231 {
2232 mutt_addrlist_copy(&e_templ->env->from, &e_cur->env->x_original_to, false);
2233 mutt_debug(LL_DEBUG5, "e_templ->env->from extracted from X-Original-To: header: %s\n",
2234 buf_string(TAILQ_FIRST(&e_templ->env->from)->mailbox));
2235 }
2236 }
2237
2238 if (!e_templ->env->message_id)
2239 e_templ->env->message_id = msgid_generate();
2240
2241 const bool c_resume_draft_files = cs_subset_bool(sub, "resume_draft_files");
2242 if (!(flags & (SEND_POSTPONED | SEND_RESEND)) &&
2243 !((flags & SEND_DRAFT_FILE) && c_resume_draft_files))
2244 {
2245 if ((flags & (SEND_REPLY | SEND_FORWARD | SEND_TO_SENDER)) &&
2246 (envelope_defaults(e_templ->env, ea, flags, sub) == -1))
2247 {
2248 goto cleanup;
2249 }
2250
2251 const bool c_hdrs = cs_subset_bool(sub, "hdrs");
2252 if (c_hdrs)
2253 process_user_recips(e_templ->env);
2254
2255 /* Expand aliases and remove duplicates/crossrefs */
2256 mutt_expand_aliases_env(e_templ->env);
2257
2258 if (flags & SEND_REPLY)
2259 mutt_fix_reply_recipients(e_templ->env, sub);
2260
2261 if ((flags & SEND_NEWS) && (m && m->type == MUTT_NNTP) && !e_templ->env->newsgroups)
2262 {
2263 e_templ->env->newsgroups = mutt_str_dup(((struct NntpMboxData *) m->mdata)->group);
2264 }
2265
2266 const bool c_auto_edit = cs_subset_bool(sub, "auto_edit");
2267 const bool c_edit_headers = cs_subset_bool(sub, "edit_headers");
2268 const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
2269 if (!(flags & SEND_BATCH) && !(c_auto_edit && c_edit_headers) &&
2270 !((flags & SEND_REPLY) && c_fast_reply))
2271 {
2272 if (edit_envelope(e_templ->env, flags, sub) == -1)
2273 goto cleanup;
2274 }
2275
2276 /* the from address must be set here regardless of whether or not
2277 * $use_from is set so that the '~P' (from you) operator in send-hook
2278 * patterns will work. if $use_from is unset, the from address is killed
2279 * after send-hooks are evaluated */
2280
2281 const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2282 if (killfrom)
2283 {
2285 }
2286
2287 if ((flags & SEND_REPLY) && e_cur)
2288 {
2289 /* change setting based upon message we are replying to */
2291
2292 /* set the replied flag for the message we are generating so that the
2293 * user can use ~Q in a send-hook to know when reply-hook's are also
2294 * being used. */
2295 e_templ->replied = true;
2296 }
2297
2298 /* change settings based upon recipients */
2299
2300 exec_message_hook(NULL, e_templ, CMD_SEND_HOOK);
2301
2302 /* Unset the replied flag from the message we are composing since it is
2303 * no longer required. This is done here because the FCC'd copy of
2304 * this message was erroneously get the 'R'eplied flag when stored in
2305 * a maildir-style mailbox. */
2306 e_templ->replied = false;
2307
2308 /* $use_from and/or $from might have changed in a send-hook */
2309 if (killfrom)
2310 {
2311 mutt_addrlist_clear(&e_templ->env->from);
2312
2313 const bool c_use_from = cs_subset_bool(sub, "use_from");
2314 if (c_use_from && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2316 }
2317
2318 if (c_hdrs)
2319 process_user_header(e_templ->env);
2320
2321 if ((flags & SEND_BATCH) && !(flags & SEND_CONSUMED_STDIN))
2322 {
2323 if (mutt_file_copy_stream(stdin, fp_tmp) < 0)
2324 {
2325 mutt_error(_("Error sending message"));
2326 goto cleanup;
2327 }
2328 }
2329
2330 if (!(flags & SEND_BATCH))
2331 mutt_make_greeting(e_templ, fp_tmp, sub);
2332
2333 const bool c_sig_on_top = cs_subset_bool(sub, "sig_on_top");
2334 const char *const c_editor = cs_subset_string(sub, "editor");
2335 if (c_sig_on_top && !(flags & (SEND_KEY | SEND_BATCH)) && c_editor)
2336 {
2337 append_signature(fp_tmp, sub);
2338 }
2339
2340 /* include replies/forwarded messages, unless we are given a template */
2341 if (!tempfile && (m || !(flags & (SEND_REPLY | SEND_FORWARD))) &&
2342 (generate_body(fp_tmp, e_templ, flags, m, ea, sub) == -1))
2343 {
2344 goto cleanup;
2345 }
2346
2347 if (!c_sig_on_top && !(flags & (SEND_KEY | SEND_BATCH)) && c_editor)
2348 {
2349 append_signature(fp_tmp, sub);
2350 }
2351 }
2352
2353 /* Only set format=flowed for new messages. postponed/resent/draftfiles
2354 * should respect the original email.
2355 *
2356 * This is set here so that send-hook can be used to turn the option on. */
2357 if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND | SEND_DRAFT_FILE)))
2358 {
2359 const bool c_text_flowed = cs_subset_bool(sub, "text_flowed");
2360 if (c_text_flowed && is_text_plain(e_templ->body))
2361 {
2362 mutt_param_set(&e_templ->body->parameter, "format", "flowed");
2363 }
2364 }
2365
2366 /* This hook is even called for postponed messages, and can, e.g., be used
2367 * for setting the editor, the sendmail path, or the envelope sender. */
2368 exec_message_hook(NULL, e_templ, CMD_SEND2_HOOK);
2369
2370 /* wait until now to set the real name portion of our return address so
2371 * that $real_name can be set in a send-hook */
2372 {
2373 struct Address *from = TAILQ_FIRST(&e_templ->env->from);
2374 if (from && !from->personal && !(flags & (SEND_RESEND | SEND_POSTPONED)))
2375 {
2376 const char *const c_real_name = cs_subset_string(sub, "real_name");
2377 if (c_real_name)
2378 from->personal = buf_new(c_real_name);
2379 }
2380 }
2381
2382 if (!(((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY)))
2383 mutt_file_fclose(&fp_tmp);
2384
2385 if (!(flags & SEND_BATCH))
2386 {
2387 struct stat st = { 0 };
2388 time_t mtime;
2389 struct Body *b = e_templ->body;
2390 while (b->parts)
2391 b = b->parts;
2392 mtime = mutt_file_decrease_mtime(b->filename, NULL);
2393 if (mtime == (time_t) -1)
2394 {
2395 mutt_perror("%s", b->filename);
2396 goto cleanup;
2397 }
2398
2399 mutt_update_encoding(b, sub);
2400
2401 const bool c_edit_headers = cs_subset_bool(sub, "edit_headers");
2402 const bool c_auto_edit = cs_subset_bool(sub, "auto_edit");
2403
2404 /* Select whether or not the user's editor should be called now. We
2405 * don't want to do this when:
2406 * 1) we are sending a key/cert
2407 * 2) we are forwarding a message and the user doesn't want to edit it.
2408 * This is controlled by the quadoption $forward_edit. However, if
2409 * both $edit_headers and $auto_edit are set, we want to ignore the
2410 * setting of $forward_edit because the user probably needs to add the
2411 * recipients. */
2412 if (!(flags & SEND_KEY) &&
2413 (((flags & SEND_FORWARD) == 0) || (c_edit_headers && c_auto_edit) ||
2414 (query_quadoption(_("Edit forwarded message?"), sub, "forward_edit") == MUTT_YES)))
2415 {
2416 /* If the this isn't a text message, look for a mailcap edit command */
2417 const char *const c_editor = cs_subset_string(sub, "editor");
2418 b = e_templ->body;
2419 while (b->parts)
2420 b = b->parts;
2421 if (mutt_needs_mailcap(b))
2422 {
2423 if (!mutt_edit_attachment(b))
2424 goto cleanup;
2425 }
2426 else if (c_edit_headers)
2427 {
2428 mutt_env_to_local(e_templ->env);
2429 mutt_edit_headers(c_editor, b->filename, e_templ, fcc);
2430 mutt_env_to_intl(e_templ->env, NULL, NULL);
2431 }
2432 else
2433 {
2434 mutt_edit_file(c_editor, b->filename);
2435 if (stat(b->filename, &st) == 0)
2436 {
2437 if (mtime != st.st_mtime)
2439 }
2440 else
2441 {
2442 mutt_perror("%s", b->filename);
2443 }
2444 }
2445
2446 exec_message_hook(NULL, e_templ, CMD_SEND2_HOOK);
2447 }
2448
2450 {
2451 if (stat(e_templ->body->filename, &st) == 0)
2452 {
2453 /* if the file was not modified, bail out now */
2454 if ((mtime == st.st_mtime) && !e_templ->body->next &&
2455 (query_quadoption(_("Abort unmodified message?"), sub, "abort_unmodified") == MUTT_YES))
2456 {
2457 mutt_message(_("Aborted unmodified message"));
2458 goto cleanup;
2459 }
2460 }
2461 else
2462 {
2463 mutt_perror("%s", e_templ->body->filename);
2464 }
2465 }
2466 }
2467
2468 /* Set the message security unless:
2469 * 1) crypto support is not enabled (WithCrypto==0)
2470 * 2) pgp: header field was present during message editing with $edit_headers (e_templ->security != 0)
2471 * 3) we are resending a message
2472 * 4) we are recalling a postponed message (don't override the user's saved settings)
2473 * 5) we are in batch mode
2474 * But 3, 4, and 5, can be overridden with '-C' in the command line (flags & SEND_CLI_CRYPTO)
2475 *
2476 * This is done after allowing the user to edit the message so that security
2477 * settings can be configured with send2-hook and $edit_headers. */
2478 if ((WithCrypto != 0) && (e_templ->security == 0) &&
2479 ((flags & SEND_CLI_CRYPTO) || !(flags & (SEND_BATCH | SEND_POSTPONED | SEND_RESEND))))
2480 {
2481 bool c_autocrypt = false;
2482 bool c_autocrypt_reply = false;
2483
2484#ifdef USE_AUTOCRYPT
2485 c_autocrypt = cs_subset_bool(sub, "autocrypt");
2486 c_autocrypt_reply = cs_subset_bool(sub, "autocrypt_reply");
2487#endif
2488
2489 if (c_autocrypt && c_autocrypt_reply && e_cur && (e_cur->security & SEC_AUTOCRYPT))
2490 {
2492 }
2493 else
2494 {
2495 const bool c_crypt_auto_sign = cs_subset_bool(sub, "crypt_auto_sign");
2496 const bool c_crypt_auto_encrypt = cs_subset_bool(sub, "crypt_auto_encrypt");
2497 const bool c_crypt_reply_encrypt = cs_subset_bool(sub, "crypt_reply_encrypt");
2498 const bool c_crypt_reply_sign = cs_subset_bool(sub, "crypt_reply_sign");
2499 const bool c_crypt_reply_sign_encrypted = cs_subset_bool(sub, "crypt_reply_sign_encrypted");
2500
2501 if (c_crypt_auto_sign)
2502 e_templ->security |= SEC_SIGN;
2503 if (c_crypt_auto_encrypt)
2504 e_templ->security |= SEC_ENCRYPT;
2505 if (c_crypt_reply_encrypt && e_cur && (e_cur->security & SEC_ENCRYPT))
2506 e_templ->security |= SEC_ENCRYPT;
2507 if (c_crypt_reply_sign && e_cur && (e_cur->security & SEC_SIGN))
2508 e_templ->security |= SEC_SIGN;
2509 if (c_crypt_reply_sign_encrypted && e_cur && (e_cur->security & SEC_ENCRYPT))
2510 e_templ->security |= SEC_SIGN;
2511
2512 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
2513
2514 if (((WithCrypto & APPLICATION_PGP) != 0) &&
2515 ((e_templ->security & (SEC_ENCRYPT | SEC_SIGN)) || c_crypt_opportunistic_encrypt))
2516 {
2517 const bool c_pgp_auto_inline = cs_subset_bool(sub, "pgp_auto_inline");
2518 const bool c_pgp_reply_inline = cs_subset_bool(sub, "pgp_reply_inline");
2519
2520 if (c_pgp_auto_inline)
2521 e_templ->security |= SEC_INLINE;
2522 if (c_pgp_reply_inline && e_cur && (e_cur->security & SEC_INLINE))
2523 e_templ->security |= SEC_INLINE;
2524 }
2525 }
2526
2527 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
2528
2529 if (e_templ->security || c_crypt_opportunistic_encrypt)
2530 {
2531 const bool c_crypt_auto_pgp = cs_subset_bool(sub, "crypt_auto_pgp");
2532 const bool c_crypt_auto_smime = cs_subset_bool(sub, "crypt_auto_smime");
2533
2534 /* When replying / forwarding, use the original message's
2535 * crypto system. According to the documentation,
2536 * smime_is_default should be disregarded here.
2537 *
2538 * Problem: At least with forwarding, this doesn't really
2539 * make much sense. Should we have an option to completely
2540 * disable individual mechanisms at run-time? */
2541 if (e_cur)
2542 {
2543 if (((WithCrypto & APPLICATION_PGP) != 0) && c_crypt_auto_pgp &&
2544 (e_cur->security & APPLICATION_PGP))
2545 {
2546 e_templ->security |= APPLICATION_PGP;
2547 }
2548 else if (((WithCrypto & APPLICATION_SMIME) != 0) &&
2549 c_crypt_auto_smime && (e_cur->security & APPLICATION_SMIME))
2550 {
2551 e_templ->security |= APPLICATION_SMIME;
2552 }
2553 }
2554
2555 const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
2556
2557 /* No crypto mechanism selected? Use availability + smime_is_default
2558 * for the decision. */
2559 if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2560 {
2561 if (((WithCrypto & APPLICATION_SMIME) != 0) && c_crypt_auto_smime && c_smime_is_default)
2562 {
2563 e_templ->security |= APPLICATION_SMIME;
2564 }
2565 else if (((WithCrypto & APPLICATION_PGP) != 0) && c_crypt_auto_pgp)
2566 {
2567 e_templ->security |= APPLICATION_PGP;
2568 }
2569 else if (((WithCrypto & APPLICATION_SMIME) != 0) && c_crypt_auto_smime)
2570 {
2571 e_templ->security |= APPLICATION_SMIME;
2572 }
2573 }
2574 }
2575
2576 /* opportunistic encrypt relies on SMIME or PGP already being selected */
2577 if (c_crypt_opportunistic_encrypt)
2578 {
2579 /* If something has already enabled encryption, e.g. `$crypt_auto_encrypt`
2580 * or `$crypt_reply_encrypt`, then don't enable opportunistic encrypt for
2581 * the message. */
2582 if (!(e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
2583 {
2584 e_templ->security |= SEC_OPPENCRYPT;
2586 }
2587 }
2588
2589 /* No permissible mechanisms found. Don't sign or encrypt. */
2590 if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2591 e_templ->security = SEC_NONE;
2592 }
2593
2594 /* Deal with the corner case where the crypto module backend is not available.
2595 * This can happen if configured without PGP/SMIME and with GPGME, but
2596 * $crypt_use_gpgme is unset. */
2597 if (e_templ->security && !crypt_has_module_backend(e_templ->security))
2598 {
2599 mutt_error(_("No crypto backend configured. Disabling message security setting."));
2600 e_templ->security = SEC_NONE;
2601 }
2602
2603 /* specify a default fcc. if we are in batchmode, only save a copy of
2604 * the message if the value of $copy is yes or ask-yes */
2605
2606 const enum QuadOption c_copy = cs_subset_quad(sub, "copy");
2607
2608 if (buf_is_empty(fcc) && !(flags & SEND_POSTPONED_FCC) &&
2609 (!(flags & SEND_BATCH) || (c_copy & 0x1)))
2610 {
2611 /* set the default FCC */
2612 const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2613 if (killfrom)
2614 {
2616 }
2617 mutt_select_fcc(fcc, e_templ);
2618 if (killfrom)
2619 {
2620 mutt_addrlist_clear(&e_templ->env->from);
2621 }
2622 }
2623
2624 mutt_rfc3676_space_stuff(e_templ);
2625
2626 mutt_update_encoding(e_templ->body, sub);
2627
2628 if (!(flags & SEND_BATCH))
2629 {
2630 main_loop:
2631
2632 pretty_mailbox(fcc);
2633 i = dlg_compose(e_templ, fcc,
2634 ((flags & SEND_NO_FREE_HEADER) ? MUTT_COMPOSE_NOFREEHEADER : 0), sub);
2635 if (i == -1)
2636 {
2637 /* abort */
2638 if (flags & SEND_NEWS)
2639 mutt_message(_("Article not posted"));
2640 else
2641 mutt_message(_("Mail not sent"));
2642 goto cleanup;
2643 }
2644 else if (i == 1)
2645 {
2646 if (postpone_message(e_templ, e_cur, buf_string(fcc), flags, sub) != 0)
2647 goto main_loop;
2648 mutt_message(_("Message postponed"));
2649 rc = 1;
2650 goto cleanup;
2651 }
2652 }
2653
2654 if (!(flags & SEND_NEWS))
2655 {
2656 if ((mutt_addrlist_count_recips(&e_templ->env->to) == 0) &&
2657 (mutt_addrlist_count_recips(&e_templ->env->cc) == 0) &&
2658 (mutt_addrlist_count_recips(&e_templ->env->bcc) == 0))
2659 {
2660 if (flags & SEND_BATCH)
2661 {
2662 puts(_("No recipients specified"));
2663 goto cleanup;
2664 }
2665
2666 mutt_warning(_("No recipients specified"));
2667 goto main_loop;
2668 }
2669 }
2670
2671 if (mutt_env_to_intl(e_templ->env, &tag, &err))
2672 {
2673 mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
2674 FREE(&err);
2675 if (flags & SEND_BATCH)
2676 goto cleanup;
2677 goto main_loop;
2678 }
2679
2680 const enum QuadOption c_abort_nosubject = cs_subset_quad(sub, "abort_nosubject");
2681
2682 if (!e_templ->env->subject && !(flags & SEND_BATCH) &&
2683 (query_quadoption(_("No subject, abort sending?"), sub, "abort_nosubject") != MUTT_NO))
2684 {
2685 /* if the abort is automatic, print an error message */
2686 if (c_abort_nosubject == MUTT_YES)
2687 mutt_error(_("No subject specified"));
2688 goto main_loop;
2689 }
2690
2691 if ((flags & SEND_NEWS) && !e_templ->env->subject)
2692 {
2693 mutt_error(_("No subject specified"));
2694 goto main_loop;
2695 }
2696
2697 if ((flags & SEND_NEWS) && !e_templ->env->newsgroups)
2698 {
2699 mutt_error(_("No newsgroup specified"));
2700 goto main_loop;
2701 }
2702
2703 if (!(flags & SEND_BATCH) && abort_for_missing_attachments(e_templ->body, sub))
2704 {
2705 goto main_loop;
2706 }
2707
2708 const bool c_confirm_empty_to = cs_subset_bool(sub, "confirm_empty_to");
2709 if (c_confirm_empty_to && TAILQ_EMPTY(&e_templ->env->to) &&
2710 (query_yesorno(_("No recipients specified in To. Send anyway?"), MUTT_NO) == MUTT_NO))
2711 {
2712 goto main_loop;
2713 }
2714
2715 if (e_templ->body->next)
2716 e_templ->body = mutt_make_multipart(e_templ->body);
2717
2718 /* Ok, we need to do it this way instead of handling all fcc stuff in
2719 * one place in order to avoid going to main_loop with encoded "env"
2720 * in case of error. Ugh. */
2721
2722 mutt_encode_descriptions(e_templ->body, true, sub);
2723
2724 /* Make sure that clear_content and free_clear_content are
2725 * properly initialized -- we may visit this particular place in
2726 * the code multiple times, including after a failed call to
2727 * mutt_protect(). */
2728
2729 clear_content = NULL;
2730 free_clear_content = false;
2731
2732 if (WithCrypto)
2733 {
2734 if (e_templ->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT))
2735 {
2736 /* save the decrypted attachments */
2737 clear_content = e_templ->body;
2738
2739 if ((crypt_get_keys(e_templ, &pgpkeylist, false) == -1) ||
2740 (mutt_protect(e_templ, pgpkeylist, false) == -1))
2741 {
2742 if (mutt_istr_equal(e_templ->body->subtype, "mixed"))
2743 e_templ->body = mutt_remove_multipart(e_templ->body);
2744
2745 FREE(&pgpkeylist);
2746
2747 decode_descriptions(e_templ->body);
2748
2749 if (flags & SEND_BATCH)
2750 {
2751 mutt_message(_("Missing encryption key; mail not sent"));
2752 rc = -1;
2753 goto cleanup;
2754 }
2755
2756 goto main_loop;
2757 }
2758 mutt_encode_descriptions(e_templ->body, false, sub);
2759 }
2760
2761 /* at this point, e_templ->body is one of the following three things:
2762 * - multipart/signed. In this case, clear_content is a child
2763 * - multipart/encrypted. In this case, clear_content exists independently
2764 * - application/pgp. In this case, clear_content exists independently
2765 * - something else. In this case, it's the same as clear_content */
2766
2767 /* This is ugly -- lack of "reporting back" from mutt_protect(). */
2768
2769 if (clear_content && (e_templ->body != clear_content) &&
2770 (e_templ->body->parts != clear_content))
2771 free_clear_content = true;
2772 }
2773
2774 if (OptGui)
2775 mutt_message(_("Sending message..."));
2776
2777 mutt_prepare_envelope(e_templ->env, true, sub);
2778
2779 const bool c_fcc_before_send = cs_subset_bool(sub, "fcc_before_send");
2780 if (c_fcc_before_send)
2781 {
2782 if (save_fcc(m, e_templ, fcc, clear_content, pgpkeylist, flags, &finalpath, sub) &&
2783 (flags & SEND_BATCH))
2784 {
2785 /* In batch mode with $fcc_before_send set, abort sending if Fcc fails. */
2786 puts(_("Fcc failed. Aborting sending."));
2787 goto cleanup;
2788 }
2789 }
2790
2791 i = invoke_mta(m, e_templ, sub);
2792 if (i < 0)
2793 {
2794 if (!(flags & SEND_BATCH))
2795 {
2796 if (!WithCrypto)
2797 ; // do nothing
2798 else if ((e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) ||
2799 ((e_templ->security & SEC_SIGN) && (e_templ->body->type == TYPE_APPLICATION)))
2800 {
2801 if (e_templ->body != clear_content)
2802 {
2803 mutt_body_free(&e_templ->body); /* destroy PGP data */
2804 e_templ->body = clear_content; /* restore clear text. */
2805 }
2806 }
2807 else if ((e_templ->security & SEC_SIGN) && (e_templ->body->type == TYPE_MULTIPART))
2808 {
2809 mutt_body_free(&e_templ->body->parts->next); /* destroy sig */
2810 if (mutt_istr_equal(e_templ->body->subtype, "mixed") ||
2811 mutt_istr_equal(e_templ->body->subtype, "signed"))
2812 {
2813 e_templ->body = mutt_remove_multipart(e_templ->body);
2814 }
2815 }
2816
2817 FREE(&pgpkeylist);
2818 mutt_env_free(&e_templ->body->mime_headers); /* protected headers */
2819 mutt_param_delete(&e_templ->body->parameter, "protected-headers");
2820 if (mutt_istr_equal(e_templ->body->subtype, "mixed"))
2821 e_templ->body = mutt_remove_multipart(e_templ->body);
2822 decode_descriptions(e_templ->body);
2823 mutt_unprepare_envelope(e_templ->env);
2824 FREE(&finalpath);
2825 goto main_loop;
2826 }
2827 else
2828 {
2829 puts(_("Could not send the message"));
2830 goto cleanup;
2831 }
2832 }
2833
2834 if (!c_fcc_before_send)
2835 save_fcc(m, e_templ, fcc, clear_content, pgpkeylist, flags, &finalpath, sub);
2836
2837 if (OptGui)
2838 {
2839 mutt_message((i != 0) ? _("Sending in background") :
2840 (flags & SEND_NEWS) ? _("Article posted") :
2841 _("Mail sent"));
2842#ifdef USE_NOTMUCH
2843 const bool c_nm_record = cs_subset_bool(sub, "nm_record");
2844 if (c_nm_record)
2845 nm_record_message(m, finalpath, e_cur);
2846#endif
2847 mutt_sleep(0);
2848 }
2849
2850 if (WithCrypto)
2851 FREE(&pgpkeylist);
2852
2853 if ((WithCrypto != 0) && free_clear_content)
2854 mutt_body_free(&clear_content);
2855
2856 /* set 'replied' flag only if the user didn't change/remove
2857 * In-Reply-To: and References: headers during edit */
2858 if (flags & SEND_REPLY)
2859 {
2860 if (!(flags & SEND_POSTPONED) && m)
2861 {
2862 struct Email **ep = NULL;
2863 ARRAY_FOREACH(ep, ea)
2864 {
2865 struct Email *e = *ep;
2866 mutt_set_flag(m, e, MUTT_REPLIED, is_reply(e, e_templ), true);
2867 }
2868 }
2869 }
2870
2871 rc = 0;
2872
2873cleanup:
2874 buf_pool_release(&fcc);
2875
2876 if (flags & SEND_POSTPONED)
2877 {
2879 {
2880 cs_subset_str_string_set(sub, "pgp_sign_as", pgp_sign_as, NULL);
2881 FREE(&pgp_sign_as);
2882 }
2884 {
2885 cs_subset_str_string_set(sub, "smime_sign_as", smime_sign_as, NULL);
2886 FREE(&smime_sign_as);
2887 }
2888 }
2889
2890 mutt_file_fclose(&fp_tmp);
2891 if (!(flags & SEND_NO_FREE_HEADER))
2892 email_free(&e_templ);
2893
2894 FREE(&finalpath);
2895 return rc;
2896}
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition address.c:1494
int mutt_addrlist_count_recips(const struct AddressList *al)
Count the number of Addresses with valid recipients.
Definition address.c:883
void mutt_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
Definition alias.c:311
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_SIZE(head)
The number of elements stored.
Definition array.h:87
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition buffer.c:311
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
@ CMD_SEND_HOOK
:send-hook
Definition command.h:110
@ CMD_SEND2_HOOK
:send2-hook
Definition command.h:109
@ CMD_REPLY_HOOK
:reply-hook
Definition command.h:105
#define MUTT_COMPOSE_NOFREEHEADER
Don't free the header when closing compose dialog.
Definition lib.h:55
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition helpers.c:192
@ MUTT_NNTP
'NNTP' (Usenet) Mailbox type
Definition mailbox.h:48
int mutt_protect(struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
Definition crypt.c:156
int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
Check we have all the keys we need.
Definition crypt.c:968
bool crypt_has_module_backend(SecurityFlags type)
Is there a crypto backend for a given type?
Definition cryptglue.c:188
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition curs_lib.c:117
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
struct Body * mutt_body_new(void)
Create a new Body.
Definition body.c:44
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 header.c:181
void mutt_parse_content_type(const char *s, struct Body *b)
Parse a content type.
Definition parse.c:464
bool mutt_parse_mailto(struct Envelope *env, char **body, const char *src)
Parse a mailto:// url.
Definition parse.c:1911
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:350
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition envelope.c:45
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope's Address fields to local format.
Definition envelope.c:316
char * msgid_generate(void)
Generate a Message-ID.
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
time_t mutt_file_decrease_mtime(const char *fp, struct stat *st)
Decrease a file's modification time by 1 second.
Definition file.c:898
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
void mutt_set_flag(struct Mailbox *m, struct Email *e, enum MessageType flag, bool bf, bool upd_mbox)
Set a flag on an email.
Definition flags.c:54
bool OptGui
(pseudo) when the gui (and curses) are started
Definition globals.c:48
int dlg_compose(struct Email *e, struct Buffer *fcc, uint8_t flags, struct ConfigSubset *sub)
Allow the user to edit the message envelope -.
#define mutt_warning(...)
Definition logging2.h:92
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
void mutt_select_fcc(struct Buffer *path, struct Email *e)
Select the FCC path for an email.
Definition exec.c:256
void exec_message_hook(struct Mailbox *m, struct Email *e, enum CommandId id)
Perform a message hook.
Definition exec.c:137
@ LL_DEBUG5
Log at debug level 5.
Definition logging2.h:49
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
@ 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:133
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition multipart.c:107
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
@ MUTT_REPLIED
Messages that have been replied to.
Definition mutt.h:91
bool mutt_edit_attachment(struct Body *b)
Edit an attachment.
void mutt_sleep(short s)
Sleep for a while.
Definition muttlib.c:795
void pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using '~' or '='.
Definition muttlib.c:431
bool mutt_needs_mailcap(struct Body *b)
Does this type need a mailcap entry do display.
Definition muttlib.c:368
@ SEC_NONE
No flags are set.
Definition lib.h:91
@ SEC_SIGN
Email is signed.
Definition lib.h:93
@ SEC_INLINE
Email has an inline signature.
Definition lib.h:99
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
@ SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition lib.h:101
@ SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition lib.h:102
int nm_record_message(struct Mailbox *m, char *path, struct Email *e)
Add a message to the Notmuch database.
Definition notmuch.c:1956
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition parameter.c:143
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition parameter.c:111
int mutt_num_postponed(struct Mailbox *m, bool force)
Return the number of postponed messages.
Definition postpone.c:63
int mutt_get_postponed(struct Mailbox *m_cur, struct Email *hdr, struct Email **cur, struct Buffer *fcc)
Recall a postponed message.
Definition postpone.c:665
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition quad.h:38
enum QuadOption query_yesorno(const char *prompt, enum QuadOption def)
Ask the user a Yes/No question.
Definition question.c:329
void mutt_rfc3676_space_stuff(struct Email *e)
Perform RFC3676 space stuffing on an Email.
Definition rfc3676.c:492
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:1857
static bool is_reply(struct Email *reply, struct Email *orig)
Is one email a reply to another?
Definition send.c:1610
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:1674
static int envelope_defaults(struct Envelope *env, struct EmailArray *ea, SendFlags flags, struct ConfigSubset *sub)
Fill in some defaults for a new email.
Definition send.c:1090
void mutt_fix_reply_recipients(struct Envelope *env, struct ConfigSubset *sub)
Remove duplicate recipients.
Definition send.c:962
static int generate_body(FILE *fp_tmp, struct Email *e, SendFlags flags, struct Mailbox *m, struct EmailArray *ea, struct ConfigSubset *sub)
Create a new email body.
Definition send.c:1163
static void mutt_make_greeting(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add greetings string.
Definition send.c:693
static int invoke_mta(struct Mailbox *m, struct Email *e, struct ConfigSubset *sub)
Send an email.
Definition send.c:1438
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition send.c:1405
static void process_user_recips(struct Envelope *env)
Process the user headers.
Definition send.c:379
static void process_user_header(struct Envelope *env)
Process the user headers.
Definition send.c:407
static int edit_envelope(struct Envelope *en, SendFlags flags, struct ConfigSubset *sub)
Edit Envelope fields.
Definition send.c:230
static bool abort_for_missing_attachments(const struct Body *b, struct ConfigSubset *sub)
Should we abort sending because of missing attachments?
Definition send.c:1983
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:1352
static void fix_end_of_file(const char *data)
Ensure a file ends with a linefeed.
Definition send.c:1536
static bool is_text_plain(const struct Body *b)
Is a Body a text/plain MIME part?
Definition send.c:1972
static void decode_descriptions(struct Body *b)
RFC2047 decode them in case of an error.
Definition send.c:1519
static void append_signature(FILE *fp, struct ConfigSubset *sub)
Append a signature to an email.
Definition send.c:100
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition sendlib.c:424
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope().
Definition sendlib.c:790
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition sendlib.c:751
struct Buffer * personal
Real name of address.
Definition address.h:36
struct Body * parts
parts of a multipart or message/rfc822
Definition body.h:73
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition body.h:68
struct Envelope * mime_headers
Memory hole protected headers.
Definition body.h:76
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
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:61
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:59
struct Envelope * env
Envelope information.
Definition email.h:68
struct Body * body
List of MIME parts.
Definition email.h:69
bool replied
Email has been replied to.
Definition email.h:51
char * message_id
Message ID.
Definition envelope.h:73
struct AddressList x_original_to
Email's 'X-Original-to'.
Definition envelope.h:66
char * newsgroups
List of newsgroups.
Definition envelope.h:78
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:104
void * mdata
Driver specific data.
Definition mailbox.h:134
NNTP-specific Mailbox data -.
Definition mdata.h:34
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:392
#define buf_mktemp_draft(buf)
Definition tmp.h:34
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 1281 of file send.c.

1282{
1283 /* Only generate the Mail-Followup-To if the user has requested it, and
1284 * it hasn't already been set */
1285
1286 const bool c_followup_to = cs_subset_bool(sub, "followup_to");
1287 if (!c_followup_to)
1288 return;
1289 if (OptNewsSend)
1290 {
1291 if (!env->followup_to && env->newsgroups && (strrchr(env->newsgroups, ',')))
1292 env->followup_to = mutt_str_dup(env->newsgroups);
1293 return;
1294 }
1295
1296 if (TAILQ_EMPTY(&env->mail_followup_to))
1297 {
1298 if (mutt_is_list_recipient(false, env))
1299 {
1300 /* this message goes to known mailing lists, so create a proper
1301 * mail-followup-to header */
1302
1303 mutt_addrlist_copy(&env->mail_followup_to, &env->to, false);
1304 mutt_addrlist_copy(&env->mail_followup_to, &env->cc, true);
1305 }
1306
1307 /* remove ourselves from the mail-followup-to header */
1308 remove_user(&env->mail_followup_to, false);
1309
1310 /* If we are not subscribed to any of the lists in question, re-add
1311 * ourselves to the mail-followup-to header. The mail-followup-to header
1312 * generated is a no-op with group-reply, but makes sure list-reply has the
1313 * desired effect. */
1314
1315 if (!TAILQ_EMPTY(&env->mail_followup_to) &&
1317 {
1318 struct AddressList *al = NULL;
1319 if (!TAILQ_EMPTY(&env->reply_to))
1320 al = &env->reply_to;
1321 else if (!TAILQ_EMPTY(&env->from))
1322 al = &env->from;
1323
1324 if (al)
1325 {
1326 struct Address *a = NULL;
1327 TAILQ_FOREACH_REVERSE(a, al, AddressList, entries)
1328 {
1330 }
1331 }
1332 else
1333 {
1335 }
1336 }
1337
1339 }
1340}
void mutt_addrlist_prepend(struct AddressList *al, struct Address *a)
Prepend an Address to an AddressList.
Definition address.c:1505
bool mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *env)
Matches subscribed mailing lists.
Definition exec.c:494
bool mutt_is_list_recipient(bool all_addr, struct Envelope *env)
Matches known mailing lists.
Definition exec.c:507
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
Definition queue.h:802
char * followup_to
List of 'followup-to' fields.
Definition envelope.h:80
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 2961 of file send.c.

2962{
2963 if (!e || !e->env)
2964 {
2965 return false;
2966 }
2967
2968 const char *uri = e->env->list_subscribe;
2969 if (!uri)
2970 {
2971 mutt_warning(_("No List-Subscribe header found"));
2972 return false;
2973 }
2974
2975 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
2976 ARRAY_ADD(&ea, e);
2977 bool rc = send_simple_email(m, &ea, uri, "Subscribe", "subscribe");
2978 ARRAY_FREE(&ea);
2979
2980 return rc;
2981}
static bool send_simple_email(struct Mailbox *m, struct EmailArray *ea, const char *mailto, const char *subj, const char *body)
Compose an email given a few basic ingredients.
Definition send.c:2908
char * list_subscribe
This stores a list URI, preferring mailto.
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 2990 of file send.c.

2991{
2992 if (!e || !e->env)
2993 {
2994 return false;
2995 }
2996
2997 const char *uri = e->env->list_unsubscribe;
2998 if (!uri)
2999 {
3000 mutt_warning(_("No List-Unsubscribe header found"));
3001 return false;
3002 }
3003
3004 struct EmailArray ea = ARRAY_HEAD_INITIALIZER;
3005 ARRAY_ADD(&ea, e);
3006 bool rc = send_simple_email(m, &ea, uri, "Unsubscribe", "unsubscribe");
3007 ARRAY_FREE(&ea);
3008
3009 return rc;
3010}
char * list_unsubscribe
This stores a list URI, preferring mailto.
Definition envelope.h:69
Here is the call graph for this function:
Here is the caller graph for this function: