NeoMutt  2021-02-05-666-ge300cd
Teaching an old dog new tricks
DOXYGEN
send.c File Reference

Prepare and send an email. More...

#include "config.h"
#include <errno.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "mutt/lib.h"
#include "address/lib.h"
#include "config/lib.h"
#include "email/lib.h"
#include "core/lib.h"
#include "alias/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "send.h"
#include "lib.h"
#include "compose/lib.h"
#include "ncrypt/lib.h"
#include "pattern/lib.h"
#include "question/lib.h"
#include "attachments.h"
#include "browser.h"
#include "context.h"
#include "copy.h"
#include "format_flags.h"
#include "handler.h"
#include "hdrline.h"
#include "hook.h"
#include "maillist.h"
#include "mutt_attach.h"
#include "mutt_body.h"
#include "mutt_globals.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "options.h"
#include "protos.h"
#include "recvattach.h"
#include "rfc3676.h"
#include "sort.h"
#include "mx.h"
#include "nntp/mdata.h"
#include "remailer.h"
#include "notmuch/lib.h"
#include "imap/lib.h"
#include "autocrypt/lib.h"
+ Include dependency graph for send.c:

Go to the source code of this file.

Data Structures

struct  GreetingInfo
 Data passed to greeting_string() More...
 

Functions

static void append_signature (FILE *fp, struct ConfigSubset *sub)
 Append a signature to an email. More...
 
static void remove_user (struct AddressList *al, bool leave_only)
 Remove any address which matches the current user. More...
 
static void add_mailing_lists (struct AddressList *out, const struct AddressList *t, const struct AddressList *c)
 Search Address lists for mailing lists. More...
 
int mutt_edit_address (struct AddressList *al, const char *field, bool expand_aliases)
 Edit an email address. More...
 
static int edit_envelope (struct Envelope *en, SendFlags flags, struct ConfigSubset *sub)
 Edit Envelope fields. More...
 
static char * nntp_get_header (const char *s)
 Get the trimmed header. More...
 
static void process_user_recips (struct Envelope *env)
 Process the user headers. More...
 
static void process_user_header (struct Envelope *env)
 Process the user headers. 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...
 
static int include_forward (struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Write out a forwarded message. More...
 
static int inline_forward_attachments (struct Mailbox *m, struct Email *e, struct Body ***plast, enum QuadOption *forwardq, struct ConfigSubset *sub)
 Add attachments to an email, inline. More...
 
void mutt_make_attribution (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add "on DATE, PERSON wrote" header. More...
 
static const char * greeting_string (char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
 Format a greetings string. More...
 
static void mutt_make_greeting (struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add greetings string. More...
 
void mutt_make_post_indent (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add suffix to replied email text. More...
 
static int include_reply (struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Generate the reply text for an email. More...
 
static const struct AddressList * choose_default_to (const struct Address *from, const struct Envelope *env, struct ConfigSubset *sub)
 Pick the best 'to:' value. More...
 
static int default_to (struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
 Generate default email addresses. More...
 
int mutt_fetch_recips (struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
 Generate recpients for a reply email. More...
 
static void add_references (struct ListHead *head, struct Envelope *env)
 Add the email's references to a list. More...
 
static void add_message_id (struct ListHead *head, struct Envelope *env)
 Add the email's message ID to a list. More...
 
void mutt_fix_reply_recipients (struct Envelope *env, struct ConfigSubset *sub)
 Remove duplicate recipients. 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_add_to_reference_headers (struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
 Generate references for a reply email. More...
 
static void make_reference_headers (struct EmailList *el, struct Envelope *env, struct ConfigSubset *sub)
 Generate reference headers for an email. More...
 
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. More...
 
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. More...
 
void mutt_set_followup_to (struct Envelope *env, struct ConfigSubset *sub)
 Set followup-to field. More...
 
static void set_reverse_name (struct AddressList *al, struct Envelope *env, struct ConfigSubset *sub)
 Try to set the 'from' field from the recipients. More...
 
struct Addressmutt_default_from (struct ConfigSubset *sub)
 Get a default 'from' Address. More...
 
static int invoke_mta (struct Mailbox *m, struct Email *e, struct ConfigSubset *sub)
 Send an email. More...
 
void mutt_encode_descriptions (struct Body *b, bool recurse, struct ConfigSubset *sub)
 rfc2047 encode the content-descriptions More...
 
static void decode_descriptions (struct Body *b)
 rfc2047 decode them in case of an error More...
 
static void fix_end_of_file (const char *data)
 Ensure a file ends with a linefeed. More...
 
int mutt_resend_message (FILE *fp, struct Mailbox *m, struct Email *e_cur, struct ConfigSubset *sub)
 Resend an email. More...
 
static bool is_reply (struct Email *reply, struct Email *orig)
 Is one email a reply to another? More...
 
static bool search_attach_keyword (char *filename, struct ConfigSubset *sub)
 Search an email for 'attachment' keywords. More...
 
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. More...
 
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. More...
 
static bool is_text_plain (const struct Body *b)
 is a Body a text/plain MIME part? More...
 
static bool abort_for_missing_attachments (const struct Body *b, struct ConfigSubset *sub)
 Should we abort sending because of missing attachments? 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...
 

Detailed Description

Prepare and send an email.

Authors
  • Michael R. Elkins
  • Pietro Cerutti

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

Function Documentation

◆ append_signature()

static void append_signature ( FILE *  fp,
struct ConfigSubset sub 
)
static

Append a signature to an email.

Parameters
fpFile to write to
subConfig Subset

Definition at line 104 of file send.c.

105 {
106  const char *const c_signature = cs_subset_path(sub, "signature");
107  if (!c_signature)
108  return;
109 
110  // If the user hasn't set $signature, don't warn them if it doesn't exist
111  struct Buffer *def_sig = mutt_buffer_pool_get();
112  cs_str_initial_get(sub->cs, "signature", def_sig);
113  mutt_path_canon(def_sig->data, def_sig->dsize, HomeDir, false);
114  bool notify_missing = !mutt_str_equal(c_signature, mutt_buffer_string(def_sig));
115  mutt_buffer_pool_release(&def_sig);
116 
117  pid_t pid = 0;
118  FILE *fp_tmp = mutt_open_read(c_signature, &pid);
119  if (!fp_tmp)
120  {
121  if (notify_missing)
122  mutt_perror(c_signature);
123  return;
124  }
125 
126  const bool c_sig_dashes = cs_subset_bool(sub, "sig_dashes");
127  if (c_sig_dashes)
128  fputs("\n-- \n", fp);
129  mutt_file_copy_stream(fp_tmp, fp);
130  mutt_file_fclose(&fp_tmp);
131  if (pid != -1)
132  filter_wait(pid);
133 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
#define mutt_perror(...)
Definition: logging.h:89
char * HomeDir
User&#39;s home directory.
Definition: mutt_globals.h:45
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
size_t dsize
Length of data.
Definition: buffer.h:37
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
int cs_str_initial_get(const struct ConfigSet *cs, const char *name, struct Buffer *result)
Get the initial, or parent, value of a config item.
Definition: set.c:520
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
char * data
Pointer to data.
Definition: buffer.h:35
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool mutt_path_canon(char *buf, size_t buflen, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition: path.c:285
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:271
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition: muttlib.c:1315
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ remove_user()

static void remove_user ( struct AddressList *  al,
bool  leave_only 
)
static

Remove any address which matches the current user.

Parameters
alList of addresses
leave_onlyIf set, don't remove the user's address if it it the only one in the list

Definition at line 141 of file send.c.

142 {
143  struct Address *a = NULL, *tmp = NULL;
144  TAILQ_FOREACH_SAFE(a, al, entries, tmp)
145  {
146  if (mutt_addr_is_user(a) && (!leave_only || TAILQ_NEXT(a, entries)))
147  {
148  TAILQ_REMOVE(al, a, entries);
149  mutt_addr_free(&a);
150  }
151  }
152 }
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
An email address.
Definition: address.h:35
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:562
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_mailing_lists()

static void add_mailing_lists ( struct AddressList *  out,
const struct AddressList *  t,
const struct AddressList *  c 
)
static

Search Address lists for mailing lists.

Parameters
outAddress list where to append matching mailing lists
t'To' Address list
c'Cc' Address list

Definition at line 160 of file send.c.

162 {
163  const struct AddressList *const als[] = { t, c };
164 
165  for (size_t i = 0; i < mutt_array_size(als); ++i)
166  {
167  const struct AddressList *al = als[i];
168  struct Address *a = NULL;
169  TAILQ_FOREACH(a, al, entries)
170  {
171  if (!a->group && mutt_is_mail_list(a))
172  {
174  }
175  }
176  }
177 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t.
Definition: maillist.c:44
An email address.
Definition: address.h:35
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:716
#define mutt_array_size(x)
Definition: memory.h:33
bool group
Group mailbox?
Definition: address.h:39
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1490
+ 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:

◆ edit_envelope()

static int edit_envelope ( struct Envelope en,
SendFlags  flags,
struct ConfigSubset sub 
)
static

Edit Envelope fields.

Parameters
enEnvelope to edit
flagsFlags, see SendFlags
subConfig Subset
Return values
0Success
-1Failure

Definition at line 222 of file send.c.

223 {
224  char buf[8192];
225 
226 #ifdef USE_NNTP
227  if (OptNewsSend)
228  {
229  if (en->newsgroups)
230  mutt_str_copy(buf, en->newsgroups, sizeof(buf));
231  else
232  buf[0] = '\0';
233  if (mutt_get_field("Newsgroups: ", buf, sizeof(buf), MUTT_COMP_NO_FLAGS,
234  false, NULL, NULL) != 0)
235  {
236  return -1;
237  }
238  FREE(&en->newsgroups);
239  en->newsgroups = mutt_str_dup(buf);
240 
241  if (en->followup_to)
242  mutt_str_copy(buf, en->followup_to, sizeof(buf));
243  else
244  buf[0] = '\0';
245 
246  const bool c_ask_follow_up = cs_subset_bool(sub, "ask_follow_up");
247  if (c_ask_follow_up && (mutt_get_field("Followup-To: ", buf, sizeof(buf),
248  MUTT_COMP_NO_FLAGS, false, NULL, NULL) != 0))
249  {
250  return -1;
251  }
252  FREE(&en->followup_to);
253  en->followup_to = mutt_str_dup(buf);
254 
255  if (en->x_comment_to)
256  mutt_str_copy(buf, en->x_comment_to, sizeof(buf));
257  else
258  buf[0] = '\0';
259 
260  const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
261  const bool c_ask_x_comment_to = cs_subset_bool(sub, "ask_x_comment_to");
262  if (c_x_comment_to && c_ask_x_comment_to &&
263  (mutt_get_field("X-Comment-To: ", buf, sizeof(buf), MUTT_COMP_NO_FLAGS,
264  false, NULL, NULL) != 0))
265  {
266  return -1;
267  }
268  FREE(&en->x_comment_to);
269  en->x_comment_to = mutt_str_dup(buf);
270  }
271  else
272 #endif
273  {
274  if ((mutt_edit_address(&en->to, _("To: "), true) == -1) || TAILQ_EMPTY(&en->to))
275  return -1;
276 
277  const bool c_ask_cc = cs_subset_bool(sub, "ask_cc");
278  if (c_ask_cc && (mutt_edit_address(&en->cc, _("Cc: "), true) == -1))
279  return -1;
280 
281  const bool c_ask_bcc = cs_subset_bool(sub, "ask_bcc");
282  if (c_ask_bcc && (mutt_edit_address(&en->bcc, _("Bcc: "), true) == -1))
283  return -1;
284 
285  const bool c_reply_with_xorig = cs_subset_bool(sub, "reply_with_xorig");
286  if (c_reply_with_xorig && (flags & (SEND_REPLY | SEND_LIST_REPLY | SEND_GROUP_REPLY)) &&
287  (mutt_edit_address(&en->from, "From: ", true) == -1))
288  {
289  return -1;
290  }
291  }
292 
293  if (en->subject)
294  {
295  const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
296  if (c_fast_reply)
297  return 0;
298  mutt_str_copy(buf, en->subject, sizeof(buf));
299  }
300  else
301  {
302  const char *p = NULL;
303 
304  buf[0] = '\0';
305  struct ListNode *uh = NULL;
306  STAILQ_FOREACH(uh, &UserHeader, entries)
307  {
308  size_t plen = mutt_istr_startswith(uh->data, "subject:");
309  if (plen)
310  {
311  p = mutt_str_skip_email_wsp(uh->data + plen);
312  mutt_str_copy(buf, p, sizeof(buf));
313  }
314  }
315  }
316 
317  const enum QuadOption c_abort_nosubject =
318  cs_subset_quad(sub, "abort_nosubject");
319  if ((mutt_get_field(_("Subject: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS,
320  false, NULL, NULL) != 0) ||
321  ((buf[0] == '\0') &&
322  (query_quadoption(c_abort_nosubject, _("No subject, abort?")) != MUTT_NO)))
323  {
324  mutt_message(_("No subject, aborting"));
325  return -1;
326  }
327  mutt_str_replace(&en->subject, buf);
328 
329  return 0;
330 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
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
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
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
char * x_comment_to
List of &#39;X-comment-to&#39; fields.
Definition: envelope.h:78
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:776
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define SEND_REPLY
Reply to sender.
Definition: send.h:40
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
char * data
String.
Definition: list.h:36
char * subject
Email&#39;s subject.
Definition: envelope.h:66
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:446
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
#define mutt_message(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:40
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
#define TAILQ_EMPTY(head)
Definition: queue.h:721
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:45
A List node for strings.
Definition: list.h:34
int mutt_edit_address(struct AddressList *al, const char *field, bool expand_aliases)
Edit an email address.
Definition: send.c:187
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nntp_get_header()

static char* nntp_get_header ( const char *  s)
static

Get the trimmed header.

Parameters
sHeader line with leading whitespace
Return values
ptrCopy of string
Note
The caller should free the returned string.

Definition at line 340 of file send.c.

341 {
342  SKIPWS(s);
343  return mutt_str_dup(s);
344 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define SKIPWS(ch)
Definition: string2.h:46
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ process_user_recips()

static void process_user_recips ( struct Envelope env)
static

Process the user headers.

Parameters
envEnvelope to populate

Definition at line 351 of file send.c.

352 {
353  struct ListNode *uh = NULL;
354  STAILQ_FOREACH(uh, &UserHeader, entries)
355  {
356  size_t plen;
357  if ((plen = mutt_istr_startswith(uh->data, "to:")))
358  mutt_addrlist_parse(&env->to, uh->data + plen);
359  else if ((plen = mutt_istr_startswith(uh->data, "cc:")))
360  mutt_addrlist_parse(&env->cc, uh->data + plen);
361  else if ((plen = mutt_istr_startswith(uh->data, "bcc:")))
362  mutt_addrlist_parse(&env->bcc, uh->data + plen);
363 #ifdef USE_NNTP
364  else if ((plen = mutt_istr_startswith(uh->data, "newsgroups:")))
365  env->newsgroups = nntp_get_header(uh->data + plen);
366  else if ((plen = mutt_istr_startswith(uh->data, "followup-to:")))
367  env->followup_to = nntp_get_header(uh->data + plen);
368  else if ((plen = mutt_istr_startswith(uh->data, "x-comment-to:")))
369  env->x_comment_to = nntp_get_header(uh->data + plen);
370 #endif
371  }
372 }
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
static char * nntp_get_header(const char *s)
Get the trimmed header.
Definition: send.c:340
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
char * x_comment_to
List of &#39;X-comment-to&#39; fields.
Definition: envelope.h:78
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
char * data
String.
Definition: list.h:36
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
A List node for strings.
Definition: list.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ process_user_header()

static void process_user_header ( struct Envelope env)
static

Process the user headers.

Parameters
envEnvelope to populate

Definition at line 378 of file send.c.

379 {
380  struct ListNode *uh = NULL;
381  STAILQ_FOREACH(uh, &UserHeader, entries)
382  {
383  size_t plen;
384  if ((plen = mutt_istr_startswith(uh->data, "from:")))
385  {
386  /* User has specified a default From: address. Remove default address */
387  mutt_addrlist_clear(&env->from);
388  mutt_addrlist_parse(&env->from, uh->data + plen);
389  }
390  else if ((plen = mutt_istr_startswith(uh->data, "reply-to:")))
391  {
393  mutt_addrlist_parse(&env->reply_to, uh->data + plen);
394  }
395  else if ((plen = mutt_istr_startswith(uh->data, "message-id:")))
396  {
397  char *tmp = mutt_extract_message_id(uh->data + plen, NULL);
398  if (mutt_addr_valid_msgid(tmp))
399  {
400  FREE(&env->message_id);
401  env->message_id = tmp;
402  }
403  else
404  FREE(&tmp);
405  }
406  else if (!mutt_istr_startswith(uh->data, "to:") &&
407  !mutt_istr_startswith(uh->data, "cc:") &&
408  !mutt_istr_startswith(uh->data, "bcc:") &&
409 #ifdef USE_NNTP
410  !mutt_istr_startswith(uh->data, "newsgroups:") &&
411  !mutt_istr_startswith(uh->data, "followup-to:") &&
412  !mutt_istr_startswith(uh->data, "x-comment-to:") &&
413 #endif
414  !mutt_istr_startswith(uh->data, "supersedes:") &&
415  !mutt_istr_startswith(uh->data, "subject:") &&
416  !mutt_istr_startswith(uh->data, "return-path:"))
417  {
419  }
420  }
421 }
struct AddressList reply_to
Email&#39;s &#39;reply-to&#39;.
Definition: envelope.h:62
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1470
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
struct ListHead userhdrs
user defined headers
Definition: envelope.h:83
char * message_id
Message ID.
Definition: envelope.h:69
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
char * mutt_extract_message_id(const char *s, size_t *len)
Find a message-id.
Definition: parse.c:363
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:172
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
char * data
String.
Definition: list.h:36
bool mutt_addr_valid_msgid(const char *msgid)
Is this a valid Message ID?
Definition: address.c:764
#define FREE(x)
Definition: memory.h:40
A List node for strings.
Definition: list.h:34
+ 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:

◆ include_forward()

static int include_forward ( struct Mailbox m,
struct Email e,
FILE *  fp_out,
struct ConfigSubset sub 
)
static

Write out a forwarded message.

Parameters
mMailbox
eEmail
fp_outFile to write to
subConfig Subset
Return values
0Success
-1Failure

Definition at line 483 of file send.c.

485 {
486  CopyHeaderFlags chflags = CH_DECODE;
488 
489  struct Message *msg = mx_msg_open(m, e->msgno);
490  if (!msg)
491  {
492  return -1;
493  }
494  mutt_parse_mime_message(m, e, msg->fp);
496 
497  const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
498  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) && c_forward_decode)
499  {
500  /* make sure we have the user's passphrase before proceeding... */
502  {
503  mx_msg_close(m, &msg);
504  return -1;
505  }
506  }
507 
508  mutt_forward_intro(e, fp_out, sub);
509 
510  if (c_forward_decode)
511  {
512  cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
513 
514  const bool c_weed = cs_subset_bool(sub, "weed");
515  if (c_weed)
516  {
517  chflags |= CH_WEED | CH_REORDER;
518  cmflags |= MUTT_CM_WEED;
519  }
520  }
521 
522  const bool c_forward_quote = cs_subset_bool(sub, "forward_quote");
523  if (c_forward_quote)
524  cmflags |= MUTT_CM_PREFIX;
525 
526  mutt_copy_message(fp_out, m, e, msg, cmflags, chflags, 0);
527  mx_msg_close(m, &msg);
528  mutt_forward_trailer(e, fp_out, sub);
529  return 0;
530 }
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:591
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_forward_intro(struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add the "start of forwarded message" text.
Definition: send.c:429
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:41
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:46
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:32
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1186
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:135
#define CH_WEED
Weed the headers?
Definition: copy.h:53
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:37
A local copy of an email.
Definition: mxapi.h:41
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:38
#define CH_REORDER
Re-order output of headers (specified by &#39;hdr_order&#39;)
Definition: copy.h:59
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:54
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
void mutt_forward_trailer(struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add a "end of forwarded message" text.
Definition: send.c:454
FILE * fp
pointer to the message data
Definition: mxapi.h:43
int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:853
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:598
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1140
int msgno
Number displayed to the user.
Definition: email.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ inline_forward_attachments()

static int inline_forward_attachments ( struct Mailbox m,
struct Email e,
struct Body ***  plast,
enum QuadOption forwardq,
struct ConfigSubset sub 
)
static

Add attachments to an email, inline.

Parameters
[in]mMailbox
[in]eCurrent Email
[out]plastPointer to the last Attachment
[out]forwardqResult of asking the user to forward the attachments, e.g. MUTT_YES
[in]subConfig Subset
Return values
0Success
-1Error

Definition at line 542 of file send.c.

545 {
546  struct Body **last = *plast;
547  struct Body *body = NULL;
548  struct AttachCtx *actx = NULL;
549  int rc = 0, i;
550 
551  struct Message *msg = mx_msg_open(m, e->msgno);
552  if (!msg)
553  {
554  return -1;
555  }
556 
557  mutt_parse_mime_message(m, e, msg->fp);
559 
560  actx = mutt_mem_calloc(1, sizeof(*actx));
561  actx->email = e;
562  actx->fp_root = msg->fp;
563 
564  mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
565  actx->fp_root, -1, 0, 0);
566 
567  for (i = 0; i < actx->idxlen; i++)
568  {
569  body = actx->idx[i]->body;
570  if ((body->type != TYPE_MULTIPART) && !mutt_can_decode(body) &&
571  !((body->type == TYPE_APPLICATION) &&
572  (mutt_istr_equal(body->subtype, "pgp-signature") ||
573  mutt_istr_equal(body->subtype, "x-pkcs7-signature") ||
574  mutt_istr_equal(body->subtype, "pkcs7-signature"))))
575  {
576  /* Ask the quadoption only once */
577  if (*forwardq == MUTT_ABORT)
578  {
579  const enum QuadOption c_forward_attachments =
580  cs_subset_quad(sub, "forward_attachments");
581  *forwardq = query_quadoption(c_forward_attachments,
582  /* L10N: This is the prompt for $forward_attachments.
583  When inline forwarding ($mime_forward answered "no"), this prompts
584  whether to add non-decodable attachments from the original email.
585  Text/plain parts and the like will already be included in the
586  message contents, but other attachment, such as PDF files, will also
587  be added as attachments to the new mail, if this is answered yes. */
588  _("Forward attachments?"));
589  if (*forwardq != MUTT_YES)
590  {
591  if (*forwardq == -1)
592  rc = -1;
593  goto cleanup;
594  }
595  }
596  if (mutt_body_copy(actx->idx[i]->fp, last, body) == -1)
597  {
598  rc = -1;
599  goto cleanup;
600  }
601  last = &((*last)->next);
602  }
603  }
604 
605 cleanup:
606  *plast = last;
607  mx_msg_close(m, &msg);
608  mutt_actx_free(&actx);
609  return rc;
610 }
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:591
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
struct Body * body
List of MIME parts.
Definition: email.h:91
void mutt_generate_recvattach_list(struct AttachCtx *actx, struct Email *e, struct Body *parts, FILE *fp, int parent_type, int level, bool decrypted)
Create a list of attachments.
Definition: recvattach.c:1465
struct Email * email
Used by recvattach for updating.
Definition: attach.h:51
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:52
#define _(a)
Definition: message.h:28
short idxlen
Number of attachmentes.
Definition: attach.h:55
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:46
The body of an email.
Definition: body.h:34
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1186
int mutt_body_copy(FILE *fp, struct Body **tgt, struct Body *src)
Create a send-mode duplicate from a receive-mode body.
Definition: mutt_body.c:48
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:347
User aborted the question (with Ctrl-G)
Definition: quad.h:37
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
char * subtype
content-type subtype
Definition: body.h:37
A local copy of an email.
Definition: mxapi.h:41
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1821
FILE * fp
Used in the recvattach menu.
Definition: attach.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
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
FILE * fp
pointer to the message data
Definition: mxapi.h:43
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:598
A set of attachments.
Definition: attach.h:49
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:54
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1140
Type: &#39;application/*&#39;.
Definition: mime.h:33
int msgno
Number displayed to the user.
Definition: email.h:87
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
void mutt_actx_free(struct AttachCtx **ptr)
Free an Attachment Context.
Definition: attach.c:140
struct Body * body
Attachment.
Definition: attach.h:36
+ 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:

◆ greeting_string()

static const char* greeting_string ( char *  buf,
size_t  buflen,
size_t  col,
int  cols,
char  op,
const char *  src,
const char *  prec,
const char *  if_str,
const char *  else_str,
intptr_t  data,
MuttFormatFlags  flags 
)
static

Format a greetings string.

Expando Description
%n Recipient's real name (or address if missing)
%u User (login) name of the recipient
%v First name of the recipient

Definition at line 645 of file send.c.

649 {
650  struct GreetingInfo *gi = (struct GreetingInfo *) data;
651  char *p = NULL;
652  char buf2[256];
653 
654  const struct Address *to = TAILQ_FIRST(&gi->email->env->to);
655  const struct Address *cc = TAILQ_FIRST(&gi->email->env->cc);
656 
657  buf[0] = '\0';
658  switch (op)
659  {
660  case 'n':
661  mutt_format_s(buf, buflen, prec, mutt_get_name(to));
662  break;
663 
664  case 'u':
665  if (to)
666  {
667  mutt_str_copy(buf2, mutt_addr_for_display(to), sizeof(buf2));
668  if ((p = strpbrk(buf2, "%@")))
669  *p = '\0';
670  }
671  else
672  buf2[0] = '\0';
673  mutt_format_s(buf, buflen, prec, buf2);
674  break;
675 
676  case 'v':
677  if (to)
678  mutt_format_s(buf2, sizeof(buf2), prec, mutt_get_name(to));
679  else if (cc)
680  mutt_format_s(buf2, sizeof(buf2), prec, mutt_get_name(cc));
681  else
682  *buf2 = '\0';
683  if ((p = strpbrk(buf2, " %@")))
684  *p = '\0';
685  mutt_format_s(buf, buflen, prec, buf2);
686  break;
687 
688  default:
689  snprintf(buf, buflen, "%%%s%c", prec, op);
690  break;
691  }
692 
693  if (flags & MUTT_FORMAT_OPTIONAL)
694  mutt_expando_format(buf, buflen, col, cols, else_str, greeting_string, data, flags);
695 
696  return src;
697 }
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string -.
Definition: muttlib.c:780
#define TAILQ_FIRST(head)
Definition: queue.h:723
An email address.
Definition: address.h:35
const char * mutt_addr_for_display(const struct Address *a)
Convert an Address for display purposes.
Definition: address.c:986
struct Envelope * env
Envelope information.
Definition: email.h:90
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
struct Email * email
Definition: send.c:96
Data passed to greeting_string()
Definition: send.c:93
static const char * greeting_string(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format a greetings string.
Definition: send.c:645
void mutt_format_s(char *buf, size_t buflen, const char *prec, const char *s)
Format a simple string.
Definition: curs_lib.c:867
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:749
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
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_make_greeting()

static void mutt_make_greeting ( struct Mailbox m,
struct Email e,
FILE *  fp_out,
struct ConfigSubset sub 
)
static

Add greetings string.

Parameters
mMailbox
eEmail
fp_outFile to write to
subConfig Subset

Definition at line 706 of file send.c.

708 {
709  const char *const c_greeting = cs_subset_string(sub, "greeting");
710  if (!c_greeting || !fp_out)
711  return;
712 
713  char buf[1024];
714  struct GreetingInfo gi = { m, e };
715 
716  mutt_expando_format(buf, sizeof(buf), 0, 0, c_greeting, greeting_string,
717  (intptr_t) &gi, MUTT_TOKEN_NO_FLAGS);
718 
719  fputs(buf, fp_out);
720  fputc('\n', fp_out);
721 }
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string -.
Definition: muttlib.c:780
Data passed to greeting_string()
Definition: send.c:93
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
static const char * greeting_string(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format a greetings string.
Definition: send.c:645
#define MUTT_TOKEN_NO_FLAGS
No flags are set.
Definition: mutt.h:66
+ 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:

◆ include_reply()

static int include_reply ( struct Mailbox m,
struct Email e,
FILE *  fp_out,
struct ConfigSubset sub 
)
static

Generate the reply text for an email.

Parameters
mMailbox
eEmail
fp_outFile to write to
subConfig Subset
Return values
0Success
-1Failure

Definition at line 752 of file send.c.

754 {
755  CopyMessageFlags cmflags =
757  CopyHeaderFlags chflags = CH_DECODE;
758 
759  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
760  {
761  /* make sure we have the user's passphrase before proceeding... */
763  return -1;
764  }
765 
766  struct Message *msg = mx_msg_open(m, e->msgno);
767  if (!msg)
768  {
769  return -1;
770  }
771  mutt_parse_mime_message(m, e, msg->fp);
773 
774  mutt_make_attribution(e, fp_out, sub);
775 
776  const bool c_header = cs_subset_bool(sub, "header");
777  if (!c_header)
778  cmflags |= MUTT_CM_NOHEADER;
779 
780  const bool c_weed = cs_subset_bool(sub, "weed");
781  if (c_weed)
782  {
783  chflags |= CH_WEED | CH_REORDER;
784  cmflags |= MUTT_CM_WEED;
785  }
786 
787  mutt_copy_message(fp_out, m, e, msg, cmflags, chflags, 0);
788  mx_msg_close(m, &msg);
789 
790  mutt_make_post_indent(e, fp_out, sub);
791 
792  return 0;
793 }
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:591
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
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:41
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:46
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:32
#define MUTT_CM_REPLYING
Replying the message.
Definition: copy.h:44
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1186
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:135
void mutt_make_attribution(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add "on DATE, PERSON wrote" header.
Definition: send.c:618
void mutt_make_post_indent(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add suffix to replied email text.
Definition: send.c:729
#define CH_WEED
Weed the headers?
Definition: copy.h:53
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:37
A local copy of an email.
Definition: mxapi.h:41
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:38
#define CH_REORDER
Re-order output of headers (specified by &#39;hdr_order&#39;)
Definition: copy.h:59
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:54
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
FILE * fp
pointer to the message data
Definition: mxapi.h:43
int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:853
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:598
#define MUTT_CM_NOHEADER
Don&#39;t copy the message header.
Definition: copy.h:36
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
return a stream pointer for a message
Definition: mx.c:1140
int msgno
Number displayed to the user.
Definition: email.h:87
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ choose_default_to()

static const struct AddressList* choose_default_to ( const struct Address from,
const struct Envelope env,
struct ConfigSubset sub 
)
static

Pick the best 'to:' value.

Parameters
fromFrom Address
envEnvelope
subConfig Subset
Return values
ptrAddresses to use

Definition at line 802 of file send.c.

805 {
806  const bool c_reply_self = cs_subset_bool(sub, "reply_self");
807  if (!c_reply_self && mutt_addr_is_user(from))
808  {
809  /* mail is from the user, assume replying to recipients */
810  return &env->to;
811  }
812  else
813  {
814  return &env->from;
815  }
816 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:562
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ default_to()

static int default_to ( struct AddressList *  to,
struct Envelope env,
SendFlags  flags,
int  hmfupto,
struct ConfigSubset sub 
)
static

Generate default email addresses.

Parameters
[in,out]to'To' address
[in]envEnvelope to populate
[in]flagsFlags, see SendFlags
[in]hmfuptoIf true, add 'followup-to' address to 'to' address
[in]subConfig Subset
Return values
0Success
-1Aborted

Definition at line 828 of file send.c.

830 {
831  const struct Address *from = TAILQ_FIRST(&env->from);
832  const struct Address *reply_to = TAILQ_FIRST(&env->reply_to);
833 
834  if (flags && !TAILQ_EMPTY(&env->mail_followup_to) && (hmfupto == MUTT_YES))
835  {
836  mutt_addrlist_copy(to, &env->mail_followup_to, true);
837  return 0;
838  }
839 
840  /* Exit now if we're setting up the default Cc list for list-reply
841  * (only set if Mail-Followup-To is present and honoured). */
842  if (flags & SEND_LIST_REPLY)
843  return 0;
844 
845  const struct AddressList *default_to = choose_default_to(from, env, sub);
846 
847  if (reply_to)
848  {
849  const bool from_is_reply_to = mutt_addr_cmp(from, reply_to);
850  const bool multiple_reply_to =
851  reply_to && TAILQ_NEXT(TAILQ_FIRST(&env->reply_to), entries);
852 
853  const bool c_ignore_list_reply_to =
854  cs_subset_bool(sub, "ignore_list_reply_to");
855  const enum QuadOption c_reply_to = cs_subset_quad(sub, "reply_to");
856  if ((from_is_reply_to && !multiple_reply_to && !reply_to->personal) ||
857  (c_ignore_list_reply_to && mutt_is_mail_list(reply_to) &&
858  (mutt_addrlist_search(&env->to, reply_to) || mutt_addrlist_search(&env->cc, reply_to))))
859  {
860  /* If the Reply-To: address is a mailing list, assume that it was
861  * put there by the mailing list, and use the From: address
862  *
863  * We also take the from header if our correspondent has a reply-to
864  * header which is identical to the electronic mail address given
865  * in his From header, and the reply-to has no display-name. */
866  mutt_addrlist_copy(to, &env->from, false);
867  }
868  else if (!(from_is_reply_to && !multiple_reply_to) && (c_reply_to != MUTT_YES))
869  {
870  char prompt[256];
871  /* There are quite a few mailing lists which set the Reply-To:
872  * header field to the list address, which makes it quite impossible
873  * to send a message to only the sender of the message. This
874  * provides a way to do that. */
875  /* L10N: Asks whether the user respects the reply-to header.
876  If she says no, neomutt will reply to the from header's address instead. */
877  snprintf(prompt, sizeof(prompt), _("Reply to %s%s?"), reply_to->mailbox,
878  multiple_reply_to ? ",..." : "");
879  switch (query_quadoption(c_reply_to, prompt))
880  {
881  case MUTT_YES:
882  mutt_addrlist_copy(to, &env->reply_to, false);
883  break;
884 
885  case MUTT_NO:
886  mutt_addrlist_copy(to, default_to, false);
887  break;
888 
889  default:
890  return -1; /* abort */
891  }
892  }
893  else
894  {
895  mutt_addrlist_copy(to, &env->reply_to, false);
896  }
897  }
898  else
899  {
900  mutt_addrlist_copy(to, default_to, false);
901  }
902 
903  return 0;
904 }
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
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
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t.
Definition: maillist.c:44
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
static const struct AddressList * choose_default_to(const struct Address *from, const struct Envelope *env, struct ConfigSubset *sub)
Pick the best &#39;to:&#39; value.
Definition: send.c:802
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
bool mutt_addr_cmp(const struct Address *a, const struct Address *b)
Compare two e-mail addresses.
Definition: address.c:864
bool mutt_addrlist_search(const struct AddressList *haystack, const struct Address *needle)
Search for an e-mail address in a list.
Definition: address.c:881
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
char * personal
Real name of address.
Definition: address.h:37
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
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
#define TAILQ_EMPTY(head)
Definition: queue.h:721
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_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:

◆ add_references()

static void add_references ( struct ListHead *  head,
struct Envelope env 
)
static

Add the email's references to a list.

Parameters
headList of references
envEnvelope of message

Definition at line 975 of file send.c.

976 {
977  struct ListNode *np = NULL;
978 
979  struct ListHead *src = STAILQ_EMPTY(&env->references) ? &env->in_reply_to : &env->references;
980  STAILQ_FOREACH(np, src, entries)
981  {
983  }
984 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:64
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
char * data
String.
Definition: list.h:36
#define STAILQ_EMPTY(head)
Definition: queue.h:348
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
A List node for strings.
Definition: list.h:34
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ add_message_id()

static void add_message_id ( struct ListHead *  head,
struct Envelope env 
)
static

Add the email's message ID to a list.

Parameters
headList of message IDs
envEnvelope of message

Definition at line 991 of file send.c.

992 {
993  if (env->message_id)
994  {
996  }
997 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
char * message_id
Message ID.
Definition: envelope.h:69
struct ListNode * mutt_list_insert_head(struct ListHead *h, char *s)
Insert a string at the beginning of a List.
Definition: list.c:45
+ 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_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_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:

◆ make_reference_headers()

static void make_reference_headers ( struct EmailList *  el,
struct Envelope env,
struct ConfigSubset sub 
)
static

Generate reference headers for an email.

Parameters
elList of source Emails
envEnvelope for result
subConfig Subset

Definition at line 1101 of file send.c.

1103 {
1104  if (!el || !env || STAILQ_EMPTY(el))
1105  return;
1106 
1107  struct EmailNode *en = STAILQ_FIRST(el);
1108  bool single = !STAILQ_NEXT(en, entries);
1109 
1110  if (!single)
1111  {
1112  STAILQ_FOREACH(en, el, entries)
1113  {
1114  mutt_add_to_reference_headers(env, en->email->env, sub);
1115  }
1116  }
1117  else
1118  mutt_add_to_reference_headers(env, en->email->env, sub);
1119 
1120  /* if there's more than entry in In-Reply-To (i.e. message has multiple
1121  * parents), don't generate a References: header as it's discouraged by
1122  * RFC2822, sect. 3.6.4 */
1123  if (!single && !STAILQ_EMPTY(&env->in_reply_to) &&
1124  STAILQ_NEXT(STAILQ_FIRST(&env->in_reply_to), entries))
1125  {
1126  mutt_list_free(&env->references);
1127  }
1128 }
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
struct Envelope * env
Envelope information.
Definition: email.h:90
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
struct Email * email
Email in the list.
Definition: email.h:131
#define STAILQ_EMPTY(head)
Definition: queue.h:348
List of Emails.
Definition: email.h:129
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
#define STAILQ_FIRST(head)
Definition: queue.h:350
void mutt_add_to_reference_headers(struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
Generate references for a reply email.
Definition: send.c:1081
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ envelope_defaults()

static int envelope_defaults ( struct Envelope env,
struct Mailbox m,
struct EmailList *  el,
SendFlags  flags,
struct ConfigSubset sub 
)
static

Fill in some defaults for a new email.

Parameters
envEnvelope for result
mMailbox
elList of Emails to use
flagsFlags, see SendFlags
subConfig Subset
Return values
0Success
-1Failure

Definition at line 1140 of file send.c.

1142 {
1143  if (!el || STAILQ_EMPTY(el))
1144  return -1;
1145 
1146  struct EmailNode *en = STAILQ_FIRST(el);
1147  bool single = !STAILQ_NEXT(en, entries);
1148 
1149  struct Envelope *curenv = en->email->env;
1150  if (!curenv)
1151  return -1;
1152 
1153  if (flags & (SEND_REPLY | SEND_TO_SENDER))
1154  {
1155 #ifdef USE_NNTP
1156  if ((flags & SEND_NEWS))
1157  {
1158  /* in case followup set Newsgroups: with Followup-To: if it present */
1159  if (!env->newsgroups && !mutt_istr_equal(curenv->followup_to, "poster"))
1160  {
1161  env->newsgroups = mutt_str_dup(curenv->followup_to);
1162  }
1163  }
1164  else
1165 #endif
1166  if (!single)
1167  {
1168  STAILQ_FOREACH(en, el, entries)
1169  {
1170  if (mutt_fetch_recips(env, en->email->env, flags, sub) == -1)
1171  return -1;
1172  }
1173  }
1174  else if (mutt_fetch_recips(env, curenv, flags, sub) == -1)
1175  return -1;
1176 
1177  if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
1178  {
1179  mutt_error(_("No mailing lists found"));
1180  return -1;
1181  }
1182 
1183  if (flags & SEND_REPLY)
1184  {
1185  mutt_make_misc_reply_headers(env, curenv, sub);
1186  make_reference_headers(el, env, sub);
1187  }
1188  }
1189  else if (flags & SEND_FORWARD)
1190  {
1191  mutt_make_forward_subject(env, en->email, sub);
1192 
1193  const bool c_forward_references = cs_subset_bool(sub, "forward_references");
1194  if (c_forward_references)
1195  make_reference_headers(el, env, sub);
1196  }
1197 
1198  return 0;
1199 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:51
#define mutt_error(...)
Definition: logging.h:88
void mutt_make_forward_subject(struct Envelope *env, struct Email *e, struct ConfigSubset *sub)
Create a subject for a forwarded email.
Definition: send.c:1034
#define SEND_FORWARD
Forward email.
Definition: send.h:43
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
static void make_reference_headers(struct EmailList *el, struct Envelope *env, struct ConfigSubset *sub)
Generate reference headers for an email.
Definition: send.c:1101
struct Envelope * env
Envelope information.
Definition: email.h:90
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:42
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
#define SEND_NEWS
Reply to a news article.
Definition: send.h:53
int mutt_fetch_recips(struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
Generate recpients for a reply email.
Definition: send.c:915
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
#define SEND_REPLY
Reply to sender.
Definition: send.h:40
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
struct Email * email
Email in the list.
Definition: email.h:131
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
#define STAILQ_EMPTY(head)
Definition: queue.h:348
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
List of Emails.
Definition: email.h:129
void mutt_make_misc_reply_headers(struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
Set subject for a reply.
Definition: send.c:1054
#define TAILQ_EMPTY(head)
Definition: queue.h:721
#define STAILQ_FIRST(head)
Definition: queue.h:350
The header of an Email.
Definition: envelope.h:54
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ generate_body()

static int generate_body ( FILE *  fp_tmp,
struct Email e,
SendFlags  flags,
struct Mailbox m,
struct EmailList *  el,
struct ConfigSubset sub 
)
static

Create a new email body.

Parameters
fp_tmpStream for outgoing message
eEmail for outgoing message
flagsCompose mode, see SendFlags
mMailbox
elList of Emails to use
subConfig Subset
Return values
0Success
-1Error

Definition at line 1212 of file send.c.

1214 {
1215  /* An EmailList is required for replying and forwarding */
1216  if (!el && (flags & (SEND_REPLY | SEND_FORWARD)))
1217  return -1;
1218 
1219  if (flags & SEND_REPLY)
1220  {
1221  const enum QuadOption c_include = cs_subset_quad(sub, "include");
1222  enum QuadOption ans =
1223  query_quadoption(c_include, _("Include message in reply?"));
1224  if (ans == MUTT_ABORT)
1225  return -1;
1226 
1227  if (ans == MUTT_YES)
1228  {
1229  mutt_message(_("Including quoted message..."));
1230  struct EmailNode *en = NULL;
1231  STAILQ_FOREACH(en, el, entries)
1232  {
1233  if (include_reply(m, en->email, fp_tmp, sub) == -1)
1234  {
1235  mutt_error(_("Could not include all requested messages"));
1236  return -1;
1237  }
1238  if (STAILQ_NEXT(en, entries) != NULL)
1239  {
1240  fputc('\n', fp_tmp);
1241  }
1242  }
1243  }
1244  }
1245  else if (flags & SEND_FORWARD)
1246  {
1247  const enum QuadOption c_mime_forward = cs_subset_quad(sub, "mime_forward");
1248  enum QuadOption ans =
1249  query_quadoption(c_mime_forward, _("Forward as attachment?"));
1250  if (ans == MUTT_YES)
1251  {
1252  struct Body *last = e->body;
1253 
1254  mutt_message(_("Preparing forwarded message..."));
1255 
1256  while (last && last->next)
1257  last = last->next;
1258 
1259  struct EmailNode *en = NULL;
1260  STAILQ_FOREACH(en, el, entries)
1261  {
1262  struct Body *tmp = mutt_make_message_attach(m, en->email, false, sub);
1263  if (last)
1264  {
1265  last->next = tmp;
1266  last = tmp;
1267  }
1268  else
1269  {
1270  last = tmp;
1271  e->body = tmp;
1272  }
1273  }
1274  }
1275  else if (ans != MUTT_ABORT)
1276  {
1277  enum QuadOption forwardq = MUTT_ABORT;
1278  struct Body **last = NULL;
1279  struct EmailNode *en = NULL;
1280 
1281  const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
1282  const enum QuadOption c_forward_attachments =
1283  cs_subset_quad(sub, "forward_attachments");
1284  if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1285  {
1286  last = &e->body;
1287  while (*last)
1288  last = &((*last)->next);
1289  }
1290 
1291  STAILQ_FOREACH(en, el, entries)
1292  {
1293  struct Email *e_cur = en->email;
1294  include_forward(m, e_cur, fp_tmp, sub);
1295  if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1296  {
1297  if (inline_forward_attachments(m, e_cur, &last, &forwardq, sub) != 0)
1298  return -1;
1299  }
1300  }
1301  }
1302  else
1303  return -1;
1304  }
1305  /* if (WithCrypto && (flags & SEND_KEY)) */
1306  else if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY))
1307  {
1308  struct Body *b = NULL;
1309 
1310  if (((WithCrypto & APPLICATION_PGP) != 0) && !(b = crypt_pgp_make_key_attachment()))
1311  {
1312  return -1;
1313  }
1314 
1315  b->next = e->body;
1316  e->body = b;
1317  }
1318 
1319  mutt_clear_error();
1320 
1321  return 0;
1322 }
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
struct Body * body
List of MIME parts.
Definition: email.h:91
static int include_forward(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Write out a forwarded message.
Definition: send.c:483
#define mutt_error(...)
Definition: logging.h:88
#define SEND_FORWARD
Forward email.
Definition: send.h:43
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
The body of an email.
Definition: body.h:34
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:347
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
User aborted the question (with Ctrl-G)
Definition: quad.h:37
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:46
static int inline_forward_attachments(struct Mailbox *m, struct Email *e, struct Body ***plast, enum QuadOption *forwardq, struct ConfigSubset *sub)
Add attachments to an email, inline.
Definition: send.c:542
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:87
struct Body * mutt_make_message_attach(struct Mailbox *m, struct Email *e, bool attach_msg, struct ConfigSubset *sub)
Create a message attachment.
Definition: sendlib.c:936
static int include_reply(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Generate the reply text for an email.
Definition: send.c:752
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
#define SEND_REPLY
Reply to sender.
Definition: send.h:40
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
struct Body * crypt_pgp_make_key_attachment(void)
Wrapper for CryptModuleSpecs::pgp_make_key_attachment()
Definition: cryptglue.c:310
struct Email * email
Email in the list.
Definition: email.h:131
#define mutt_message(...)
Definition: logging.h:87
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
List of Emails.
Definition: email.h:129
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_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:

◆ set_reverse_name()

static void set_reverse_name ( struct AddressList *  al,
struct Envelope env,
struct ConfigSubset sub 
)
static

Try to set the 'from' field from the recipients.

Parameters
alAddressList to prepend the found address
envEnvelope to use
subConfig Subset

Look through the recipients of the message we are replying to, and if we find an address that matches $alternates, we use that as the default from field

Definition at line 1402 of file send.c.

1404 {
1405  struct Address *a = NULL;
1406  if (TAILQ_EMPTY(al))
1407  {
1408  TAILQ_FOREACH(a, &env->to, entries)
1409  {
1410  if (mutt_addr_is_user(a))
1411  {
1413  break;
1414  }
1415  }
1416  }
1417 
1418  if (TAILQ_EMPTY(al))
1419  {
1420  TAILQ_FOREACH(a, &env->cc, entries)
1421  {
1422  if (mutt_addr_is_user(a))
1423  {
1425  break;
1426  }
1427  }
1428  }
1429 
1430  if (TAILQ_EMPTY(al))
1431  {
1432  struct Address *from = TAILQ_FIRST(&env->from);
1433  if (from && mutt_addr_is_user(from))
1434  {
1436  }
1437  }
1438 
1439  if (!TAILQ_EMPTY(al))
1440  {
1441  /* when $reverse_real_name is not set, clear the personal name so that it
1442  * may be set via a reply- or send-hook. */
1443 
1444  const bool c_reverse_real_name = cs_subset_bool(sub, "reverse_real_name");
1445  if (!c_reverse_real_name)
1446  FREE(&TAILQ_FIRST(al)->personal);
1447  }
1448 }
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
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
An email address.
Definition: address.h:35
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:716
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
char * personal
Real name of address.
Definition: address.h:37
#define FREE(x)
Definition: memory.h:40
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:562
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_EMPTY(head)
Definition: queue.h:721
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1490
+ 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:

◆ invoke_mta()

static int invoke_mta ( struct Mailbox m,
struct Email e,
struct ConfigSubset sub 
)
static

Send an email.

Parameters
mMailbox
eEmail
subConfig Subset
Return values
0Success
-1Failure

Definition at line 1487 of file send.c.

1488 {
1489  struct Buffer *tempfile = NULL;
1490  int rc = -1;
1491 
1492  /* Write out the message in MIME form. */
1493  tempfile = mutt_buffer_pool_get();
1494  mutt_buffer_mktemp(tempfile);
1495  FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w");
1496  if (!fp_tmp)
1497  goto cleanup;
1498 
1499 #ifdef USE_SMTP
1500  const bool c_write_bcc = cs_subset_bool(sub, "write_bcc");
1501  const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
1502  if (c_smtp_url)
1503  cs_subset_str_native_set(sub, "write_bcc", false, NULL);
1504 #endif
1505 #ifdef MIXMASTER
1507  !STAILQ_EMPTY(&e->chain),
1509 #endif
1510 #ifndef MIXMASTER
1512  false, mutt_should_hide_protected_subject(e), sub);
1513 #endif
1514 #ifdef USE_SMTP
1515  cs_subset_str_native_set(sub, "write_bcc", c_write_bcc, NULL);
1516 #endif
1517 
1518  fputc('\n', fp_tmp); /* tie off the header. */
1519 
1520  if ((mutt_write_mime_body(e->body, fp_tmp, sub) == -1))
1521  goto cleanup;
1522 
1523  if (mutt_file_fclose(&fp_tmp) != 0)
1524  {
1525  mutt_perror(mutt_buffer_string(tempfile));
1526  unlink(mutt_buffer_string(tempfile));
1527  goto cleanup;
1528  }
1529 
1530 #ifdef MIXMASTER
1531  if (!STAILQ_EMPTY(&e->chain))
1532  {
1533  rc = mix_send_message(&e->chain, mutt_buffer_string(tempfile));
1534  goto cleanup;
1535  }
1536 #endif
1537 
1538 #ifdef USE_NNTP
1539  if (OptNewsSend)
1540  goto sendmail;
1541 #endif
1542 
1543 #ifdef USE_SMTP
1544  if (c_smtp_url)
1545  {
1546  rc = mutt_smtp_send(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1547  mutt_buffer_string(tempfile),
1548  (e->body->encoding == ENC_8BIT), sub);
1549  goto cleanup;
1550  }
1551 #endif
1552 
1553 sendmail:
1554  rc = mutt_invoke_sendmail(m, &e->env->from, &e->env->to, &e->env->cc,
1555  &e->env->bcc, mutt_buffer_string(tempfile),
1556  (e->body->encoding == ENC_8BIT), sub);
1557 cleanup:
1558  if (fp_tmp)
1559  {
1560  mutt_file_fclose(&fp_tmp);
1561  unlink(mutt_buffer_string(tempfile));
1562  }
1563  mutt_buffer_pool_release(&tempfile);
1564  return rc;
1565 }
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
struct Body * body
List of MIME parts.
Definition: email.h:91
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1108
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
String manipulation buffer.
Definition: buffer.h:33
8-bit text
Definition: mime.h:50
#define mutt_perror(...)
Definition: logging.h:89
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
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
struct AddressList cc
Email&#39;s &#39;Cc&#39; list.
Definition: envelope.h:59
A normal Email, write full header + MIME headers.
Definition: header.h:40
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:66
struct ListHead chain
Mixmaster chain.
Definition: email.h:102
int mutt_invoke_sendmail(struct Mailbox *m, struct AddressList *from, struct AddressList *to, struct AddressList *cc, struct AddressList *bcc, const char *msg, bool eightbit, struct ConfigSubset *sub)
Run sendmail.
Definition: sendmail.c:287
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
int mix_send_message(struct ListHead *chain, const char *tempfile)
Send an email via Mixmaster.
Definition: remailer.c:935
int mutt_smtp_send(const struct AddressList *from, const struct AddressList *to, const struct AddressList *cc, const struct AddressList *bcc, const char *msgfile, bool eightbit, struct ConfigSubset *sub)
Send a message using SMTP.
Definition: smtp.c:882
#define STAILQ_EMPTY(head)
Definition: queue.h:348
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:45
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
int mutt_rfc822_write_header(FILE *fp, struct Envelope *env, struct Body *attach, enum MuttWriteHeaderMode mode, bool privacy, bool hide_protected_subject, struct ConfigSubset *sub)
Write out one RFC822 header line.
Definition: header.c:574
+ 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:

◆ decode_descriptions()

static void decode_descriptions ( struct Body b)
static

rfc2047 decode them in case of an error

Parameters
bMIME parts to decode

Definition at line 1591 of file send.c.

1592 {
1593  for (struct Body *t = b; t; t = t->next)
1594  {
1595  if (t->description)
1596  {
1597  rfc2047_decode(&t->description);
1598  }
1599  if (t->parts)
1600  decode_descriptions(t->parts);
1601  }
1602 }
struct Body * next
next attachment in the list
Definition: body.h:53
The body of an email.
Definition: body.h:34
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:641
static void decode_descriptions(struct Body *b)
rfc2047 decode them in case of an error
Definition: send.c:1591
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ fix_end_of_file()

static void fix_end_of_file ( const char *  data)
static

Ensure a file ends with a linefeed.

Parameters
dataName of file to fix

Definition at line 1608 of file send.c.

1609 {
1610  FILE *fp = mutt_file_fopen(data, "a+");
1611  if (!fp)
1612  return;
1613  if (fseek(fp, -1, SEEK_END) >= 0)
1614  {
1615  int c = fgetc(fp);
1616  if (c != '\n')
1617  fputc('\n', fp);
1618  }
1619  mutt_file_fclose(&fp);
1620 }
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
char * data
Pointer to data.
Definition: buffer.h:35
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
+ 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:

◆ is_reply()

static bool is_reply ( struct Email reply,
struct Email orig 
)
static

Is one email a reply to another?

Parameters
replyEmail to test
origOriginal email
Return values
trueIt is a reply
falseIt is not a reply

Definition at line 1682 of file send.c.

1683 {
1684  if (!reply || !reply->env || !orig || !orig->env)
1685  return false;
1686  return mutt_list_find(&orig->env->references, reply->env->message_id) ||
1687  mutt_list_find(&orig->env->in_reply_to, reply->env->message_id);
1688 }
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:82
char * message_id
Message ID.
Definition: envelope.h:69
struct Envelope * env
Envelope information.
Definition: email.h:90
struct ListNode * mutt_list_find(const struct ListHead *h, const char *data)
Find a string in a List.
Definition: list.c:102
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ search_attach_keyword()

static bool search_attach_keyword ( char *  filename,
struct ConfigSubset sub 
)
static

Search an email for 'attachment' keywords.

Parameters
filenameFilename
subConfig Subset
Return values
trueThe regex matches in the email

Search an email for the regex in $abort_noattach_regex. A match might indicate that the user should have attached something.

Note
Quoted lines (as defined by $quote_regex) are ignored

Definition at line 1701 of file send.c.

1702 {
1703  const struct Regex *c_abort_noattach_regex =
1704  cs_subset_regex(sub, "abort_noattach_regex");
1705  const struct Regex *c_quote_regex = cs_subset_regex(sub, "quote_regex");
1706 
1707  /* Search for the regex in `$abort_noattach_regex` within a file */
1708  if (!c_abort_noattach_regex || !c_abort_noattach_regex->regex ||
1709  !c_quote_regex || !c_quote_regex->regex)
1710  {
1711  return false;
1712  }
1713 
1714  FILE *fp_att = mutt_file_fopen(filename, "r");
1715  if (!fp_att)
1716  return false;
1717 
1718  char *inputline = mutt_mem_malloc(1024);
1719  bool found = false;
1720  while (!feof(fp_att))
1721  {
1722  fgets(inputline, 1024, fp_att);
1723  if (!mutt_is_quote_line(inputline, NULL) &&
1724  mutt_regex_match(c_abort_noattach_regex, inputline))
1725  {
1726  found = true;
1727  break;
1728  }
1729  }
1730  FREE(&inputline);
1731  mutt_file_fclose(&fp_att);
1732  return found;
1733 }
regex_t * regex
compiled expression
Definition: regex3.h:92
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:243
int mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition: dlg_pager.c:968
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
Cached regular expression.
Definition: regex3.h:89
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:613
#define FREE(x)
Definition: memory.h:40
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:589
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ save_fcc()

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 
)
static

Save an Email to a 'sent mail' folder.

Parameters
[in]mCurrent Mailbox
[in]eEmail to save
[in]fccFolder to save to (can be comma-separated list)
[in]clear_contentCleartext content of Email
[in]pgpkeylistList of pgp keys
[in]flagsSend mode, see SendFlags
[out]finalpathPath of final folder
[in]subConfig Subset
Return values
0Success
-1Error

Definition at line 1748 of file send.c.

1751 {
1752  int rc = 0;
1753  struct Body *save_content = NULL;
1754 
1756 
1757  /* Don't save a copy when we are in batch-mode, and the FCC
1758  * folder is on an IMAP server: This would involve possibly lots
1759  * of user interaction, which is not available in batch mode.
1760  *
1761  * Note: A patch to fix the problems with the use of IMAP servers
1762  * from non-curses mode is available from Brendan Cully. However,
1763  * I'd like to think a bit more about this before including it. */
1764 
1765 #ifdef USE_IMAP
1766  if ((flags & SEND_BATCH) && !mutt_buffer_is_empty(fcc) &&
1767  (imap_path_probe(mutt_buffer_string(fcc), NULL) == MUTT_IMAP))
1768  {
1769  mutt_error(
1770  _("Warning: Fcc to an IMAP mailbox is not supported in batch mode"));
1771  /* L10N: Printed after the "Fcc to an IMAP mailbox is not supported" message.
1772  To make it clearer that the message doesn't mean NeoMutt is aborting
1773  sending the mail too.
1774  %s is the full mailbox URL, including imap(s)://
1775  */
1776  mutt_error(_("Skipping Fcc to %s"), mutt_buffer_string(fcc));
1777  mutt_buffer_reset(fcc);
1778  return rc;
1779  }
1780 #endif
1781 
1782  if (mutt_buffer_is_empty(fcc) || mutt_str_equal("/dev/null", mutt_buffer_string(fcc)))
1783  return rc;
1784 
1785  struct Body *tmpbody = e->body;
1786  struct Body *save_sig = NULL;
1787  struct Body *save_parts = NULL;
1788 
1789  const bool c_fcc_before_send = cs_subset_bool(sub, "fcc_before_send");
1790  /* Before sending, we don't allow message manipulation because it
1791  * will break message signatures. This is especially complicated by
1792  * Protected Headers. */
1793  if (!c_fcc_before_send)
1794  {
1795  const bool c_fcc_clear = cs_subset_bool(sub, "fcc_clear");
1796  if ((WithCrypto != 0) &&
1797  (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) && c_fcc_clear)
1798  {
1799  e->body = clear_content;
1802  }
1803 
1804  const enum QuadOption c_fcc_attach = cs_subset_quad(sub, "fcc_attach");
1805 
1806  /* check to see if the user wants copies of all attachments */
1807  bool save_atts = true;
1808  if (e->body->type == TYPE_MULTIPART)
1809  {
1810  /* In batch mode, save attachments if the quadoption is yes or ask-yes */
1811  if (flags & SEND_BATCH)
1812  {
1813  if ((c_fcc_attach == MUTT_NO) || (c_fcc_attach == MUTT_ASKNO))
1814  save_atts = false;
1815  }
1816  else if (query_quadoption(c_fcc_attach, _("Save attachments in Fcc?")) != MUTT_YES)
1817  save_atts = false;
1818  }
1819  if (!save_atts)
1820  {
1821  if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) &&
1822  (mutt_str_equal(e->body->subtype, "encrypted") ||
1823  mutt_str_equal(e->body->subtype, "signed")))
1824  {
1825  if ((clear_content->type == TYPE_MULTIPART) &&
1826  (query_quadoption(c_fcc_attach, _("Save attachments in Fcc?")) == MUTT_NO))
1827  {
1828  if (!(e->security & SEC_ENCRYPT) && (e->security & SEC_SIGN))
1829  {
1830  /* save initial signature and attachments */
1831  save_sig = e->body->parts->next;
1832  save_parts = clear_content->parts->next;
1833  }
1834 
1835  /* this means writing only the main part */
1836  e->body = clear_content->parts;
1837 
1838  if (mutt_protect(m, e, pgpkeylist, false) == -1)
1839  {
1840  /* we can't do much about it at this point, so
1841  * fallback to saving the whole thing to fcc */
1842  e->body = tmpbody;
1843  save_sig = NULL;
1844  goto full_fcc;
1845  }
1846 
1847  save_content = e->body;
1848  }
1849  }
1850  else
1851  {
1852  if (query_quadoption(c_fcc_attach, _("Save attachments in Fcc?")) == MUTT_NO)
1853  e->body = e->body->parts;
1854  }
1855  }
1856  }
1857 
1858 full_fcc:
1859  if (e->body)
1860  {
1861  /* update received time so that when storing to a mbox-style folder
1862  * the From_ line contains the current time instead of when the
1863  * message was first postponed. */
1864  e->received = mutt_date_epoch();
1865  rc = mutt_write_multiple_fcc(mutt_buffer_string(fcc), e, NULL, false, NULL,
1866  finalpath, sub);
1867  while (rc && !(flags & SEND_BATCH))
1868  {
1869  mutt_clear_error();
1870  int choice = mutt_multi_choice(
1871  /* L10N: Called when saving to $record or Fcc failed after sending.
1872  (r)etry tries the same mailbox again.
1873  alternate (m)ailbox prompts for a different mailbox to try.
1874  (s)kip aborts saving. */
1875  _("Fcc failed. (r)etry, alternate (m)ailbox, or (s)kip?"),
1876  /* L10N: These correspond to the "Fcc failed" multi-choice prompt
1877  (r)etry, alternate (m)ailbox, or (s)kip.
1878  Any similarity to famous leaders of the FSF is coincidental. */
1879  _("rms"));
1880  switch (choice)
1881  {
1882  case 2: /* alternate (m)ailbox */
1883  /* L10N: This is the prompt to enter an "alternate (m)ailbox" when the
1884  initial Fcc fails. */
1885  rc = mutt_buffer_enter_fname(_("Fcc mailbox"), fcc, true, m, false,
1886  NULL, NULL, MUTT_SEL_NO_FLAGS);
1887  if ((rc == -1) || mutt_buffer_is_empty(fcc))
1888  {
1889  rc = 0;
1890  break;
1891  }
1892  /* fall through */
1893 
1894  case 1: /* (r)etry */
1895  rc = mutt_write_multiple_fcc(mutt_buffer_string(fcc), e, NULL, false,
1896  NULL, finalpath, sub);
1897  break;
1898 
1899  case -1: /* abort */
1900  case 3: /* (s)kip */
1901  rc = 0;
1902  break;
1903  }
1904  }
1905  }
1906 
1907  if (!c_fcc_before_send)
1908  {
1909  e->body = tmpbody;
1910 
1911  if ((WithCrypto != 0) && save_sig)
1912  {
1913  /* cleanup the second signature structures */
1914  if (save_content->parts)
1915  {
1916  mutt_body_free(&save_content->parts->next);
1917  save_content->parts = NULL;
1918  }
1919  mutt_body_free(&save_content);
1920 
1921  /* restore old signature and attachments */
1922  e->body->parts->next = save_sig;
1923  e->body->parts->parts->next = save_parts;
1924  }
1925  else if ((WithCrypto != 0) && save_content)
1926  {
1927  /* destroy the new encrypted body. */
1928  mutt_body_free(&save_content);
1929  }
1930  }
1931 
1932  return 0;
1933 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:904
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
Ask the user, defaulting to &#39;No&#39;.
Definition: quad.h:40
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:63
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
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
struct Body * body
List of MIME parts.
Definition: email.h:91
#define mutt_error(...)
Definition: logging.h:88
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: browser.h:36
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:84
The body of an email.
Definition: body.h:34
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2402
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:347
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:112
char * subtype
content-type subtype
Definition: body.h:37
int mutt_write_multiple_fcc(const char *path, struct Email *e, const char *msgid, bool post, char *fcc, char **finalpath, struct ConfigSubset *sub)
Handle FCC with multiple, comma separated entries.
Definition: sendlib.c:1467
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
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:49
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
#define SEC_SIGN
Email is signed.
Definition: lib.h:76
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
int mutt_buffer_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file.
Definition: curs_lib.c:513
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:322
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
&#39;IMAP&#39; Mailbox type
Definition: mailbox.h:53
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:83
#define SEND_BATCH
Send email in batch mode (without user interaction)
Definition: send.h:45
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:

◆ postpone_message()

static int postpone_message ( struct Email e_post,
struct Email e_cur,
const char *  fcc,
SendFlags  flags,
struct ConfigSubset sub 
)
static

Save an Email for another day.

Parameters
e_postEmail to postpone
e_curCurrent Email in the index
fccFolder for 'sent mail'
flagsSend mode, see SendFlags
subConfig Subset
Return values
0Success
-1Error

Definition at line 1945 of file send.c.

1947 {
1948  char *pgpkeylist = NULL;
1949  const char *encrypt_as = NULL;
1950  struct Body *clear_content = NULL;
1951  struct Mailbox *m = ctx_mailbox(Context);
1952 
1953  const char *const c_postponed = cs_subset_string(sub, "postponed");
1954  if (!c_postponed)
1955  {
1956  mutt_error(_("Can't postpone. $postponed is unset"));
1957  return -1;
1958  }
1959 
1960  if (e_post->body->next)
1961  e_post->body = mutt_make_multipart(e_post->body);
1962 
1963  mutt_encode_descriptions(e_post->body, true, sub);
1964 
1965  const bool c_postpone_encrypt = cs_subset_bool(sub, "postpone_encrypt");
1966  if ((WithCrypto != 0) && c_postpone_encrypt &&
1967  (e_post->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
1968  {
1969  if (((WithCrypto & APPLICATION_PGP) != 0) && (e_post->security & APPLICATION_PGP))
1970  {
1971  const char *const c_pgp_default_key =
1972  cs_subset_string(sub, "pgp_default_key");
1973  encrypt_as = c_pgp_default_key;
1974  }
1975  else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e_post->security & APPLICATION_SMIME))
1976  {
1977  const char *const c_smime_default_key =
1978  cs_subset_string(sub, "smime_default_key");
1979  encrypt_as = c_smime_default_key;
1980  }
1981  if (!encrypt_as)
1982  {
1983  const char *const c_postpone_encrypt_as =
1984  cs_subset_string(sub, "postpone_encrypt_as");
1985  encrypt_as = c_postpone_encrypt_as;
1986  }
1987 
1988 #ifdef USE_AUTOCRYPT
1989  if (e_post->security & SEC_AUTOCRYPT)
1990  {
1992  {
1993  e_post->body = mutt_remove_multipart(e_post->body);
1994  decode_descriptions(e_post->body);
1995  mutt_error(_("Error encrypting message. Check your crypt settings."));
1996  return -1;
1997  }
1998  encrypt_as = AutocryptDefaultKey;
1999  }
2000 #endif
2001 
2002  if (encrypt_as)
2003  {
2004  pgpkeylist = mutt_str_dup(encrypt_as);
2005  clear_content = e_post->body;
2006  if (mutt_protect(m, e_post, pgpkeylist, true) == -1)
2007  {
2008  FREE(&pgpkeylist);
2009  e_post->body = mutt_remove_multipart(e_post->body);
2010  decode_descriptions(e_post->body);
2011  mutt_error(_("Error encrypting message. Check your crypt settings."));
2012  return -1;
2013  }
2014 
2015  FREE(&pgpkeylist);
2016 
2017  mutt_encode_descriptions(e_post->body, false, sub);
2018  }
2019  }
2020 
2021  /* make sure the message is written to the right part of a maildir
2022  * postponed folder. */
2023  e_post->read = false;
2024  e_post->old = false;
2025 
2026  mutt_prepare_envelope(e_post->env, false, sub);
2027  mutt_env_to_intl(e_post->env, NULL, NULL); /* Handle bad IDNAs the next time. */
2028 
2029  if (mutt_write_fcc(NONULL(c_postponed), e_post,
2030  (e_cur && (flags & SEND_REPLY)) ? e_cur->env->message_id : NULL,
2031  true, fcc, NULL, sub) < 0)
2032  {
2033  if (clear_content)
2034  {
2035  mutt_body_free(&e_post->body);
2036  e_post->body = clear_content;
2037  }
2038  mutt_env_free(&e_post->body->mime_headers); /* protected headers */
2039  e_post->body = mutt_remove_multipart(e_post->body);
2040  decode_descriptions(e_post->body);
2041  mutt_unprepare_envelope(e_post->env);
2042  return -1;
2043  }
2044 
2046 
2047  if (clear_content)
2048  mutt_body_free(&clear_content);
2049 
2050  return 0;
2051 }
The "current" mailbox.
Definition: context.h:37
#define NONULL(x)
Definition: string2.h:37
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:63
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
struct Body * body
List of MIME parts.
Definition: email.h:91
struct Mailbox * ctx_mailbox(struct Context *ctx)
wrapper to get the mailbox in a Context, or NULL
Definition: context.c:444
#define mutt_error(...)
Definition: logging.h:88
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:75
int mutt_write_fcc(const char *path, struct Email *e, const char *msgid, bool post, const char *fcc, char **finalpath, struct ConfigSubset *sub)
Write email to FCC mailbox.
Definition: sendlib.c:1515
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
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:370
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:84
char * AutocryptDefaultKey
Autocrypt default key id (used for postponing messages)
Definition: config.c:36
The body of an email.
Definition: body.h:34
bool read
Email is read.
Definition: email.h:51
char * message_id
Message ID.
Definition: envelope.h:69
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:1243
bool old
Email is seen, but unread.
Definition: email.h:50
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
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: multipart.c:100
int mutt_autocrypt_set_sign_as_default_key(struct Mailbox *m, struct Email *e)
Set the Autocrypt default key for signing.
Definition: autocrypt.c:712
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:88
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:1282
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
A mailbox.
Definition: mailbox.h:81
int mutt_protect(struct Mailbox *m, struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
Definition: crypt.c:161
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
void mutt_update_num_postponed(void)
Force the update of the number of postponed messages.
Definition: postpone.c:240
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
uint8_t flags
e.g. MB_NORMAL
Definition: mailbox.h:134
#define FREE(x)
Definition: memory.h:40
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:

◆ is_text_plain()

static bool is_text_plain ( const struct Body b)
static

is a Body a text/plain MIME part?

Parameters
bBody to check
Return values
trueBody is text/plain
falseBody is not

Definition at line 2059 of file send.c.

2060 {
2061  return (b->type == TYPE_TEXT) && mutt_istr_equal(b->subtype, "plain");
2062 }
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:916
char * subtype
content-type subtype
Definition: body.h:37
Type: &#39;text/*&#39;.
Definition: mime.h:38
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ abort_for_missing_attachments()

static bool abort_for_missing_attachments ( const struct Body b,
struct ConfigSubset sub 
)
static

Should we abort sending because of missing attachments?

Parameters
bBody
subConfig Subset
Return values
Abortbecause of missing attachments

Definition at line 2070 of file send.c.

2071 {
2072  const enum QuadOption c_abort_noattach =
2073  cs_subset_quad(sub, "abort_noattach");
2074 
2075  if (c_abort_noattach == MUTT_NO)
2076  return false;
2077 
2078  if (b->next)
2079  return false;
2080 
2081  bool has_keyword = false;
2082 
2083  /* search text/plain parts, whether they are main or alternative parts */
2084  if (is_text_plain(b))
2085  {
2086  has_keyword |= search_attach_keyword(b->filename, sub);
2087  }
2088  else
2089  {
2090  for (b = b->parts; b; b = b->next)
2091  {
2092  if (is_text_plain(b))
2093  {
2094  has_keyword |= search_attach_keyword(b->filename, sub);
2095  }
2096  }
2097  }
2098 
2099  if (!has_keyword)
2100  return false;
2101 
2102  if (c_abort_noattach == MUTT_YES)
2103  {
2104  mutt_error(_("Message contains text matching \"$abort_noattach_regex\". "
2105  "Not sending."));
2106  return true;
2107  }
2108 
2109  return query_quadoption(c_abort_noattach,
2110  _("No attachments, cancel sending?")) != MUTT_NO;
2111 }
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
#define mutt_error(...)
Definition: logging.h:88
#define _(a)
Definition: message.h:28
struct Body * next
next attachment in the list
Definition: body.h:53
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:347
static bool is_text_plain(const struct Body *b)
is a Body a text/plain MIME part?
Definition: send.c:2059
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
static bool search_attach_keyword(char *filename, struct ConfigSubset *sub)
Search an email for &#39;attachment&#39; keywords.
Definition: send.c:1701
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_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: