NeoMutt  2021-02-05-666-ge300cd
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...
 

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

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.

Typedef Documentation

◆ SendFlags

typedef uint16_t SendFlags

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

Definition at line 36 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 1081 of file send.c.

1083 {
1084  add_references(&env->references, curenv);
1085  add_message_id(&env->references, curenv);
1086  add_message_id(&env->in_reply_to, curenv);
1087 
1088 #ifdef USE_NNTP
1089  const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
1090  if (OptNewsSend && c_x_comment_to && !TAILQ_EMPTY(&curenv->from))
1092 #endif
1093 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define TAILQ_FIRST(head)
Definition: queue.h:723
static void add_references(struct ListHead *head, struct Envelope *env)
Add the email&#39;s references to a list.
Definition: send.c:975
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
static void add_message_id(struct ListHead *head, struct Envelope *env)
Add the email&#39;s message ID to a list.
Definition: send.c:991
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
char * x_comment_to
List of &#39;X-comment-to&#39; fields.
Definition: envelope.h:78
#define TAILQ_EMPTY(head)
Definition: queue.h:721
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:45
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition: sort.c:136
+ 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 1454 of file send.c.

1455 {
1456  /* Note: We let $from override $real_name here.
1457  * Is this the right thing to do?
1458  */
1459 
1460  const struct Address *c_from = cs_subset_address(sub, "from");
1461  const bool c_use_domain = cs_subset_bool(sub, "use_domain");
1462  if (c_from)
1463  {
1464  return mutt_addr_copy(c_from);
1465  }
1466  else if (c_use_domain)
1467  {
1468  struct Address *addr = mutt_addr_new();
1469  mutt_str_asprintf(&addr->mailbox, "%s@%s", NONULL(Username),
1470  NONULL(mutt_fqdn(true, sub)));
1471  return addr;
1472  }
1473  else
1474  {
1475  return mutt_addr_create(NULL, Username);
1476  }
1477 }
#define NONULL(x)
Definition: string2.h:37
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: helpers.c:49
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:716
struct Address * mutt_addr_create(const char *personal, const char *mailbox)
Create and populate a new Address.
Definition: address.c:398
WHERE char * Username
User&#39;s login name.
Definition: mutt_globals.h:48
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:1187
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1128
+ 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 187 of file send.c.

188 {
189  char buf[8192];
190  char *err = NULL;
191  int idna_ok = 0;
192 
193  do
194  {
195  buf[0] = '\0';
197  mutt_addrlist_write(al, buf, sizeof(buf), false);
198  if (mutt_get_field(field, buf, sizeof(buf), MUTT_ALIAS, false, NULL, NULL) != 0)
199  return -1;
201  mutt_addrlist_parse2(al, buf);
202  if (expand_aliases)
204  idna_ok = mutt_addrlist_to_intl(al, &err);
205  if (idna_ok != 0)
206  {
207  mutt_error(_("Bad IDN: '%s'"), err);
208  FREE(&err);
209  }
210  } while (idna_ok != 0);
211  return 0;
212 }
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:300
#define MUTT_ALIAS
Do alias "completion" by calling up the alias-menu.
Definition: mutt.h:53
#define mutt_error(...)
Definition: logging.h:88
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1388
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
int mutt_get_field(const char *field, char *buf, size_t buflen, CompletionFlags complete, bool multiple, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:335
#define _(a)
Definition: message.h:28
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
#define FREE(x)
Definition: memory.h:40
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
+ 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 1573 of file send.c.

1574 {
1575  for (struct Body *t = b; t; t = t->next)
1576  {
1577  if (t->description)
1578  {
1579  const char *const c_send_charset = cs_subset_string(sub, "send_charset");
1580  rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), c_send_charset);
1581  }
1582  if (recurse && t->parts)
1583  mutt_encode_descriptions(t->parts, recurse, sub);
1584  }
1585 }
struct Body * next
next attachment in the list
Definition: body.h:53
The body of an email.
Definition: body.h:34
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:616
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
rfc2047 encode the content-descriptions
Definition: send.c:1573
+ 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 915 of file send.c.

917 {
918  enum QuadOption hmfupto = MUTT_ABORT;
919  const struct Address *followup_to = TAILQ_FIRST(&in->mail_followup_to);
920 
921  if ((flags & (SEND_LIST_REPLY | SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) && followup_to)
922  {
923  char prompt[256];
924  snprintf(prompt, sizeof(prompt), _("Follow-up to %s%s?"), followup_to->mailbox,
925  TAILQ_NEXT(TAILQ_FIRST(&in->mail_followup_to), entries) ? ",..." : "");
926 
927  const enum QuadOption c_honor_followup_to =
928  cs_subset_quad(sub, "honor_followup_to");
929  hmfupto = query_quadoption(c_honor_followup_to, prompt);
930  if (hmfupto == MUTT_ABORT)
931  return -1;
932  }
933 
934  if (flags & SEND_LIST_REPLY)
935  {
936  add_mailing_lists(&out->to, &in->to, &in->cc);
937 
938  if (followup_to && (hmfupto == MUTT_YES) &&
939  (default_to(&out->cc, in, flags & SEND_LIST_REPLY, (hmfupto == MUTT_YES), sub) == MUTT_ABORT))
940  {
941  return -1; /* abort */
942  }
943  }
944  else if (flags & SEND_TO_SENDER)
945  {
946  mutt_addrlist_copy(&out->to, &in->from, false);
947  }
948  else
949  {
950  if (default_to(&out->to, in, flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY),
951  (hmfupto == MUTT_YES), sub) == -1)
952  {
953  return -1; /* abort */
954  }
955 
956  if ((flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) &&
957  (!followup_to || (hmfupto != MUTT_YES)))
958  {
959  /* if(!mutt_addr_is_user(in->to)) */
960  if (flags & SEND_GROUP_REPLY)
961  mutt_addrlist_copy(&out->cc, &in->to, true);
962  else
963  mutt_addrlist_copy(&out->to, &in->to, true);
964  mutt_addrlist_copy(&out->cc, &in->cc, true);
965  }
966  }
967  return 0;
968 }
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:51
#define TAILQ_FIRST(head)
Definition: queue.h:723
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:63
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
#define _(a)
Definition: message.h:28
An email address.
Definition: address.h:35
char * mailbox
Mailbox and host address.
Definition: address.h:38
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
static int default_to(struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
Generate default email addresses.
Definition: send.c:828
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:347
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:42
User aborted the question (with Ctrl-G)
Definition: quad.h:37
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:41
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:160
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:52
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
+ 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 1004 of file send.c.

1005 {
1006  const bool c_me_too = cs_subset_bool(sub, "me_too");
1007  if (!c_me_too)
1008  {
1009  const bool c_reply_self = cs_subset_bool(sub, "reply_self");
1010 
1011  /* the order is important here. do the CC: first so that if the
1012  * the user is the only recipient, it ends up on the TO: field */
1013  remove_user(&env->cc, TAILQ_EMPTY(&env->to));
1014  remove_user(&env->to, TAILQ_EMPTY(&env->cc) || c_reply_self);
1015  }
1016 
1017  /* the CC field can get cluttered, especially with lists */
1018  mutt_addrlist_dedupe(&env->to);
1019  mutt_addrlist_dedupe(&env->cc);
1020  mutt_addrlist_remove_xrefs(&env->to, &env->cc);
1021 
1022  if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
1023  {
1024  TAILQ_SWAP(&env->to, &env->cc, Address, entries);
1025  }
1026 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
An email address.
Definition: address.h:35
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1407
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
void mutt_addrlist_remove_xrefs(const struct AddressList *a, struct AddressList *b)
Remove cross-references.
Definition: address.c:1443
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_EMPTY(head)
Definition: queue.h:721
static void remove_user(struct AddressList *al, bool leave_only)
Remove any address which matches the current user.
Definition: send.c:141
#define TAILQ_SWAP(head1, head2, type, field)
Definition: queue.h:859
+ 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 429 of file send.c.

430 {
431  const char *const c_forward_attribution_intro =
432  cs_subset_string(sub, "forward_attribution_intro");
433  if (!c_forward_attribution_intro || !fp)
434  return;
435 
436  const char *const c_attribution_locale =
437  cs_subset_string(sub, "attribution_locale");
438 
439  char buf[1024];
440  setlocale(LC_TIME, NONULL(c_attribution_locale));
441  mutt_make_string(buf, sizeof(buf), 0, c_forward_attribution_intro, NULL, -1,
442  e, MUTT_FORMAT_NO_FLAGS, NULL);
443  setlocale(LC_TIME, "");
444  fputs(buf, fp);
445  fputs("\n\n", fp);
446 }
#define NONULL(x)
Definition: string2.h:37
#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:1409
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
+ 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 454 of file send.c.

455 {
456  const char *const c_forward_attribution_trailer =
457  cs_subset_string(sub, "forward_attribution_trailer");
458  if (!c_forward_attribution_trailer || !fp)
459  return;
460 
461  const char *const c_attribution_locale =
462  cs_subset_string(sub, "attribution_locale");
463 
464  char buf[1024];
465  setlocale(LC_TIME, NONULL(c_attribution_locale));
466  mutt_make_string(buf, sizeof(buf), 0, c_forward_attribution_trailer, NULL, -1,
467  e, MUTT_FORMAT_NO_FLAGS, NULL);
468  setlocale(LC_TIME, "");
469  fputc('\n', fp);
470  fputs(buf, fp);
471  fputc('\n', fp);
472 }
#define NONULL(x)
Definition: string2.h:37
#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:1409
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
+ 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 618 of file send.c.

619 {
620  const char *const c_attribution = cs_subset_string(sub, "attribution");
621  if (!c_attribution || !fp_out)
622  return;
623 
624  const char *const c_attribution_locale =
625  cs_subset_string(sub, "attribution_locale");
626 
627  char buf[1024];
628  setlocale(LC_TIME, NONULL(c_attribution_locale));
629  mutt_make_string(buf, sizeof(buf), 0, c_attribution, NULL, -1, e,
630  MUTT_FORMAT_NO_FLAGS, NULL);
631  setlocale(LC_TIME, "");
632  fputs(buf, fp_out);
633  fputc('\n', fp_out);
634 }
#define NONULL(x)
Definition: string2.h:37
#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:1409
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
+ 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 1034 of file send.c.

1035 {
1036  if (!env)
1037  return;
1038 
1039  const char *const c_forward_format = cs_subset_string(sub, "forward_format");
1040 
1041  char buf[256];
1042  /* set the default subject for the message. */
1043  mutt_make_string(buf, sizeof(buf), 0, NONULL(c_forward_format), NULL, -1, e,
1044  MUTT_FORMAT_NO_FLAGS, NULL);
1045  mutt_str_replace(&env->subject, buf);
1046 }
#define NONULL(x)
Definition: string2.h:37
#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:1409
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
char * subject
Email&#39;s subject.
Definition: envelope.h:66
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
+ 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 1054 of file send.c.

1056 {
1057  if (!env || !curenv)
1058  return;
1059 
1060  /* This takes precedence over a subject that might have
1061  * been taken from a List-Post header. Is that correct? */
1062  if (curenv->real_subj)
1063  {
1064  FREE(&env->subject);
1065  env->subject = mutt_mem_malloc(mutt_str_len(curenv->real_subj) + 5);
1066  sprintf(env->subject, "Re: %s", curenv->real_subj);
1067  }
1068  else if (!env->subject)
1069  {
1070  const char *const c_empty_subject = cs_subset_string(sub, "empty_subject");
1071  env->subject = mutt_str_dup(c_empty_subject);
1072  }
1073 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
char * real_subj
Offset of the real subject.
Definition: envelope.h:67
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:664
char * subject
Email&#39;s subject.
Definition: envelope.h:66
#define FREE(x)
Definition: memory.h:40
+ 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 729 of file send.c.

730 {
731  const char *const c_post_indent_string =
732  cs_subset_string(sub, "post_indent_string");
733  if (!c_post_indent_string || !fp_out)
734  return;
735 
736  char buf[256];
737  mutt_make_string(buf, sizeof(buf), 0, c_post_indent_string, NULL, -1, e,
738  MUTT_FORMAT_NO_FLAGS, NULL);
739  fputs(buf, fp_out);
740  fputc('\n', fp_out);
741 }
#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:1409
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
+ 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 1632 of file send.c.

1634 {
1635  struct Email *e_new = email_new();
1636 
1637  if (mutt_prepare_template(fp, m, e_new, e_cur, true) < 0)
1638  {
1639  email_free(&e_new);
1640  return -1;
1641  }
1642 
1643  if (WithCrypto)
1644  {
1645  /* mutt_prepare_template doesn't always flip on an application bit.
1646  * so fix that here */
1647  if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1648  {
1649  const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
1650  if (((WithCrypto & APPLICATION_SMIME) != 0) && c_smime_is_default)
1651  e_new->security |= APPLICATION_SMIME;
1652  else if (WithCrypto & APPLICATION_PGP)
1653  e_new->security |= APPLICATION_PGP;
1654  else
1655  e_new->security |= APPLICATION_SMIME;
1656  }
1657 
1658  const bool c_crypt_opportunistic_encrypt =
1659  cs_subset_bool(sub, "crypt_opportunistic_encrypt");
1660  if (c_crypt_opportunistic_encrypt)
1661  {
1662  e_new->security |= SEC_OPPENCRYPT;
1663  crypt_opportunistic_encrypt(m, e_new);
1664  }
1665  }
1666 
1667  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1668  emaillist_add_email(&el, e_cur);
1669  int rc = mutt_send_message(SEND_RESEND, e_new, NULL, m, &el, sub);
1670  emaillist_clear(&el);
1671 
1672  return rc;
1673 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define WithCrypto
Definition: lib.h:113
The envelope/body of an email.
Definition: email.h:37
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
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void crypt_opportunistic_encrypt(struct Mailbox *m, struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1054
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:2125
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
#define SEND_RESEND
Reply using the current email as a template.
Definition: send.h:47
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:159
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:83
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
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:736
+ 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 2125 of file send.c.

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

1330 {
1331  /* Only generate the Mail-Followup-To if the user has requested it, and
1332  * it hasn't already been set */
1333 
1334  const bool c_followup_to = cs_subset_bool(sub, "followup_to");
1335  if (!c_followup_to)
1336  return;
1337 #ifdef USE_NNTP
1338  if (OptNewsSend)
1339  {
1340  if (!env->followup_to && env->newsgroups && (strrchr(env->newsgroups, ',')))
1341  env->followup_to = mutt_str_dup(env->newsgroups);
1342  return;
1343  }
1344 #endif
1345 
1346  if (TAILQ_EMPTY(&env->mail_followup_to))
1347  {
1348  if (mutt_is_list_recipient(false, env))
1349  {
1350  /* this message goes to known mailing lists, so create a proper
1351  * mail-followup-to header */
1352 
1353  mutt_addrlist_copy(&env->mail_followup_to, &env->to, false);
1354  mutt_addrlist_copy(&env->mail_followup_to, &env->cc, true);
1355  }
1356 
1357  /* remove ourselves from the mail-followup-to header */
1358  remove_user(&env->mail_followup_to, false);
1359 
1360  /* If we are not subscribed to any of the lists in question, re-add
1361  * ourselves to the mail-followup-to header. The mail-followup-to header
1362  * generated is a no-op with group-reply, but makes sure list-reply has the
1363  * desired effect. */
1364 
1365  if (!TAILQ_EMPTY(&env->mail_followup_to) &&
1366  !mutt_is_subscribed_list_recipient(false, env))
1367  {
1368  struct AddressList *al = NULL;
1369  if (!TAILQ_EMPTY(&env->reply_to))
1370  al = &env->reply_to;
1371  else if (!TAILQ_EMPTY(&env->from))
1372  al = &env->from;
1373 
1374  if (al)
1375  {
1376  struct Address *a = NULL;
1377  TAILQ_FOREACH_REVERSE(a, al, AddressList, entries)
1378  {
1380  }
1381  }
1382  else
1383  {
1385  }
1386  }
1387 
1389  }
1390 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct AddressList mail_followup_to
Email&#39;s &#39;mail-followup-to&#39;.
Definition: envelope.h:63
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
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
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
An email address.
Definition: address.h:35
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:716
int mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *e)
Matches subscribed mailing lists.
Definition: exec.c:441
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1407
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
Definition: queue.h:745
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
int mutt_is_list_recipient(bool all_addr, struct Envelope *e)
Matches known mailing lists.
Definition: exec.c:454
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default &#39;from&#39; Address.
Definition: send.c:1454
void mutt_addrlist_prepend(struct AddressList *al, struct Address *a)
Prepend an Address to an AddressList.
Definition: address.c:1501
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_EMPTY(head)
Definition: queue.h:721
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:45
static void remove_user(struct AddressList *al, bool leave_only)
Remove any address which matches the current user.
Definition: send.c:141
+ Here is the call graph for this function:
+ Here is the caller graph for this function: