NeoMutt  2021-02-05
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 "context.h"
#include "copy.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 "mutt_parse.h"
#include "muttlib.h"
#include "options.h"
#include "protos.h"
#include "recvattach.h"
#include "rfc3676.h"
#include "sort.h"
#include "nntp/lib.h"
#include "mx.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.

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 Mailbox *m, struct Email *e, FILE *fp, struct ConfigSubset *sub)
 Add the "start of forwarded message" text. More...
 
void mutt_forward_trailer (struct Mailbox *m, 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 Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add "on DATE, PERSON wrote" header. More...
 
void mutt_make_post_indent (struct Mailbox *m, 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 Mailbox *m, 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 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 Context *ctx, 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 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 Context *ctx, 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 92 of file send.c.

93 {
94  const char *c_signature = cs_subset_path(sub, "signature");
95  if (!c_signature)
96  return;
97 
98  pid_t pid = 0;
99  FILE *fp_tmp = mutt_open_read(c_signature, &pid);
100  if (!fp_tmp)
101  {
102  mutt_perror(c_signature);
103  return;
104  }
105 
106  const bool c_sig_dashes = cs_subset_bool(sub, "sig_dashes");
107  if (c_sig_dashes)
108  fputs("\n-- \n", fp);
109  mutt_file_copy_stream(fp_tmp, fp);
110  mutt_file_fclose(&fp_tmp);
111  if (pid != -1)
112  filter_wait(pid);
113 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define mutt_perror(...)
Definition: logging.h:85
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:133
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:1305
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 121 of file send.c.

122 {
123  struct Address *a = NULL, *tmp = NULL;
124  TAILQ_FOREACH_SAFE(a, al, entries, tmp)
125  {
126  if (mutt_addr_is_user(a) && (!leave_only || TAILQ_NEXT(a, entries)))
127  {
128  TAILQ_REMOVE(al, a, entries);
129  mutt_addr_free(&a);
130  }
131  }
132 }
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:728
An email address.
Definition: address.h:34
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:834
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:547
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
+ 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 140 of file send.c.

142 {
143  const struct AddressList *const als[] = { t, c };
144 
145  for (size_t i = 0; i < mutt_array_size(als); ++i)
146  {
147  const struct AddressList *al = als[i];
148  struct Address *a = NULL;
149  TAILQ_FOREACH(a, al, entries)
150  {
151  if (!a->group && mutt_is_mail_list(a))
152  {
154  }
155  }
156  }
157 }
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
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:45
An email address.
Definition: address.h:34
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:38
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1488
+ 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 167 of file send.c.

168 {
169  char buf[8192];
170  char *err = NULL;
171  int idna_ok = 0;
172 
173  do
174  {
175  buf[0] = '\0';
177  mutt_addrlist_write(al, buf, sizeof(buf), false);
178  if (mutt_get_field(field, buf, sizeof(buf), MUTT_ALIAS) != 0)
179  return -1;
181  mutt_addrlist_parse2(al, buf);
182  if (expand_aliases)
184  idna_ok = mutt_addrlist_to_intl(al, &err);
185  if (idna_ok != 0)
186  {
187  mutt_error(_("Bad IDN: '%s'"), err);
188  FREE(&err);
189  }
190  } while (idna_ok != 0);
191  return 0;
192 }
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:294
#define MUTT_ALIAS
Do alias "completion" by calling up the alias-menu.
Definition: mutt.h:57
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1386
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1468
#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
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:91
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1304
#define mutt_error(...)
Definition: logging.h:84
#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 202 of file send.c.

203 {
204  char buf[8192];
205 
206 #ifdef USE_NNTP
207  if (OptNewsSend)
208  {
209  if (en->newsgroups)
210  mutt_str_copy(buf, en->newsgroups, sizeof(buf));
211  else
212  buf[0] = '\0';
213  if (mutt_get_field("Newsgroups: ", buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0)
214  return -1;
215  FREE(&en->newsgroups);
216  en->newsgroups = mutt_str_dup(buf);
217 
218  if (en->followup_to)
219  mutt_str_copy(buf, en->followup_to, sizeof(buf));
220  else
221  buf[0] = '\0';
222 
223  const bool c_ask_follow_up = cs_subset_bool(sub, "ask_follow_up");
224  if (c_ask_follow_up &&
225  (mutt_get_field("Followup-To: ", buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0))
226  {
227  return -1;
228  }
229  FREE(&en->followup_to);
230  en->followup_to = mutt_str_dup(buf);
231 
232  if (en->x_comment_to)
233  mutt_str_copy(buf, en->x_comment_to, sizeof(buf));
234  else
235  buf[0] = '\0';
236 
237  const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
238  const bool c_ask_x_comment_to = cs_subset_bool(sub, "ask_x_comment_to");
239  if (c_x_comment_to && c_ask_x_comment_to &&
240  (mutt_get_field("X-Comment-To: ", buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0))
241  {
242  return -1;
243  }
244  FREE(&en->x_comment_to);
245  en->x_comment_to = mutt_str_dup(buf);
246  }
247  else
248 #endif
249  {
250  if ((mutt_edit_address(&en->to, _("To: "), true) == -1) || TAILQ_EMPTY(&en->to))
251  return -1;
252 
253  const bool c_askcc = cs_subset_bool(sub, "askcc");
254  if (c_askcc && (mutt_edit_address(&en->cc, _("Cc: "), true) == -1))
255  return -1;
256 
257  const bool c_askbcc = cs_subset_bool(sub, "askbcc");
258  if (c_askbcc && (mutt_edit_address(&en->bcc, _("Bcc: "), true) == -1))
259  return -1;
260 
261  const bool c_reply_with_xorig = cs_subset_bool(sub, "reply_with_xorig");
262  if (c_reply_with_xorig && (flags & (SEND_REPLY | SEND_LIST_REPLY | SEND_GROUP_REPLY)) &&
263  (mutt_edit_address(&en->from, "From: ", true) == -1))
264  {
265  return -1;
266  }
267  }
268 
269  if (en->subject)
270  {
271  const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
272  if (c_fast_reply)
273  return 0;
274  mutt_str_copy(buf, en->subject, sizeof(buf));
275  }
276  else
277  {
278  const char *p = NULL;
279 
280  buf[0] = '\0';
281  struct ListNode *uh = NULL;
282  STAILQ_FOREACH(uh, &UserHeader, entries)
283  {
284  size_t plen = mutt_istr_startswith(uh->data, "subject:");
285  if (plen)
286  {
287  p = mutt_str_skip_email_wsp(uh->data + plen);
288  mutt_str_copy(buf, p, sizeof(buf));
289  }
290  }
291  }
292 
293  const enum QuadOption c_abort_nosubject =
294  cs_subset_quad(sub, "abort_nosubject");
295  if ((mutt_get_field(_("Subject: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0) ||
296  ((buf[0] == '\0') &&
297  (query_quadoption(c_abort_nosubject, _("No subject, abort?")) != MUTT_NO)))
298  {
299  mutt_message(_("No subject, aborting"));
300  return -1;
301  }
302  mutt_str_replace(&en->subject, buf);
303 
304  return 0;
305 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define mutt_message(...)
Definition: logging.h:83
struct AddressList bcc
Email&#39;s &#39;Bcc&#39; list.
Definition: envelope.h:60
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
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:91
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
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
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:43
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:743
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:349
#define SEND_REPLY
Reply to sender.
Definition: send.h:41
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:154
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:42
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:716
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 FREE(x)
Definition: memory.h:40
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_EMPTY(head)
Definition: queue.h:714
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:46
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:167
+ 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 315 of file send.c.

316 {
317  SKIPWS(s);
318  return mutt_str_dup(s);
319 }
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 326 of file send.c.

327 {
328  struct ListNode *uh = NULL;
329  STAILQ_FOREACH(uh, &UserHeader, entries)
330  {
331  size_t plen;
332  if ((plen = mutt_istr_startswith(uh->data, "to:")))
333  mutt_addrlist_parse(&env->to, uh->data + plen);
334  else if ((plen = mutt_istr_startswith(uh->data, "cc:")))
335  mutt_addrlist_parse(&env->cc, uh->data + plen);
336  else if ((plen = mutt_istr_startswith(uh->data, "bcc:")))
337  mutt_addrlist_parse(&env->bcc, uh->data + plen);
338 #ifdef USE_NNTP
339  else if ((plen = mutt_istr_startswith(uh->data, "newsgroups:")))
340  env->newsgroups = nntp_get_header(uh->data + plen);
341  else if ((plen = mutt_istr_startswith(uh->data, "followup-to:")))
342  env->followup_to = nntp_get_header(uh->data + plen);
343  else if ((plen = mutt_istr_startswith(uh->data, "x-comment-to:")))
344  env->x_comment_to = nntp_get_header(uh->data + plen);
345 #endif
346  }
347 }
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:315
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:349
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 353 of file send.c.

354 {
355  struct ListNode *uh = NULL;
356  STAILQ_FOREACH(uh, &UserHeader, entries)
357  {
358  size_t plen;
359  if ((plen = mutt_istr_startswith(uh->data, "from:")))
360  {
361  /* User has specified a default From: address. Remove default address */
362  mutt_addrlist_clear(&env->from);
363  mutt_addrlist_parse(&env->from, uh->data + plen);
364  }
365  else if ((plen = mutt_istr_startswith(uh->data, "reply-to:")))
366  {
368  mutt_addrlist_parse(&env->reply_to, uh->data + plen);
369  }
370  else if ((plen = mutt_istr_startswith(uh->data, "message-id:")))
371  {
372  char *tmp = mutt_extract_message_id(uh->data + plen, NULL);
373  if (mutt_addr_valid_msgid(tmp))
374  {
375  FREE(&env->message_id);
376  env->message_id = tmp;
377  }
378  else
379  FREE(&tmp);
380  }
381  else if (!mutt_istr_startswith(uh->data, "to:") &&
382  !mutt_istr_startswith(uh->data, "cc:") &&
383  !mutt_istr_startswith(uh->data, "bcc:") &&
384 #ifdef USE_NNTP
385  !mutt_istr_startswith(uh->data, "newsgroups:") &&
386  !mutt_istr_startswith(uh->data, "followup-to:") &&
387  !mutt_istr_startswith(uh->data, "x-comment-to:") &&
388 #endif
389  !mutt_istr_startswith(uh->data, "supersedes:") &&
390  !mutt_istr_startswith(uh->data, "subject:") &&
391  !mutt_istr_startswith(uh->data, "return-path:"))
392  {
394  }
395  }
396 }
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:1468
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:361
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:349
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 Mailbox m,
struct Email e,
FILE *  fp,
struct ConfigSubset sub 
)

Add the "start of forwarded message" text.

Parameters
mMailbox
eEmail
subConfig Subset
fpFile to write to

Definition at line 405 of file send.c.

406 {
407  const char *c_forward_attribution_intro =
408  cs_subset_string(sub, "forward_attribution_intro");
409  if (!c_forward_attribution_intro || !fp)
410  return;
411 
412  const char *c_attribution_locale =
413  cs_subset_string(sub, "attribution_locale");
414 
415  char buf[1024];
416  setlocale(LC_TIME, NONULL(c_attribution_locale));
417  mutt_make_string(buf, sizeof(buf), 0, c_forward_attribution_intro, m, -1, e);
418  setlocale(LC_TIME, "");
419  fputs(buf, fp);
420  fputs("\n\n", fp);
421 }
#define NONULL(x)
Definition: string2.h:37
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
#define mutt_make_string(BUF, BUFLEN, COLS, S, M, INPGR, E)
Definition: hdrline.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_forward_trailer()

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

Add a "end of forwarded message" text.

Parameters
mMailbox
eEmail
subConfig Subset
fpFile to write to

Definition at line 430 of file send.c.

432 {
433  const char *c_forward_attribution_trailer =
434  cs_subset_string(sub, "forward_attribution_trailer");
435  if (!c_forward_attribution_trailer || !fp)
436  return;
437 
438  const char *c_attribution_locale =
439  cs_subset_string(sub, "attribution_locale");
440 
441  char buf[1024];
442  setlocale(LC_TIME, NONULL(c_attribution_locale));
443  mutt_make_string(buf, sizeof(buf), 0, c_forward_attribution_trailer, m, -1, e);
444  setlocale(LC_TIME, "");
445  fputc('\n', fp);
446  fputs(buf, fp);
447  fputc('\n', fp);
448 }
#define NONULL(x)
Definition: string2.h:37
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
#define mutt_make_string(BUF, BUFLEN, COLS, S, M, INPGR, E)
Definition: hdrline.h:58
+ 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 459 of file send.c.

461 {
462  CopyHeaderFlags chflags = CH_DECODE;
464 
467 
468  const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
469  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) && c_forward_decode)
470  {
471  /* make sure we have the user's passphrase before proceeding... */
473  return -1;
474  }
475 
476  mutt_forward_intro(m, e, fp_out, sub);
477 
478  if (c_forward_decode)
479  {
480  cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
481 
482  const bool c_weed = cs_subset_bool(sub, "weed");
483  if (c_weed)
484  {
485  chflags |= CH_WEED | CH_REORDER;
486  cmflags |= MUTT_CM_WEED;
487  }
488  }
489 
490  const bool c_forward_quote = cs_subset_bool(sub, "forward_quote");
491  if (c_forward_quote)
492  cmflags |= MUTT_CM_PREFIX;
493 
494  mutt_copy_message(fp_out, m, e, cmflags, chflags, 0);
495  mutt_forward_trailer(m, e, fp_out, sub);
496  return 0;
497 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define WithCrypto
Definition: lib.h:123
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:40
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:49
int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:835
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:52
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:31
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:34
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:134
#define CH_WEED
Weed the headers?
Definition: copy.h:52
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:36
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:37
#define CH_REORDER
Re-order output of headers (specified by &#39;hdr_order&#39;)
Definition: copy.h:58
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:41
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:53
void mutt_forward_intro(struct Mailbox *m, struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add the "start of forwarded message" text.
Definition: send.c:405
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:49
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:573
void mutt_forward_trailer(struct Mailbox *m, struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add a "end of forwarded message" text.
Definition: send.c:430
+ 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 509 of file send.c.

512 {
513  struct Body **last = *plast;
514  struct Body *body = NULL;
515  struct Message *msg = NULL;
516  struct AttachCtx *actx = NULL;
517  int rc = 0, i;
518 
521 
522  msg = mx_msg_open(m, e->msgno);
523  if (!msg)
524  return -1;
525 
526  actx = mutt_mem_calloc(1, sizeof(*actx));
527  actx->email = e;
528  actx->fp_root = msg->fp;
529 
530  mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
531  actx->fp_root, -1, 0, 0);
532 
533  for (i = 0; i < actx->idxlen; i++)
534  {
535  body = actx->idx[i]->body;
536  if ((body->type != TYPE_MULTIPART) && !mutt_can_decode(body) &&
537  !((body->type == TYPE_APPLICATION) &&
538  (mutt_istr_equal(body->subtype, "pgp-signature") ||
539  mutt_istr_equal(body->subtype, "x-pkcs7-signature") ||
540  mutt_istr_equal(body->subtype, "pkcs7-signature"))))
541  {
542  /* Ask the quadoption only once */
543  if (*forwardq == MUTT_ABORT)
544  {
545  const enum QuadOption c_forward_attachments =
546  cs_subset_quad(sub, "forward_attachments");
547  *forwardq = query_quadoption(c_forward_attachments,
548  /* L10N: This is the prompt for $forward_attachments.
549  When inline forwarding ($mime_forward answered "no"), this prompts
550  whether to add non-decodable attachments from the original email.
551  Text/plain parts and the like will already be included in the
552  message contents, but other attachment, such as PDF files, will also
553  be added as attachments to the new mail, if this is answered yes. */
554  _("Forward attachments?"));
555  if (*forwardq != MUTT_YES)
556  {
557  if (*forwardq == -1)
558  rc = -1;
559  goto cleanup;
560  }
561  }
562  if (mutt_body_copy(actx->idx[i]->fp, last, body) == -1)
563  {
564  rc = -1;
565  goto cleanup;
566  }
567  last = &((*last)->next);
568  }
569  }
570 
571 cleanup:
572  *plast = last;
573  mx_msg_close(m, &msg);
574  mutt_actx_free(&actx);
575  return rc;
576 }
void mutt_actx_free(struct AttachCtx **ptr)
Free an Attachment Context.
Definition: attach.c:140
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:1361
struct Email * email
Used by recvattach for updating.
Definition: attach.h:51
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:52
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:49
#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:52
The body of an email.
Definition: body.h:34
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1205
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
User aborted the question (with Ctrl-G)
Definition: quad.h:38
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
char * subtype
content-type subtype
Definition: body.h:37
A local copy of an email.
Definition: mx.h:82
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1805
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:154
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
FILE * fp
pointer to the message data
Definition: mx.h:84
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:573
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:1159
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:40
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 Mailbox m,
struct Email e,
FILE *  fp_out,
struct ConfigSubset sub 
)

Add "on DATE, PERSON wrote" header.

Parameters
mMailbox
eEmail
fp_outFile to write to
subConfig Subset

Definition at line 585 of file send.c.

587 {
588  const char *c_attribution = cs_subset_string(sub, "attribution");
589  if (!c_attribution || !fp_out)
590  return;
591 
592  const char *c_attribution_locale =
593  cs_subset_string(sub, "attribution_locale");
594 
595  char buf[1024];
596  setlocale(LC_TIME, NONULL(c_attribution_locale));
597  mutt_make_string(buf, sizeof(buf), 0, c_attribution, m, -1, e);
598  setlocale(LC_TIME, "");
599  fputs(buf, fp_out);
600  fputc('\n', fp_out);
601 }
#define NONULL(x)
Definition: string2.h:37
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
#define mutt_make_string(BUF, BUFLEN, COLS, S, M, INPGR, E)
Definition: hdrline.h:58
+ 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 Mailbox m,
struct Email e,
FILE *  fp_out,
struct ConfigSubset sub 
)

Add suffix to replied email text.

Parameters
mMailbox
eEmail
fp_outFile to write to
subConfig Subset

Definition at line 610 of file send.c.

612 {
613  const char *c_post_indent_string =
614  cs_subset_string(sub, "post_indent_string");
615  if (!c_post_indent_string || !fp_out)
616  return;
617 
618  char buf[256];
619  mutt_make_string(buf, sizeof(buf), 0, c_post_indent_string, m, -1, e);
620  fputs(buf, fp_out);
621  fputc('\n', fp_out);
622 }
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
#define mutt_make_string(BUF, BUFLEN, COLS, S, M, INPGR, E)
Definition: hdrline.h:58
+ 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 633 of file send.c.

635 {
636  CopyMessageFlags cmflags =
638  CopyHeaderFlags chflags = CH_DECODE;
639 
640  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
641  {
642  /* make sure we have the user's passphrase before proceeding... */
644  return -1;
645  }
646 
649 
650  mutt_make_attribution(m, e, fp_out, sub);
651 
652  const bool c_header = cs_subset_bool(sub, "header");
653  if (!c_header)
654  cmflags |= MUTT_CM_NOHEADER;
655 
656  const bool c_weed = cs_subset_bool(sub, "weed");
657  if (c_weed)
658  {
659  chflags |= CH_WEED | CH_REORDER;
660  cmflags |= MUTT_CM_WEED;
661  }
662 
663  mutt_copy_message(fp_out, m, e, cmflags, chflags, 0);
664 
665  mutt_make_post_indent(m, e, fp_out, sub);
666 
667  return 0;
668 }
void mutt_make_attribution(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add "on DATE, PERSON wrote" header.
Definition: send.c:585
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define WithCrypto
Definition: lib.h:123
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:40
void mutt_parse_mime_message(struct Mailbox *m, struct Email *e)
Parse a MIME email.
Definition: mutt_parse.c:49
int mutt_copy_message(FILE *fp_out, struct Mailbox *m, struct Email *e, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:835
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:52
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:31
#define MUTT_CM_REPLYING
Replying the message.
Definition: copy.h:43
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:134
#define CH_WEED
Weed the headers?
Definition: copy.h:52
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:36
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:37
#define CH_REORDER
Re-order output of headers (specified by &#39;hdr_order&#39;)
Definition: copy.h:58
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:41
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:53
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:49
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:573
#define MUTT_CM_NOHEADER
Don&#39;t copy the message header.
Definition: copy.h:35
void mutt_make_post_indent(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add suffix to replied email text.
Definition: send.c:610
+ 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 677 of file send.c.

680 {
681  const bool c_reply_self = cs_subset_bool(sub, "reply_self");
682  if (!c_reply_self && mutt_addr_is_user(from))
683  {
684  /* mail is from the user, assume replying to recipients */
685  return &env->to;
686  }
687  else
688  {
689  return &env->from;
690  }
691 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
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:547
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 703 of file send.c.

705 {
706  const struct Address *from = TAILQ_FIRST(&env->from);
707  const struct Address *reply_to = TAILQ_FIRST(&env->reply_to);
708 
709  if (flags && !TAILQ_EMPTY(&env->mail_followup_to) && (hmfupto == MUTT_YES))
710  {
711  mutt_addrlist_copy(to, &env->mail_followup_to, true);
712  return 0;
713  }
714 
715  /* Exit now if we're setting up the default Cc list for list-reply
716  * (only set if Mail-Followup-To is present and honoured). */
717  if (flags & SEND_LIST_REPLY)
718  return 0;
719 
720  const struct AddressList *default_to = choose_default_to(from, env, sub);
721 
722  if (reply_to)
723  {
724  const bool from_is_reply_to = mutt_addr_cmp(from, reply_to);
725  const bool multiple_reply_to =
726  reply_to && TAILQ_NEXT(TAILQ_FIRST(&env->reply_to), entries);
727 
728  const bool c_ignore_list_reply_to =
729  cs_subset_bool(sub, "ignore_list_reply_to");
730  const enum QuadOption c_reply_to = cs_subset_quad(sub, "reply_to");
731  if ((from_is_reply_to && !multiple_reply_to && !reply_to->personal) ||
732  (c_ignore_list_reply_to && mutt_is_mail_list(reply_to) &&
733  (mutt_addrlist_search(&env->to, reply_to) || mutt_addrlist_search(&env->cc, reply_to))))
734  {
735  /* If the Reply-To: address is a mailing list, assume that it was
736  * put there by the mailing list, and use the From: address
737  *
738  * We also take the from header if our correspondent has a reply-to
739  * header which is identical to the electronic mail address given
740  * in his From header, and the reply-to has no display-name. */
741  mutt_addrlist_copy(to, &env->from, false);
742  }
743  else if (!(from_is_reply_to && !multiple_reply_to) && (c_reply_to != MUTT_YES))
744  {
745  char prompt[256];
746  /* There are quite a few mailing lists which set the Reply-To:
747  * header field to the list address, which makes it quite impossible
748  * to send a message to only the sender of the message. This
749  * provides a way to do that. */
750  /* L10N: Asks whether the user respects the reply-to header.
751  If she says no, neomutt will reply to the from header's address instead. */
752  snprintf(prompt, sizeof(prompt), _("Reply to %s%s?"), reply_to->mailbox,
753  multiple_reply_to ? ",..." : "");
754  switch (query_quadoption(c_reply_to, prompt))
755  {
756  case MUTT_YES:
757  mutt_addrlist_copy(to, &env->reply_to, false);
758  break;
759 
760  case MUTT_NO:
761  mutt_addrlist_copy(to, default_to, false);
762  break;
763 
764  default:
765  return -1; /* abort */
766  }
767  }
768  else
769  {
770  mutt_addrlist_copy(to, &env->reply_to, false);
771  }
772  }
773  else
774  {
775  mutt_addrlist_copy(to, default_to, false);
776  }
777 
778  return 0;
779 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define TAILQ_FIRST(head)
Definition: queue.h:716
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:45
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:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
static int default_to(struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
Generate default email addresses.
Definition: send.c:703
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:677
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
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:43
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:154
char * personal
Real name of address.
Definition: address.h:36
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
#define TAILQ_EMPTY(head)
Definition: queue.h:714
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
+ 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 790 of file send.c.

792 {
793  enum QuadOption hmfupto = MUTT_ABORT;
794  const struct Address *followup_to = TAILQ_FIRST(&in->mail_followup_to);
795 
796  if ((flags & (SEND_LIST_REPLY | SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) && followup_to)
797  {
798  char prompt[256];
799  snprintf(prompt, sizeof(prompt), _("Follow-up to %s%s?"), followup_to->mailbox,
800  TAILQ_NEXT(TAILQ_FIRST(&in->mail_followup_to), entries) ? ",..." : "");
801 
802  const enum QuadOption c_honor_followup_to =
803  cs_subset_quad(sub, "honor_followup_to");
804  hmfupto = query_quadoption(c_honor_followup_to, prompt);
805  if (hmfupto == MUTT_ABORT)
806  return -1;
807  }
808 
809  if (flags & SEND_LIST_REPLY)
810  {
811  add_mailing_lists(&out->to, &in->to, &in->cc);
812 
813  if (followup_to && (hmfupto == MUTT_YES) &&
814  (default_to(&out->cc, in, flags & SEND_LIST_REPLY, (hmfupto == MUTT_YES), sub) == MUTT_ABORT))
815  {
816  return -1; /* abort */
817  }
818  }
819  else if (flags & SEND_TO_SENDER)
820  {
821  mutt_addrlist_copy(&out->to, &in->from, false);
822  }
823  else
824  {
825  if (default_to(&out->to, in, flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY),
826  (hmfupto == MUTT_YES), sub) == -1)
827  return -1; /* abort */
828 
829  if ((flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) &&
830  (!followup_to || (hmfupto != MUTT_YES)))
831  {
832  /* if(!mutt_addr_is_user(in->to)) */
833  if (flags & SEND_GROUP_REPLY)
834  mutt_addrlist_copy(&out->cc, &in->to, true);
835  else
836  mutt_addrlist_copy(&out->to, &in->to, true);
837  mutt_addrlist_copy(&out->cc, &in->cc, true);
838  }
839  }
840  return 0;
841 }
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:52
#define TAILQ_FIRST(head)
Definition: queue.h:716
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:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
static int default_to(struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
Generate default email addresses.
Definition: send.c:703
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
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:43
User aborted the question (with Ctrl-G)
Definition: quad.h:38
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:154
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:42
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:140
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_NEXT(elm, field)
Definition: queue.h:825
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:53
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
+ 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 848 of file send.c.

849 {
850  struct ListNode *np = NULL;
851 
852  struct ListHead *src = STAILQ_EMPTY(&env->references) ? &env->in_reply_to : &env->references;
853  STAILQ_FOREACH(np, src, entries)
854  {
856  }
857 }
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:349
char * data
String.
Definition: list.h:36
#define STAILQ_EMPTY(head)
Definition: queue.h:345
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 864 of file send.c.

865 {
866  if (env->message_id)
867  {
869  }
870 }
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 877 of file send.c.

878 {
879  const bool c_metoo = cs_subset_bool(sub, "metoo");
880  if (!c_metoo)
881  {
882  const bool c_reply_self = cs_subset_bool(sub, "reply_self");
883 
884  /* the order is important here. do the CC: first so that if the
885  * the user is the only recipient, it ends up on the TO: field */
886  remove_user(&env->cc, TAILQ_EMPTY(&env->to));
887  remove_user(&env->to, TAILQ_EMPTY(&env->cc) || c_reply_self);
888  }
889 
890  /* the CC field can get cluttered, especially with lists */
891  mutt_addrlist_dedupe(&env->to);
892  mutt_addrlist_dedupe(&env->cc);
893  mutt_addrlist_remove_xrefs(&env->to, &env->cc);
894 
895  if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
896  {
897  TAILQ_SWAP(&env->to, &env->cc, Address, entries);
898  }
899 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
An email address.
Definition: address.h:34
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1405
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:1441
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_EMPTY(head)
Definition: queue.h:714
static void remove_user(struct AddressList *al, bool leave_only)
Remove any address which matches the current user.
Definition: send.c:121
#define TAILQ_SWAP(head1, head2, type, field)
Definition: queue.h:852
+ 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 Mailbox m,
struct Email e,
struct ConfigSubset sub 
)

Create a subject for a forwarded email.

Parameters
envEnvelope for result
mMailbox
eEmail
subConfig Subset

Definition at line 908 of file send.c.

910 {
911  if (!env)
912  return;
913 
914  const char *c_forward_format = cs_subset_string(sub, "forward_format");
915 
916  char buf[256];
917  /* set the default subject for the message. */
918  mutt_make_string(buf, sizeof(buf), 0, NONULL(c_forward_format), m, -1, e);
919  mutt_str_replace(&env->subject, buf);
920 }
#define NONULL(x)
Definition: string2.h:37
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
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
#define mutt_make_string(BUF, BUFLEN, COLS, S, M, INPGR, E)
Definition: hdrline.h:58
+ 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 928 of file send.c.

930 {
931  if (!env || !curenv)
932  return;
933 
934  /* This takes precedence over a subject that might have
935  * been taken from a List-Post header. Is that correct? */
936  if (curenv->real_subj)
937  {
938  FREE(&env->subject);
939  env->subject = mutt_mem_malloc(mutt_str_len(curenv->real_subj) + 5);
940  sprintf(env->subject, "Re: %s", curenv->real_subj);
941  }
942  else if (!env->subject)
943  {
944  const char *c_empty_subject = cs_subset_string(sub, "empty_subject");
945  env->subject = mutt_str_dup(c_empty_subject);
946  }
947 }
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:241
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:631
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 955 of file send.c.

957 {
958  add_references(&env->references, curenv);
959  add_message_id(&env->references, curenv);
960  add_message_id(&env->in_reply_to, curenv);
961 
962 #ifdef USE_NNTP
963  const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
964  if (OptNewsSend && c_x_comment_to && !TAILQ_EMPTY(&curenv->from))
966 #endif
967 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define TAILQ_FIRST(head)
Definition: queue.h:716
static void add_references(struct ListHead *head, struct Envelope *env)
Add the email&#39;s references to a list.
Definition: send.c:848
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:864
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:714
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:46
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:158
+ 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 975 of file send.c.

977 {
978  if (!el || !env || STAILQ_EMPTY(el))
979  return;
980 
981  struct EmailNode *en = STAILQ_FIRST(el);
982  bool single = !STAILQ_NEXT(en, entries);
983 
984  if (!single)
985  {
986  STAILQ_FOREACH(en, el, entries)
987  {
988  mutt_add_to_reference_headers(env, en->email->env, sub);
989  }
990  }
991  else
992  mutt_add_to_reference_headers(env, en->email->env, sub);
993 
994  /* if there's more than entry in In-Reply-To (i.e. message has multiple
995  * parents), don't generate a References: header as it's discouraged by
996  * RFC2822, sect. 3.6.4 */
997  if (!single && !STAILQ_EMPTY(&env->in_reply_to) &&
998  STAILQ_NEXT(STAILQ_FIRST(&env->in_reply_to), entries))
999  {
1000  mutt_list_free(&env->references);
1001  }
1002 }
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:349
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
struct Email * email
Email in the list.
Definition: email.h:127
#define STAILQ_EMPTY(head)
Definition: queue.h:345
List of Emails.
Definition: email.h:125
struct ListHead references
message references (in reverse order)
Definition: envelope.h:81
#define STAILQ_FIRST(head)
Definition: queue.h:347
void mutt_add_to_reference_headers(struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
Generate references for a reply email.
Definition: send.c:955
+ 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 1014 of file send.c.

1016 {
1017  if (!el || STAILQ_EMPTY(el))
1018  return -1;
1019 
1020  struct EmailNode *en = STAILQ_FIRST(el);
1021  bool single = !STAILQ_NEXT(en, entries);
1022 
1023  struct Envelope *curenv = en->email->env;
1024  if (!curenv)
1025  return -1;
1026 
1027  if (flags & (SEND_REPLY | SEND_TO_SENDER))
1028  {
1029 #ifdef USE_NNTP
1030  if ((flags & SEND_NEWS))
1031  {
1032  /* in case followup set Newsgroups: with Followup-To: if it present */
1033  if (!env->newsgroups && !mutt_istr_equal(curenv->followup_to, "poster"))
1034  {
1035  env->newsgroups = mutt_str_dup(curenv->followup_to);
1036  }
1037  }
1038  else
1039 #endif
1040  if (!single)
1041  {
1042  STAILQ_FOREACH(en, el, entries)
1043  {
1044  if (mutt_fetch_recips(env, en->email->env, flags, sub) == -1)
1045  return -1;
1046  }
1047  }
1048  else if (mutt_fetch_recips(env, curenv, flags, sub) == -1)
1049  return -1;
1050 
1051  if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
1052  {
1053  mutt_error(_("No mailing lists found"));
1054  return -1;
1055  }
1056 
1057  if (flags & SEND_REPLY)
1058  {
1059  mutt_make_misc_reply_headers(env, curenv, sub);
1060  make_reference_headers(el, env, sub);
1061  }
1062  }
1063  else if (flags & SEND_FORWARD)
1064  {
1065  mutt_make_forward_subject(env, m, en->email, sub);
1066 
1067  const bool c_forward_references = cs_subset_bool(sub, "forward_references");
1068  if (c_forward_references)
1069  make_reference_headers(el, env, sub);
1070  }
1071 
1072  return 0;
1073 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:52
#define SEND_FORWARD
Forward email.
Definition: send.h:44
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:975
struct Envelope * env
Envelope information.
Definition: email.h:90
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:43
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
#define SEND_NEWS
Reply to a news article.
Definition: send.h:54
int mutt_fetch_recips(struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
Generate recpients for a reply email.
Definition: send.c:790
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
#define SEND_REPLY
Reply to sender.
Definition: send.h:41
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
struct Email * email
Email in the list.
Definition: email.h:127
#define mutt_error(...)
Definition: logging.h:84
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
#define STAILQ_EMPTY(head)
Definition: queue.h:345
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
List of Emails.
Definition: email.h:125
void mutt_make_misc_reply_headers(struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
Set subject for a reply.
Definition: send.c:928
#define TAILQ_EMPTY(head)
Definition: queue.h:714
#define STAILQ_FIRST(head)
Definition: queue.h:347
The header of an Email.
Definition: envelope.h:54
void mutt_make_forward_subject(struct Envelope *env, struct Mailbox *m, struct Email *e, struct ConfigSubset *sub)
Create a subject for a forwarded email.
Definition: send.c:908
+ 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 1086 of file send.c.

1088 {
1089  /* An EmailList is required for replying and forwarding */
1090  if (!el && (flags & (SEND_REPLY | SEND_FORWARD)))
1091  return -1;
1092 
1093  if (flags & SEND_REPLY)
1094  {
1095  const enum QuadOption c_include = cs_subset_quad(sub, "include");
1096  enum QuadOption ans =
1097  query_quadoption(c_include, _("Include message in reply?"));
1098  if (ans == MUTT_ABORT)
1099  return -1;
1100 
1101  if (ans == MUTT_YES)
1102  {
1103  mutt_message(_("Including quoted message..."));
1104  struct EmailNode *en = NULL;
1105  STAILQ_FOREACH(en, el, entries)
1106  {
1107  if (include_reply(m, en->email, fp_tmp, sub) == -1)
1108  {
1109  mutt_error(_("Could not include all requested messages"));
1110  return -1;
1111  }
1112  if (STAILQ_NEXT(en, entries) != NULL)
1113  {
1114  fputc('\n', fp_tmp);
1115  }
1116  }
1117  }
1118  }
1119  else if (flags & SEND_FORWARD)
1120  {
1121  const enum QuadOption c_mime_forward = cs_subset_quad(sub, "mime_forward");
1122  enum QuadOption ans =
1123  query_quadoption(c_mime_forward, _("Forward as attachment?"));
1124  if (ans == MUTT_YES)
1125  {
1126  struct Body *last = e->body;
1127 
1128  mutt_message(_("Preparing forwarded message..."));
1129 
1130  while (last && last->next)
1131  last = last->next;
1132 
1133  struct EmailNode *en = NULL;
1134  STAILQ_FOREACH(en, el, entries)
1135  {
1136  struct Body *tmp = mutt_make_message_attach(m, en->email, false, sub);
1137  if (last)
1138  {
1139  last->next = tmp;
1140  last = tmp;
1141  }
1142  else
1143  {
1144  last = tmp;
1145  e->body = tmp;
1146  }
1147  }
1148  }
1149  else if (ans != MUTT_ABORT)
1150  {
1151  enum QuadOption forwardq = MUTT_ABORT;
1152  struct Body **last = NULL;
1153  struct EmailNode *en = NULL;
1154 
1155  const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
1156  const enum QuadOption c_forward_attachments =
1157  cs_subset_quad(sub, "forward_attachments");
1158  if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1159  {
1160  last = &e->body;
1161  while (*last)
1162  last = &((*last)->next);
1163  }
1164 
1165  STAILQ_FOREACH(en, el, entries)
1166  {
1167  struct Email *e_cur = en->email;
1168  include_forward(m, e_cur, fp_tmp, sub);
1169  if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1170  {
1171  if (inline_forward_attachments(m, e_cur, &last, &forwardq, sub) != 0)
1172  return -1;
1173  }
1174  }
1175  }
1176  else
1177  return -1;
1178  }
1179  /* if (WithCrypto && (flags & SEND_KEY)) */
1180  else if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY))
1181  {
1182  struct Body *b = NULL;
1183 
1184  if (((WithCrypto & APPLICATION_PGP) != 0) && !(b = crypt_pgp_make_key_attachment()))
1185  {
1186  return -1;
1187  }
1188 
1189  b->next = e->body;
1190  e->body = b;
1191  }
1192 
1193  mutt_clear_error();
1194 
1195  return 0;
1196 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define WithCrypto
Definition: lib.h:123
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:459
#define mutt_message(...)
Definition: logging.h:83
#define SEND_FORWARD
Forward email.
Definition: send.h:44
#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:36
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
User aborted the question (with Ctrl-G)
Definition: quad.h:38
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:47
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:509
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
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:937
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:633
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
#define SEND_REPLY
Reply to sender.
Definition: send.h:41
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:154
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
struct Body * crypt_pgp_make_key_attachment(void)
Wrapper for CryptModuleSpecs::pgp_make_key_attachment()
Definition: cryptglue.c:303
struct Email * email
Email in the list.
Definition: email.h:127
#define mutt_error(...)
Definition: logging.h:84
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
List of Emails.
Definition: email.h:125
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
+ 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 1203 of file send.c.

1204 {
1205  /* Only generate the Mail-Followup-To if the user has requested it, and
1206  * it hasn't already been set */
1207 
1208  const bool c_followup_to = cs_subset_bool(sub, "followup_to");
1209  if (!c_followup_to)
1210  return;
1211 #ifdef USE_NNTP
1212  if (OptNewsSend)
1213  {
1214  if (!env->followup_to && env->newsgroups && (strrchr(env->newsgroups, ',')))
1215  env->followup_to = mutt_str_dup(env->newsgroups);
1216  return;
1217  }
1218 #endif
1219 
1220  if (TAILQ_EMPTY(&env->mail_followup_to))
1221  {
1222  if (mutt_is_list_recipient(false, env))
1223  {
1224  /* this message goes to known mailing lists, so create a proper
1225  * mail-followup-to header */
1226 
1227  mutt_addrlist_copy(&env->mail_followup_to, &env->to, false);
1228  mutt_addrlist_copy(&env->mail_followup_to, &env->cc, true);
1229  }
1230 
1231  /* remove ourselves from the mail-followup-to header */
1232  remove_user(&env->mail_followup_to, false);
1233 
1234  /* If we are not subscribed to any of the lists in question, re-add
1235  * ourselves to the mail-followup-to header. The mail-followup-to header
1236  * generated is a no-op with group-reply, but makes sure list-reply has the
1237  * desired effect. */
1238 
1239  if (!TAILQ_EMPTY(&env->mail_followup_to) &&
1240  !mutt_is_subscribed_list_recipient(false, env))
1241  {
1242  struct AddressList *al = NULL;
1243  if (!TAILQ_EMPTY(&env->reply_to))
1244  al = &env->reply_to;
1245  else if (!TAILQ_EMPTY(&env->from))
1246  al = &env->from;
1247 
1248  if (al)
1249  {
1250  struct Address *a = NULL;
1251  TAILQ_FOREACH_REVERSE(a, al, AddressList, entries)
1252  {
1254  }
1255  }
1256  else
1257  {
1259  }
1260  }
1261 
1263  }
1264 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
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:34
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:427
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1405
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
Definition: queue.h:738
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:440
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default &#39;from&#39; Address.
Definition: send.c:1328
void mutt_addrlist_prepend(struct AddressList *al, struct Address *a)
Prepend an Address to an AddressList.
Definition: address.c:1499
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:714
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:46
static void remove_user(struct AddressList *al, bool leave_only)
Remove any address which matches the current user.
Definition: send.c:121
+ 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 1276 of file send.c.

1278 {
1279  struct Address *a = NULL;
1280  if (TAILQ_EMPTY(al))
1281  {
1282  TAILQ_FOREACH(a, &env->to, entries)
1283  {
1284  if (mutt_addr_is_user(a))
1285  {
1287  break;
1288  }
1289  }
1290  }
1291 
1292  if (TAILQ_EMPTY(al))
1293  {
1294  TAILQ_FOREACH(a, &env->cc, entries)
1295  {
1296  if (mutt_addr_is_user(a))
1297  {
1299  break;
1300  }
1301  }
1302  }
1303 
1304  if (TAILQ_EMPTY(al))
1305  {
1306  struct Address *from = TAILQ_FIRST(&env->from);
1307  if (from && mutt_addr_is_user(from))
1308  {
1310  }
1311  }
1312 
1313  if (!TAILQ_EMPTY(al))
1314  {
1315  /* when $reverse_realname is not set, clear the personal name so that it
1316  * may be set via a reply- or send-hook. */
1317 
1318  const bool c_reverse_realname = cs_subset_bool(sub, "reverse_realname");
1319  if (!c_reverse_realname)
1320  FREE(&TAILQ_FIRST(al)->personal);
1321  }
1322 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define TAILQ_FIRST(head)
Definition: queue.h:716
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
An email address.
Definition: address.h:34
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:36
#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:547
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
#define TAILQ_EMPTY(head)
Definition: queue.h:714
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1488
+ 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 1328 of file send.c.

1329 {
1330  /* Note: We let $from override $realname here.
1331  * Is this the right thing to do?
1332  */
1333 
1334  const struct Address *c_from = cs_subset_address(sub, "from");
1335  const bool c_use_domain = cs_subset_bool(sub, "use_domain");
1336  if (c_from)
1337  {
1338  return mutt_addr_copy(c_from);
1339  }
1340  else if (c_use_domain)
1341  {
1342  struct Address *addr = mutt_addr_new();
1343  mutt_str_asprintf(&addr->mailbox, "%s@%s", NONULL(Username),
1344  NONULL(mutt_fqdn(true, sub)));
1345  return addr;
1346  }
1347  else
1348  {
1349  return mutt_addr_create(NULL, Username);
1350  }
1351 }
#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:69
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:385
An email address.
Definition: address.h:34
char * mailbox
Mailbox and host address.
Definition: address.h:37
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: helpers.c:48
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:52
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:1182
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1095
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ invoke_mta()

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

Send an email.

Parameters
eEmail
subConfig Subset
Return values
0Success
-1Failure

Definition at line 1360 of file send.c.

1361 {
1362  struct Buffer *tempfile = NULL;
1363  int rc = -1;
1364 #ifdef USE_SMTP
1365  short old_write_bcc;
1366 #endif
1367 
1368  /* Write out the message in MIME form. */
1369  tempfile = mutt_buffer_pool_get();
1370  mutt_buffer_mktemp(tempfile);
1371  FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w");
1372  if (!fp_tmp)
1373  goto cleanup;
1374 
1375 #ifdef USE_SMTP
1376  const bool c_write_bcc = cs_subset_bool(sub, "write_bcc");
1377  const char *c_smtp_url = cs_subset_string(sub, "smtp_url");
1378  old_write_bcc = c_write_bcc;
1379  if (c_smtp_url)
1380  cs_subset_str_native_set(sub, "write_bcc", false, NULL);
1381 #endif
1382 #ifdef MIXMASTER
1384  !STAILQ_EMPTY(&e->chain),
1386 #endif
1387 #ifndef MIXMASTER
1389  false, mutt_should_hide_protected_subject(e), sub);
1390 #endif
1391 #ifdef USE_SMTP
1392  if (old_write_bcc)
1393  cs_subset_str_native_set(sub, "write_bcc", true, NULL);
1394 #endif
1395 
1396  fputc('\n', fp_tmp); /* tie off the header. */
1397 
1398  if ((mutt_write_mime_body(e->body, fp_tmp, sub) == -1))
1399  goto cleanup;
1400 
1401  if (mutt_file_fclose(&fp_tmp) != 0)
1402  {
1403  mutt_perror(mutt_buffer_string(tempfile));
1404  unlink(mutt_buffer_string(tempfile));
1405  goto cleanup;
1406  }
1407 
1408 #ifdef MIXMASTER
1409  if (!STAILQ_EMPTY(&e->chain))
1410  {
1411  rc = mix_send_message(&e->chain, mutt_buffer_string(tempfile));
1412  goto cleanup;
1413  }
1414 #endif
1415 
1416 #ifdef USE_NNTP
1417  if (OptNewsSend)
1418  goto sendmail;
1419 #endif
1420 
1421 #ifdef USE_SMTP
1422  if (c_smtp_url)
1423  {
1424  rc = mutt_smtp_send(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1425  mutt_buffer_string(tempfile),
1426  (e->body->encoding == ENC_8BIT), sub);
1427  goto cleanup;
1428  }
1429 #endif
1430 
1431 sendmail:
1432  rc = mutt_invoke_sendmail(&e->env->from, &e->env->to, &e->env->cc,
1433  &e->env->bcc, mutt_buffer_string(tempfile),
1434  (e->body->encoding == ENC_8BIT), sub);
1435 cleanup:
1436  if (fp_tmp)
1437  {
1438  mutt_file_fclose(&fp_tmp);
1439  unlink(mutt_buffer_string(tempfile));
1440  }
1441  mutt_buffer_pool_release(&tempfile);
1442  return rc;
1443 }
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:77
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define mutt_perror(...)
Definition: logging.h:85
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:1073
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
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:292
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
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
int mix_send_message(struct ListHead *chain, const char *tempfile)
Send an email via Mixmaster.
Definition: remailer.c:846
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:880
int mutt_invoke_sendmail(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:286
#define STAILQ_EMPTY(head)
Definition: queue.h:345
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:46
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:573
+ 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 1451 of file send.c.

1452 {
1453  for (struct Body *t = b; t; t = t->next)
1454  {
1455  if (t->description)
1456  {
1457  const char *c_send_charset = cs_subset_string(sub, "send_charset");
1458  rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), c_send_charset);
1459  }
1460  if (recurse && t->parts)
1461  mutt_encode_descriptions(t->parts, recurse, sub);
1462  }
1463 }
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:241
void rfc2047_encode(char **pd, const char *specials, int col, const char *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:615
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
rfc2047 encode the content-descriptions
Definition: send.c:1451
+ 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 1469 of file send.c.

1470 {
1471  for (struct Body *t = b; t; t = t->next)
1472  {
1473  if (t->description)
1474  {
1475  rfc2047_decode(&t->description);
1476  }
1477  if (t->parts)
1478  decode_descriptions(t->parts);
1479  }
1480 }
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:639
static void decode_descriptions(struct Body *b)
rfc2047 decode them in case of an error
Definition: send.c:1469
+ 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 1486 of file send.c.

1487 {
1488  FILE *fp = mutt_file_fopen(data, "a+");
1489  if (!fp)
1490  return;
1491  if (fseek(fp, -1, SEEK_END) >= 0)
1492  {
1493  int c = fgetc(fp);
1494  if (c != '\n')
1495  fputc('\n', fp);
1496  }
1497  mutt_file_fclose(&fp);
1498 }
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 Context ctx,
struct Email e_cur,
struct ConfigSubset sub 
)

Resend an email.

Parameters
fpFile containing email
ctxMailbox
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 1510 of file send.c.

1512 {
1513  struct Email *e_new = email_new();
1514 
1515  if (mutt_prepare_template(fp, ctx->mailbox, e_new, e_cur, true) < 0)
1516  {
1517  email_free(&e_new);
1518  return -1;
1519  }
1520 
1521  if (WithCrypto)
1522  {
1523  /* mutt_prepare_template doesn't always flip on an application bit.
1524  * so fix that here */
1525  if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1526  {
1527  const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
1528  if (((WithCrypto & APPLICATION_SMIME) != 0) && c_smime_is_default)
1529  e_new->security |= APPLICATION_SMIME;
1530  else if (WithCrypto & APPLICATION_PGP)
1531  e_new->security |= APPLICATION_PGP;
1532  else
1533  e_new->security |= APPLICATION_SMIME;
1534  }
1535 
1536  const bool c_crypt_opportunistic_encrypt =
1537  cs_subset_bool(sub, "crypt_opportunistic_encrypt");
1538  if (c_crypt_opportunistic_encrypt)
1539  {
1540  e_new->security |= SEC_OPPENCRYPT;
1542  }
1543  }
1544 
1545  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1546  emaillist_add_email(&el, e_cur);
1547  int rc = mutt_send_message(SEND_RESEND, e_new, NULL, ctx, &el, sub);
1548  emaillist_clear(&el);
1549 
1550  return rc;
1551 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define WithCrypto
Definition: lib.h:123
The envelope/body of an email.
Definition: email.h:37
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:43
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:130
struct Email * email_new(void)
Create a new Email.
Definition: email.c:72
struct Mailbox * mailbox
Definition: context.h:50
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:98
#define SEND_RESEND
Reply using the current email as a template.
Definition: send.h:48
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:97
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:151
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:93
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1021
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Context *ctx, struct EmailList *el, struct ConfigSubset *sub)
Send an email.
Definition: send.c:1999
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
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:656
+ 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 1560 of file send.c.

1561 {
1562  if (!reply || !reply->env || !orig || !orig->env)
1563  return false;
1564  return mutt_list_find(&orig->env->references, reply->env->message_id) ||
1565  mutt_list_find(&orig->env->in_reply_to, reply->env->message_id);
1566 }
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
trueIf the 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 1579 of file send.c.

1580 {
1581  const struct Regex *c_abort_noattach_regex =
1582  cs_subset_regex(sub, "abort_noattach_regex");
1583  const struct Regex *c_quote_regex = cs_subset_regex(sub, "quote_regex");
1584 
1585  /* Search for the regex in `$abort_noattach_regex` within a file */
1586  if (!c_abort_noattach_regex || !c_abort_noattach_regex->regex ||
1587  !c_quote_regex || !c_quote_regex->regex)
1588  {
1589  return false;
1590  }
1591 
1592  FILE *fp_att = mutt_file_fopen(filename, "r");
1593  if (!fp_att)
1594  return false;
1595 
1596  char *inputline = mutt_mem_malloc(1024);
1597  bool found = false;
1598  while (!feof(fp_att))
1599  {
1600  fgets(inputline, 1024, fp_att);
1601  if (!mutt_is_quote_line(inputline, NULL) &&
1602  mutt_regex_match(c_abort_noattach_regex, inputline))
1603  {
1604  found = true;
1605  break;
1606  }
1607  }
1608  FREE(&inputline);
1609  mutt_file_fclose(&fp_att);
1610  return found;
1611 }
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:176
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:611
#define FREE(x)
Definition: memory.h:40
int mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition: pager.c:965
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 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]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 1625 of file send.c.

1628 {
1629  int rc = 0;
1630  struct Body *save_content = NULL;
1631 
1633 
1634  /* Don't save a copy when we are in batch-mode, and the FCC
1635  * folder is on an IMAP server: This would involve possibly lots
1636  * of user interaction, which is not available in batch mode.
1637  *
1638  * Note: A patch to fix the problems with the use of IMAP servers
1639  * from non-curses mode is available from Brendan Cully. However,
1640  * I'd like to think a bit more about this before including it. */
1641 
1642 #ifdef USE_IMAP
1643  if ((flags & SEND_BATCH) && !mutt_buffer_is_empty(fcc) &&
1644  (imap_path_probe(mutt_buffer_string(fcc), NULL) == MUTT_IMAP))
1645  {
1646  mutt_error(
1647  _("Warning: Fcc to an IMAP mailbox is not supported in batch mode"));
1648  /* L10N: Printed after the "Fcc to an IMAP mailbox is not supported" message.
1649  To make it clearer that the message doesn't mean NeoMutt is aborting
1650  sending the mail too.
1651  %s is the full mailbox URL, including imap(s)://
1652  */
1653  mutt_error(_("Skipping Fcc to %s"), mutt_buffer_string(fcc));
1654  mutt_buffer_reset(fcc);
1655  return rc;
1656  }
1657 #endif
1658 
1659  if (mutt_buffer_is_empty(fcc) || mutt_str_equal("/dev/null", mutt_buffer_string(fcc)))
1660  return rc;
1661 
1662  struct Body *tmpbody = e->body;
1663  struct Body *save_sig = NULL;
1664  struct Body *save_parts = NULL;
1665 
1666  const bool c_fcc_before_send = cs_subset_bool(sub, "fcc_before_send");
1667  /* Before sending, we don't allow message manipulation because it
1668  * will break message signatures. This is especially complicated by
1669  * Protected Headers. */
1670  if (!c_fcc_before_send)
1671  {
1672  const bool c_fcc_clear = cs_subset_bool(sub, "fcc_clear");
1673  if ((WithCrypto != 0) &&
1674  (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) && c_fcc_clear)
1675  {
1676  e->body = clear_content;
1679  }
1680 
1681  const enum QuadOption c_fcc_attach = cs_subset_quad(sub, "fcc_attach");
1682 
1683  /* check to see if the user wants copies of all attachments */
1684  bool save_atts = true;
1685  if (e->body->type == TYPE_MULTIPART)
1686  {
1687  /* In batch mode, save attachments if the quadoption is yes or ask-yes */
1688  if (flags & SEND_BATCH)
1689  {
1690  if ((c_fcc_attach == MUTT_NO) || (c_fcc_attach == MUTT_ASKNO))
1691  save_atts = false;
1692  }
1693  else if (query_quadoption(c_fcc_attach, _("Save attachments in Fcc?")) != MUTT_YES)
1694  save_atts = false;
1695  }
1696  if (!save_atts)
1697  {
1698  if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) &&
1699  (mutt_str_equal(e->body->subtype, "encrypted") ||
1700  mutt_str_equal(e->body->subtype, "signed")))
1701  {
1702  if ((clear_content->type == TYPE_MULTIPART) &&
1703  (query_quadoption(c_fcc_attach, _("Save attachments in Fcc?")) == MUTT_NO))
1704  {
1705  if (!(e->security & SEC_ENCRYPT) && (e->security & SEC_SIGN))
1706  {
1707  /* save initial signature and attachments */
1708  save_sig = e->body->parts->next;
1709  save_parts = clear_content->parts->next;
1710  }
1711 
1712  /* this means writing only the main part */
1713  e->body = clear_content->parts;
1714 
1715  if (mutt_protect(e, pgpkeylist, false) == -1)
1716  {
1717  /* we can't do much about it at this point, so
1718  * fallback to saving the whole thing to fcc */
1719  e->body = tmpbody;
1720  save_sig = NULL;
1721  goto full_fcc;
1722  }
1723 
1724  save_content = e->body;
1725  }
1726  }
1727  else
1728  {
1729  if (query_quadoption(c_fcc_attach, _("Save attachments in Fcc?")) == MUTT_NO)
1730  e->body = e->body->parts;
1731  }
1732  }
1733  }
1734 
1735 full_fcc:
1736  if (e->body)
1737  {
1738  /* update received time so that when storing to a mbox-style folder
1739  * the From_ line contains the current time instead of when the
1740  * message was first postponed. */
1741  e->received = mutt_date_epoch();
1742  rc = mutt_write_multiple_fcc(mutt_buffer_string(fcc), e, NULL, false, NULL,
1743  finalpath, sub);
1744  while (rc && !(flags & SEND_BATCH))
1745  {
1746  mutt_clear_error();
1747  int choice = mutt_multi_choice(
1748  /* L10N: Called when saving to $record or Fcc failed after sending.
1749  (r)etry tries the same mailbox again.
1750  alternate (m)ailbox prompts for a different mailbox to try.
1751  (s)kip aborts saving. */
1752  _("Fcc failed. (r)etry, alternate (m)ailbox, or (s)kip?"),
1753  /* L10N: These correspond to the "Fcc failed" multi-choice prompt
1754  (r)etry, alternate (m)ailbox, or (s)kip.
1755  Any similarity to famous leaders of the FSF is coincidental. */
1756  _("rms"));
1757  switch (choice)
1758  {
1759  case 2: /* alternate (m)ailbox */
1760  /* L10N: This is the prompt to enter an "alternate (m)ailbox" when the
1761  initial Fcc fails. */
1762  rc = mutt_buffer_enter_fname(_("Fcc mailbox"), fcc, true);
1763  if ((rc == -1) || mutt_buffer_is_empty(fcc))
1764  {
1765  rc = 0;
1766  break;
1767  }
1768  /* fall through */
1769 
1770  case 1: /* (r)etry */
1771  rc = mutt_write_multiple_fcc(mutt_buffer_string(fcc), e, NULL, false,
1772  NULL, finalpath, sub);
1773  break;
1774 
1775  case -1: /* abort */
1776  case 3: /* (s)kip */
1777  rc = 0;
1778  break;
1779  }
1780  }
1781  }
1782 
1783  if (!c_fcc_before_send)
1784  {
1785  e->body = tmpbody;
1786 
1787  if ((WithCrypto != 0) && save_sig)
1788  {
1789  /* cleanup the second signature structures */
1790  if (save_content->parts)
1791  {
1792  mutt_body_free(&save_content->parts->next);
1793  save_content->parts = NULL;
1794  }
1795  mutt_body_free(&save_content);
1796 
1797  /* restore old signature and attachments */
1798  e->body->parts->next = save_sig;
1799  e->body->parts->parts->next = save_parts;
1800  }
1801  else if ((WithCrypto != 0) && save_content)
1802  {
1803  /* destroy the new encrypted body. */
1804  mutt_body_free(&save_content);
1805  }
1806  }
1807 
1808  return 0;
1809 }
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:871
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:416
Ask the user, defaulting to &#39;No&#39;.
Definition: quad.h:41
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:69
#define WithCrypto
Definition: lib.h:123
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe()
Definition: imap.c:2367
struct Body * body
List of MIME parts.
Definition: email.h:91
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
#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:94
The body of an email.
Definition: body.h:34
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
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:1460
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:933
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
int mutt_protect(struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
Definition: crypt.c:159
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
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:154
unsigned int type
content-type primary type, ContentType
Definition: body.h:65
#define SEC_SIGN
Email is signed.
Definition: lib.h:86
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:323
#define mutt_error(...)
Definition: logging.h:84
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
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
#define mutt_buffer_enter_fname(prompt, fname, mailbox)
Definition: curs_lib.h:88
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:46
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
+ 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 1821 of file send.c.

1823 {
1824  char *pgpkeylist = NULL;
1825  const char *encrypt_as = NULL;
1826  struct Body *clear_content = NULL;
1827 
1828  const char *c_postponed = cs_subset_string(sub, "postponed");
1829  if (!c_postponed)
1830  {
1831  mutt_error(_("Can't postpone. $postponed is unset"));
1832  return -1;
1833  }
1834 
1835  if (e_post->body->next)
1836  e_post->body = mutt_make_multipart(e_post->body);
1837 
1838  mutt_encode_descriptions(e_post->body, true, sub);
1839 
1840  const bool c_postpone_encrypt = cs_subset_bool(sub, "postpone_encrypt");
1841  if ((WithCrypto != 0) && c_postpone_encrypt &&
1842  (e_post->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
1843  {
1844  if (((WithCrypto & APPLICATION_PGP) != 0) && (e_post->security & APPLICATION_PGP))
1845  {
1846  const char *c_pgp_default_key = cs_subset_string(sub, "pgp_default_key");
1847  encrypt_as = c_pgp_default_key;
1848  }
1849  else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e_post->security & APPLICATION_SMIME))
1850  {
1851  const char *c_smime_default_key =
1852  cs_subset_string(sub, "smime_default_key");
1853  encrypt_as = c_smime_default_key;
1854  }
1855  if (!encrypt_as)
1856  {
1857  const char *c_postpone_encrypt_as =
1858  cs_subset_string(sub, "postpone_encrypt_as");
1859  encrypt_as = c_postpone_encrypt_as;
1860  }
1861 
1862 #ifdef USE_AUTOCRYPT
1863  if (e_post->security & SEC_AUTOCRYPT)
1864  {
1866  {
1867  e_post->body = mutt_remove_multipart(e_post->body);
1868  decode_descriptions(e_post->body);
1869  mutt_error(_("Error encrypting message. Check your crypt settings."));
1870  return -1;
1871  }
1872  encrypt_as = AutocryptDefaultKey;
1873  }
1874 #endif
1875 
1876  if (encrypt_as)
1877  {
1878  pgpkeylist = mutt_str_dup(encrypt_as);
1879  clear_content = e_post->body;
1880  if (mutt_protect(e_post, pgpkeylist, true) == -1)
1881  {
1882  FREE(&pgpkeylist);
1883  e_post->body = mutt_remove_multipart(e_post->body);
1884  decode_descriptions(e_post->body);
1885  mutt_error(_("Error encrypting message. Check your crypt settings."));
1886  return -1;
1887  }
1888 
1889  FREE(&pgpkeylist);
1890 
1891  mutt_encode_descriptions(e_post->body, false, sub);
1892  }
1893  }
1894 
1895  /* make sure the message is written to the right part of a maildir
1896  * postponed folder. */
1897  e_post->read = false;
1898  e_post->old = false;
1899 
1900  mutt_prepare_envelope(e_post->env, false, sub);
1901  mutt_env_to_intl(e_post->env, NULL, NULL); /* Handle bad IDNAs the next time. */
1902 
1903  if (mutt_write_fcc(NONULL(c_postponed), e_post,
1904  (e_cur && (flags & SEND_REPLY)) ? e_cur->env->message_id : NULL,
1905  true, fcc, NULL, sub) < 0)
1906  {
1907  if (clear_content)
1908  {
1909  mutt_body_free(&e_post->body);
1910  e_post->body = clear_content;
1911  }
1912  mutt_env_free(&e_post->body->mime_headers); /* protected headers */
1913  e_post->body = mutt_remove_multipart(e_post->body);
1914  decode_descriptions(e_post->body);
1915  mutt_unprepare_envelope(e_post->env);
1916  return -1;
1917  }
1918 
1920 
1921  if (clear_content)
1922  mutt_body_free(&clear_content);
1923 
1924  return 0;
1925 }
#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:69
#define WithCrypto
Definition: lib.h:123
struct Body * body
List of MIME parts.
Definition: email.h:91
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
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:1508
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:94
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 * AutocryptDefaultKey
Autocrypt default key id (used for postponing messages)
Definition: config.c:43
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:1238
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:1469
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 Email *e)
Set the Autocrypt default key for signing.
Definition: autocrypt.c:688
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:98
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:1277
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:97
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
int mutt_protect(struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
Definition: crypt.c:159
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
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:203
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:41
#define mutt_error(...)
Definition: logging.h:84
#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:1451
+ 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
trueif it's text/plain
falseif it's not

Definition at line 1933 of file send.c.

1934 {
1935  return (b->type == TYPE_TEXT) && mutt_istr_equal(b->subtype, "plain");
1936 }
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
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 1944 of file send.c.

1945 {
1946  const enum QuadOption c_abort_noattach =
1947  cs_subset_quad(sub, "abort_noattach");
1948 
1949  if (c_abort_noattach == MUTT_NO)
1950  return false;
1951 
1952  if (b->next)
1953  return false;
1954 
1955  bool has_keyword = false;
1956 
1957  /* search text/plain parts, whether they are main or alternative parts */
1958  if (is_text_plain(b))
1959  {
1960  has_keyword |= search_attach_keyword(b->filename, sub);
1961  }
1962  else
1963  {
1964  for (b = b->parts; b; b = b->next)
1965  {
1966  if (is_text_plain(b))
1967  {
1968  has_keyword |= search_attach_keyword(b->filename, sub);
1969  }
1970  }
1971  }
1972 
1973  if (!has_keyword)
1974  return false;
1975 
1976  if (c_abort_noattach == MUTT_YES)
1977  {
1978  mutt_error(_("Message contains text matching \"$abort_noattach_regex\". "
1979  "Not sending."));
1980  return true;
1981  }
1982 
1983  return query_quadoption(c_abort_noattach,
1984  _("No attachments, cancel sending?")) != MUTT_NO;
1985 }
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
#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:36
static bool is_text_plain(const struct Body *b)
is a Body a text/plain MIME part?
Definition: send.c:1933
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:154
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
#define mutt_error(...)
Definition: logging.h:84
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
static bool search_attach_keyword(char *filename, struct ConfigSubset *sub)
Search an email for &#39;attachment&#39; keywords.
Definition: send.c:1579
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
+ 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 Context ctx,
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
ctxCurrent 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 1999 of file send.c.

2001 {
2002  char buf[1024];
2003  struct Buffer fcc = mutt_buffer_make(0); /* where to copy this message */
2004  FILE *fp_tmp = NULL;
2005  struct Body *pbody = NULL;
2006  int i;
2007  bool free_clear_content = false;
2008 
2009  struct Body *clear_content = NULL;
2010  char *pgpkeylist = NULL;
2011  /* save current value of "pgp_sign_as" and "smime_default_key" */
2012  char *pgp_sign_as = NULL;
2013  char *smime_sign_as = NULL;
2014  const char *tag = NULL;
2015  char *err = NULL;
2016  char *ctype = NULL;
2017  char *finalpath = NULL;
2018  struct EmailNode *en = NULL;
2019  struct Email *e_cur = NULL;
2020  struct Mailbox *mailbox = ctx ? ctx->mailbox : NULL;
2021 
2022  if (el)
2023  en = STAILQ_FIRST(el);
2024  if (en)
2025  e_cur = STAILQ_NEXT(en, entries) ? NULL : en->email;
2026 
2027  int rc = -1;
2028 
2029 #ifdef USE_NNTP
2030  if (flags & SEND_NEWS)
2031  OptNewsSend = true;
2032  else
2033  OptNewsSend = false;
2034 #endif
2035 
2036  const enum QuadOption c_recall = cs_subset_quad(sub, "recall");
2037 
2038  if (!flags && !e_templ && (c_recall != MUTT_NO) && mutt_num_postponed(mailbox, true))
2039  {
2040  /* If the user is composing a new message, check to see if there
2041  * are any postponed messages first. */
2042  enum QuadOption ans =
2043  query_quadoption(c_recall, _("Recall postponed message?"));
2044  if (ans == MUTT_ABORT)
2045  return rc;
2046 
2047  if (ans == MUTT_YES)
2048  flags |= SEND_POSTPONED;
2049  }
2050 
2051  /* Allocate the buffer due to the long lifetime, but
2052  * pre-resize it to ensure there are no NULL data field issues */
2053  mutt_buffer_alloc(&fcc, 1024);
2054 
2055  if (flags & SEND_POSTPONED)
2056  {
2058  {
2059  const char *c_pgp_sign_as = cs_subset_string(sub, "pgp_sign_as");
2060  pgp_sign_as = mutt_str_dup(c_pgp_sign_as);
2061  }
2063  {
2064  const char *c_smime_sign_as = cs_subset_string(sub, "smime_sign_as");
2065  smime_sign_as = mutt_str_dup(c_smime_sign_as);
2066  }
2067  }
2068 
2069  /* Delay expansion of aliases until absolutely necessary--shouldn't
2070  * be necessary unless we are prompting the user or about to execute a
2071  * send-hook. */
2072 
2073  if (!e_templ)
2074  {
2075  e_templ = email_new();
2076 
2077  if (flags == SEND_POSTPONED)
2078  {
2079  rc = mutt_get_postponed(ctx, e_templ, &e_cur, &fcc);
2080  if (rc < 0)
2081  {
2083  goto cleanup;
2084  }
2085  flags = rc;
2086 #ifdef USE_NNTP
2087  /* If postponed message is a news article, it have
2088  * a "Newsgroups:" header line, then set appropriate flag. */
2089  if (e_templ->env->newsgroups)
2090  {
2091  flags |= SEND_NEWS;
2092  OptNewsSend = true;
2093  }
2094  else
2095  {
2096  flags &= ~SEND_NEWS;
2097  OptNewsSend = false;
2098  }
2099 #endif
2100  }
2101 
2102  if (flags & (SEND_POSTPONED | SEND_RESEND))
2103  {
2104  fp_tmp = mutt_file_fopen(e_templ->body->filename, "a+");
2105  if (!fp_tmp)
2106  {
2107  mutt_perror(e_templ->body->filename);
2108  goto cleanup;
2109  }
2110  }
2111 
2112  if (!e_templ->env)
2113  e_templ->env = mutt_env_new();
2114  }
2115 
2116  /* Parse and use an eventual list-post header */
2117  if ((flags & SEND_LIST_REPLY) && e_cur && e_cur->env && e_cur->env->list_post)
2118  {
2119  /* Use any list-post header as a template */
2120  mutt_parse_mailto(e_templ->env, NULL, e_cur->env->list_post);
2121  /* We don't let them set the sender's address. */
2122  mutt_addrlist_clear(&e_templ->env->from);
2123  }
2124 
2125  if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND)))
2126  {
2127  /* When SEND_DRAFT_FILE is set, the caller has already
2128  * created the "parent" body structure. */
2129  if (!(flags & SEND_DRAFT_FILE))
2130  {
2131  pbody = mutt_body_new();
2132  pbody->next = e_templ->body; /* don't kill command-line attachments */
2133  e_templ->body = pbody;
2134 
2135  const char *c_content_type = cs_subset_string(sub, "content_type");
2136  ctype = mutt_str_dup(c_content_type);
2137  if (!ctype)
2138  ctype = mutt_str_dup("text/plain");
2139  mutt_parse_content_type(ctype, e_templ->body);
2140  FREE(&ctype);
2141  e_templ->body->unlink = true;
2142  e_templ->body->use_disp = false;
2143  e_templ->body->disposition = DISP_INLINE;
2144 
2145  if (tempfile)
2146  {
2147  fp_tmp = mutt_file_fopen(tempfile, "a+");
2148  e_templ->body->filename = mutt_str_dup(tempfile);
2149  }
2150  else
2151  {
2152  mutt_mktemp(buf, sizeof(buf));
2153  fp_tmp = mutt_file_fopen(buf, "w+");
2154  e_templ->body->filename = mutt_str_dup(buf);
2155  }
2156  }
2157  else
2158  fp_tmp = mutt_file_fopen(e_templ->body->filename, "a+");
2159 
2160  if (!fp_tmp)
2161  {
2162  mutt_debug(LL_DEBUG1, "can't create tempfile %s (errno=%d)\n",
2163  e_templ->body->filename, errno);
2164  mutt_perror(e_templ->body->filename);
2165  goto cleanup;
2166  }
2167  }
2168 
2169  const bool c_reverse_name = cs_subset_bool(sub, "reverse_name");
2170  /* this is handled here so that the user can match ~f in send-hook */
2171  if (e_cur && c_reverse_name && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2172  {
2173  /* We shouldn't have to worry about alias expansion here since we are
2174  * either replying to a real or postponed message, therefore no aliases
2175  * should exist since the user has not had the opportunity to add
2176  * addresses to the list. We just have to ensure the postponed messages
2177  * have their aliases expanded. */
2178 
2179  if (!TAILQ_EMPTY(&e_templ->env->from))
2180  {
2181  mutt_debug(LL_DEBUG5, "e_templ->env->from before set_reverse_name: %s\n",
2182  TAILQ_FIRST(&e_templ->env->from)->mailbox);
2183  mutt_addrlist_clear(&e_templ->env->from);
2184  }
2185  set_reverse_name(&e_templ->env->from, e_cur->env, sub);
2186  }
2187 
2188  const bool c_reply_with_xorig = cs_subset_bool(sub, "reply_with_xorig");
2189  if (e_cur && c_reply_with_xorig && !(flags & (SEND_POSTPONED | SEND_RESEND | SEND_FORWARD)))
2190  {
2191  /* We shouldn't have to worry about freeing 'e_templ->env->from' before
2192  * setting it here since this code will only execute when doing some
2193  * sort of reply. The pointer will only be set when using the -H command
2194  * line option.
2195  *
2196  * If there is already a from address recorded in 'e_templ->env->from',
2197  * then it theoretically comes from `$reverse_name` handling, and we don't use
2198  * the 'X-Orig-To header'. */
2199  if (!TAILQ_EMPTY(&e_cur->env->x_original_to) && TAILQ_EMPTY(&e_templ->env->from))
2200  {
2201  mutt_addrlist_copy(&e_templ->env->from, &e_cur->env->x_original_to, false);
2202  mutt_debug(LL_DEBUG5, "e_templ->env->from extracted from X-Original-To: header: %s\n",
2203  TAILQ_FIRST(&e_templ->env->from)->mailbox);
2204  }
2205  }
2206 
2207  const bool c_resume_draft_files = cs_subset_bool(sub, "resume_draft_files");
2208  if (!(flags & (SEND_POSTPONED | SEND_RESEND)) &&
2209  !((flags & SEND_DRAFT_FILE) && c_resume_draft_files))
2210  {
2211  if ((flags & (SEND_REPLY | SEND_FORWARD | SEND_TO_SENDER)) && mailbox &&
2212  (envelope_defaults(e_templ->env, mailbox, el, flags, sub) == -1))
2213  {
2214  goto cleanup;
2215  }
2216 
2217  const bool c_hdrs = cs_subset_bool(sub, "hdrs");
2218  if (c_hdrs)
2219  process_user_recips(e_templ->env);
2220 
2221  /* Expand aliases and remove duplicates/crossrefs */
2222  mutt_expand_aliases_env(e_templ->env);
2223 
2224  if (flags & SEND_REPLY)
2225  mutt_fix_reply_recipients(e_templ->env, sub);
2226 
2227 #ifdef USE_NNTP
2228  if ((flags & SEND_NEWS) && (mailbox && mailbox->type == MUTT_NNTP) &&
2229  !e_templ->env->newsgroups)
2230  {
2231  e_templ->env->newsgroups =
2232  mutt_str_dup(((struct NntpMboxData *) mailbox->mdata)->group);
2233  }
2234 #endif
2235 
2236  const bool c_autoedit = cs_subset_bool(sub, "autoedit");
2237  const bool c_edit_headers = cs_subset_bool(sub, "edit_headers");
2238  const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
2239  if (!(flags & SEND_BATCH) && !(c_autoedit && c_edit_headers) &&
2240  !((flags & SEND_REPLY) && c_fast_reply))
2241  {
2242  if (edit_envelope(e_templ->env, flags, sub) == -1)
2243  goto cleanup;
2244  }
2245 
2246  /* the from address must be set here regardless of whether or not
2247  * $use_from is set so that the '~P' (from you) operator in send-hook
2248  * patterns will work. if $use_from is unset, the from address is killed
2249  * after send-hooks are evaluated */
2250 
2251  const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2252  if (killfrom)
2253  {
2254  mutt_addrlist_append(&e_templ->env->from, mutt_default_from(sub));
2255  }
2256 
2257  if ((flags & SEND_REPLY) && e_cur)
2258  {
2259  /* change setting based upon message we are replying to */
2260  mutt_message_hook(mailbox, e_cur, MUTT_REPLY_HOOK);
2261 
2262  /* set the replied flag for the message we are generating so that the
2263  * user can use ~Q in a send-hook to know when reply-hook's are also
2264  * being used. */
2265  e_templ->replied = true;
2266  }
2267 
2268  /* change settings based upon recipients */
2269 
2270  mutt_message_hook(NULL, e_templ, MUTT_SEND_HOOK);
2271 
2272  /* Unset the replied flag from the message we are composing since it is
2273  * no longer required. This is done here because the FCC'd copy of
2274  * this message was erroneously get the 'R'eplied flag when stored in
2275  * a maildir-style mailbox. */
2276  e_templ->replied = false;
2277 
2278  /* $use_from and/or $from might have changed in a send-hook */
2279  if (killfrom)
2280  {
2281  mutt_addrlist_clear(&e_templ->env->from);
2282 
2283  const bool c_use_from = cs_subset_bool(sub, "use_from");
2284  if (c_use_from && !(flags & (SEND_POSTPONED | SEND_RESEND)))
2285  mutt_addrlist_append(&e_templ->env->from, mutt_default_from(sub));
2286  }
2287 
2288  if (c_hdrs)
2289  process_user_header(e_templ->env);
2290 
2291  if (flags & SEND_BATCH)
2292  {
2293  if (mutt_file_copy_stream(stdin, fp_tmp) < 1)
2294  {
2295  mutt_error(_("Refusing to send an empty email"));
2296  mutt_message(_("Try: echo | neomutt -s 'subject' user@example.com"));
2297  goto cleanup;
2298  }
2299  }
2300 
2301  const bool c_sig_on_top = cs_subset_bool(sub, "sig_on_top");
2302  const char *c_editor = cs_subset_string(sub, "editor");
2303  if (c_sig_on_top && !(flags & (SEND_KEY | SEND_BATCH)) && c_editor)
2304  {
2305  append_signature(fp_tmp, sub);
2306  }
2307 
2308  /* include replies/forwarded messages, unless we are given a template */
2309  if (!tempfile && (mailbox || !(flags & (SEND_REPLY | SEND_FORWARD))) &&
2310  (generate_body(fp_tmp, e_templ, flags, mailbox, el, sub) == -1))
2311  {
2312  goto cleanup;
2313  }
2314 
2315  if (!c_sig_on_top && !(flags & (SEND_KEY | SEND_BATCH)) && c_editor)
2316  {
2317  append_signature(fp_tmp, sub);
2318  }
2319  }
2320 
2321  /* Only set format=flowed for new messages. postponed/resent/draftfiles
2322  * should respect the original email.
2323  *
2324  * This is set here so that send-hook can be used to turn the option on. */
2325  if (!(flags & (SEND_KEY | SEND_POSTPONED | SEND_RESEND | SEND_DRAFT_FILE)))
2326  {
2327  const bool c_text_flowed = cs_subset_bool(sub, "text_flowed");
2328  if (c_text_flowed && is_text_plain(e_templ->body))
2329  {
2330  mutt_param_set(&e_templ->body->parameter, "format", "flowed");
2331  }
2332  }
2333 
2334  /* This hook is even called for postponed messages, and can, e.g., be used
2335  * for setting the editor, the sendmail path, or the envelope sender. */
2336  mutt_message_hook(NULL, e_templ, MUTT_SEND2_HOOK);
2337 
2338  /* wait until now to set the real name portion of our return address so
2339  * that $realname can be set in a send-hook */
2340  {
2341  struct Address *from = TAILQ_FIRST(&e_templ->env->from);
2342  if (from && !from->personal && !(flags & (SEND_RESEND | SEND_POSTPONED)))
2343  {
2344  const char *c_realname = cs_subset_string(sub, "realname");
2345  from->personal = mutt_str_dup(c_realname);
2346  }
2347  }
2348 
2349  if (!(((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY)))
2350  mutt_file_fclose(&fp_tmp);
2351 
2352  if (!(flags & SEND_BATCH))
2353  {
2354  struct stat st;
2355  time_t mtime = mutt_file_decrease_mtime(e_templ->body->filename, NULL);
2356  if (mtime == (time_t) -1)
2357  {
2358  mutt_perror(e_templ->body->filename);
2359  goto cleanup;
2360  }
2361 
2362  mutt_update_encoding(e_templ->body, sub);
2363 
2364  const bool c_edit_headers = cs_subset_bool(sub, "edit_headers");
2365  const bool c_autoedit = cs_subset_bool(sub, "autoedit");
2366  const enum QuadOption c_forward_edit = cs_subset_quad(sub, "forward_edit");
2367 
2368  /* Select whether or not the user's editor should be called now. We
2369  * don't want to do this when:
2370  * 1) we are sending a key/cert
2371  * 2) we are forwarding a message and the user doesn't want to edit it.
2372  * This is controlled by the quadoption $forward_edit. However, if
2373  * both $edit_headers and $autoedit are set, we want to ignore the
2374  * setting of $forward_edit because the user probably needs to add the
2375  * recipients. */
2376  if (!(flags & SEND_KEY) &&
2377  (((flags & SEND_FORWARD) == 0) || (c_edit_headers && c_autoedit) ||
2378  (query_quadoption(c_forward_edit, _("Edit forwarded message?")) == MUTT_YES)))
2379  {
2380  /* If the this isn't a text message, look for a mailcap edit command */
2381  const char *c_editor = cs_subset_string(sub, "editor");
2382  if (mutt_needs_mailcap(e_templ->body))
2383  {
2384  if (!mutt_edit_attachment(e_templ->body))
2385  goto cleanup;
2386  }
2387  else if (c_edit_headers)
2388  {
2389  mutt_env_to_local(e_templ->env);
2390  mutt_edit_headers(c_editor, e_templ->body->filename, e_templ, &fcc);
2391  mutt_env_to_intl(e_templ->env, NULL, NULL);
2392  }
2393  else
2394  {
2395  mutt_edit_file(c_editor, e_templ->body->filename);
2396  if (stat(e_templ->body->filename, &st) == 0)
2397  {
2398  if (mtime != st.st_mtime)
2399  fix_end_of_file(e_templ->body->filename);
2400  }
2401  else
2402  mutt_perror(e_templ->body->filename);
2403  }
2404 
2405  mutt_message_hook(NULL, e_templ, MUTT_SEND2_HOOK);
2406  }
2407 
2408  if (!(flags & (SEND_POSTPONED | SEND_FORWARD | SEND_KEY | SEND_RESEND | SEND_DRAFT_FILE)))
2409  {
2410  if (stat(e_templ->body->filename, &st) == 0)
2411  {
2412  const enum QuadOption c_abort_unmodified =
2413  cs_subset_quad(sub, "abort_unmodified");
2414 
2415  /* if the file was not modified, bail out now */
2416  if ((mtime == st.st_mtime) && !e_templ->body->next &&
2417  (query_quadoption(c_abort_unmodified,
2418  _("Abort unmodified message?")) == MUTT_YES))
2419  {
2420  mutt_message(_("Aborted unmodified message"));
2421  goto cleanup;
2422  }
2423  }
2424  else
2425  mutt_perror(e_templ->body->filename);
2426  }
2427  }
2428 
2429  /* Set the message security unless:
2430  * 1) crypto support is not enabled (WithCrypto==0)
2431  * 2) pgp: header field was present during message editing with $edit_headers (e_templ->security != 0)
2432  * 3) we are resending a message
2433  * 4) we are recalling a postponed message (don't override the user's saved settings)
2434  * 5) we are in batch mode
2435  *
2436  * This is done after allowing the user to edit the message so that security
2437  * settings can be configured with send2-hook and $edit_headers. */
2438  if ((WithCrypto != 0) && (e_templ->security == 0) &&
2439  !(flags & (SEND_BATCH | SEND_POSTPONED | SEND_RESEND)))
2440  {
2441  bool c_autocrypt = false;
2442  bool c_autocrypt_reply = false;
2443 
2444 #ifdef USE_AUTOCRYPT
2445  c_autocrypt = cs_subset_bool(sub, "autocrypt");
2446  c_autocrypt_reply = cs_subset_bool(sub, "autocrypt_reply");
2447 #endif
2448 
2449  if (c_autocrypt && c_autocrypt_reply && e_cur && (e_cur->security & SEC_AUTOCRYPT))
2450  {
2452  }
2453  else
2454  {
2455  const bool c_crypt_autosign = cs_subset_bool(sub, "crypt_autosign");
2456  const bool c_crypt_autoencrypt = cs_subset_bool(sub, "crypt_autoencrypt");
2457  const bool c_crypt_replyencrypt =
2458  cs_subset_bool(sub, "crypt_replyencrypt");
2459  const bool c_crypt_replysign = cs_subset_bool(sub, "crypt_replysign");
2460  const bool c_crypt_replysignencrypted =
2461  cs_subset_bool(sub, "crypt_replysignencrypted");
2462 
2463  if (c_crypt_autosign)
2464  e_templ->security |= SEC_SIGN;
2465  if (c_crypt_autoencrypt)
2466  e_templ->security |= SEC_ENCRYPT;
2467  if (c_crypt_replyencrypt && e_cur && (e_cur->security & SEC_ENCRYPT))
2468  e_templ->security |= SEC_ENCRYPT;
2469  if (c_crypt_replysign && e_cur && (e_cur->security & SEC_SIGN))
2470  e_templ->security |= SEC_SIGN;
2471  if (c_crypt_replysignencrypted && e_cur && (e_cur->security & SEC_ENCRYPT))
2472  e_templ->security |= SEC_SIGN;
2473 
2474  const bool c_crypt_opportunistic_encrypt =
2475  cs_subset_bool(sub, "crypt_opportunistic_encrypt");
2476 
2477  if (((WithCrypto & APPLICATION_PGP) != 0) &&
2478  ((e_templ->security & (SEC_ENCRYPT | SEC_SIGN)) || c_crypt_opportunistic_encrypt))
2479  {
2480  const bool c_pgp_autoinline = cs_subset_bool(sub, "pgp_autoinline");
2481  const bool c_pgp_replyinline = cs_subset_bool(sub, "pgp_replyinline");
2482 
2483  if (c_pgp_autoinline)
2484  e_templ->security |= SEC_INLINE;
2485  if (c_pgp_replyinline && e_cur && (e_cur->security & SEC_INLINE))
2486  e_templ->security |= SEC_INLINE;
2487  }
2488  }
2489 
2490  const bool c_crypt_opportunistic_encrypt =
2491  cs_subset_bool(sub, "crypt_opportunistic_encrypt");
2492 
2493  if (e_templ->security || c_crypt_opportunistic_encrypt)
2494  {
2495  const bool c_crypt_autopgp = cs_subset_bool(sub, "crypt_autopgp");
2496  const bool c_crypt_autosmime = cs_subset_bool(sub, "crypt_autosmime");
2497 
2498  /* When replying / forwarding, use the original message's
2499  * crypto system. According to the documentation,
2500  * smime_is_default should be disregarded here.
2501  *
2502  * Problem: At least with forwarding, this doesn't really
2503  * make much sense. Should we have an option to completely
2504  * disable individual mechanisms at run-time? */
2505  if (e_cur)
2506  {
2507  if (((WithCrypto & APPLICATION_PGP) != 0) && c_crypt_autopgp &&
2508  (e_cur->security & APPLICATION_PGP))
2509  {
2510  e_templ->security |= APPLICATION_PGP;
2511  }
2512  else if (((WithCrypto & APPLICATION_SMIME) != 0) && c_crypt_autosmime &&
2513  (e_cur->security & APPLICATION_SMIME))
2514  {
2515  e_templ->security |= APPLICATION_SMIME;
2516  }
2517  }
2518 
2519  const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
2520 
2521  /* No crypto mechanism selected? Use availability + smime_is_default
2522  * for the decision. */
2523  if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2524  {
2525  if (((WithCrypto & APPLICATION_SMIME) != 0) && c_crypt_autosmime && c_smime_is_default)
2526  {
2527  e_templ->security |= APPLICATION_SMIME;
2528  }
2529  else if (((WithCrypto & APPLICATION_PGP) != 0) && c_crypt_autopgp)
2530  {
2531  e_templ->security |= APPLICATION_PGP;
2532  }
2533  else if (((WithCrypto & APPLICATION_SMIME) != 0) && c_crypt_autosmime)
2534  {
2535  e_templ->security |= APPLICATION_SMIME;
2536  }
2537  }
2538  }
2539 
2540  /* opportunistic encrypt relies on SMIME or PGP already being selected */
2541  if (c_crypt_opportunistic_encrypt)
2542  {
2543  /* If something has already enabled encryption, e.g. `$crypt_autoencrypt`
2544  * or `$crypt_replyencrypt`, then don't enable opportunistic encrypt for
2545  * the message. */
2546  if (!(e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
2547  {
2548  e_templ->security |= SEC_OPPENCRYPT;
2549  crypt_opportunistic_encrypt(e_templ);
2550  }
2551  }
2552 
2553  /* No permissible mechanisms found. Don't sign or encrypt. */
2554  if (!(e_templ->security & (APPLICATION_SMIME | APPLICATION_PGP)))
2555  e_templ->security = SEC_NO_FLAGS;
2556  }
2557 
2558  /* Deal with the corner case where the crypto module backend is not available.
2559  * This can happen if configured without PGP/SMIME and with GPGME, but
2560  * $crypt_use_gpgme is unset. */
2561  if (e_templ->security && !crypt_has_module_backend(e_templ->security))
2562  {
2563  mutt_error(_(
2564  "No crypto backend configured. Disabling message security setting."));
2565  e_templ->security = SEC_NO_FLAGS;
2566  }
2567 
2568  /* specify a default fcc. if we are in batchmode, only save a copy of
2569  * the message if the value of $copy is yes or ask-yes */
2570 
2571  const enum QuadOption c_copy = cs_subset_quad(sub, "copy");
2572 
2573  if (mutt_buffer_is_empty(&fcc) && !(flags & SEND_POSTPONED_FCC) &&
2574  (!(flags & SEND_BATCH) || (c_copy & 0x1)))
2575  {
2576  /* set the default FCC */
2577  const bool killfrom = TAILQ_EMPTY(&e_templ->env->from);
2578  if (killfrom)
2579  {
2580  mutt_addrlist_append(&e_templ->env->from, mutt_default_from(sub));
2581  }
2582  mutt_select_fcc(&fcc, e_templ);
2583  if (killfrom)
2584  {
2585  mutt_addrlist_clear(&e_templ->env->from);
2586  }
2587  }
2588 
2589  mutt_rfc3676_space_stuff(e_templ);
2590 
2591  mutt_update_encoding(e_templ->body, sub);
2592 
2593  if (!(flags & SEND_BATCH))
2594  {
2595  main_loop:
2596 
2598  i = mutt_compose_menu(
2599  e_templ, &fcc, e_cur,
2600  ((flags & SEND_NO_FREE_HEADER) ? MUTT_COMPOSE_NOFREEHEADER : 0), sub);
2601  if (i == -1)
2602  {
2603 /* abort */
2604 #ifdef USE_NNTP
2605  if (flags & SEND_NEWS)
2606  mutt_message(_("Article not posted"));
2607  else
2608 #endif
2609  mutt_message(_("Mail not sent"));
2610  goto cleanup;
2611  }
2612  else if (i == 1)
2613  {
2614  if (postpone_message(e_templ, e_cur, mutt_buffer_string(&fcc), flags, sub) != 0)
2615  goto main_loop;
2616  mutt_message(_("Message postponed"));
2617  rc = 1;
2618  goto cleanup;
2619  }
2620  }
2621 
2622 #ifdef USE_NNTP
2623  if (!(flags & SEND_NEWS))
2624 #endif
2625  if ((mutt_addrlist_count_recips(&e_templ->env->to) == 0) &&
2626  (mutt_addrlist_count_recips(&e_templ->env->cc) == 0) &&
2627  (mutt_addrlist_count_recips(&e_templ->env->bcc) == 0))
2628  {
2629  if (flags & SEND_BATCH)
2630  {
2631  puts(_("No recipients specified"));
2632  goto cleanup;
2633  }
2634 
2635  mutt_error(_("No recipients specified"));
2636  goto main_loop;
2637  }
2638 
2639  if (mutt_env_to_intl(e_templ->env, &tag, &err))
2640  {
2641  mutt_error(_("Bad IDN in '%s': '%s'"), tag, err);
2642  FREE(&err);
2643  if (flags & SEND_BATCH)
2644  goto cleanup;
2645  goto main_loop;
2646  }
2647 
2648  const enum QuadOption c_abort_nosubject =
2649  cs_subset_quad(sub, "abort_nosubject");
2650 
2651  if (!e_templ->env->subject && !(flags & SEND_BATCH) &&
2652  (query_quadoption(c_abort_nosubject, _("No subject, abort sending?")) != MUTT_NO))
2653  {
2654  /* if the abort is automatic, print an error message */
2655  if (c_abort_nosubject == MUTT_YES)
2656  mutt_error(_("No subject specified"));
2657  goto main_loop;
2658  }
2659 #ifdef USE_NNTP
2660  if ((flags & SEND_NEWS) && !e_templ->env->subject)
2661  {
2662  mutt_error(_("No subject specified"));
2663  goto main_loop;
2664  }
2665 
2666  if ((flags & SEND_NEWS) && !e_templ->env->newsgroups)
2667  {
2668  mutt_error(_("No newsgroup specified"));
2669  goto main_loop;
2670  }
2671 #endif
2672 
2673  if (!(flags & SEND_BATCH) && abort_for_missing_attachments(e_templ->body, sub))
2674  {
2675  goto main_loop;
2676  }
2677 
2678  if (e_templ->body->next)
2679  e_templ->body = mutt_make_multipart(e_templ->body);
2680 
2681  /* Ok, we need to do it this way instead of handling all fcc stuff in
2682  * one place in order to avoid going to main_loop with encoded "env"
2683  * in case of error. Ugh. */
2684 
2685  mutt_encode_descriptions(e_templ->body, true, sub);
2686 
2687  /* Make sure that clear_content and free_clear_content are
2688  * properly initialized -- we may visit this particular place in
2689  * the code multiple times, including after a failed call to
2690  * mutt_protect(). */
2691 
2692  clear_content = NULL;
2693  free_clear_content = false;
2694 
2695  if (WithCrypto)
2696  {
2697  if (e_templ->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT))
2698  {
2699  /* save the decrypted attachments */
2700  clear_content = e_templ->body;
2701 
2702  if ((crypt_get_keys(e_templ, &pgpkeylist, 0) == -1) ||
2703  (mutt_protect(e_templ, pgpkeylist, false) == -1))
2704  {
2705  e_templ->body = mutt_remove_multipart(e_templ->body);
2706 
2707  FREE(&pgpkeylist);
2708 
2709  decode_descriptions(e_templ->body);
2710  goto main_loop;
2711  }
2712  mutt_encode_descriptions(e_templ->body, false, sub);
2713  }
2714 
2715  /* at this point, e_templ->body is one of the following three things:
2716  * - multipart/signed. In this case, clear_content is a child
2717  * - multipart/encrypted. In this case, clear_content exists independently
2718  * - application/pgp. In this case, clear_content exists independently
2719  * - something else. In this case, it's the same as clear_content */
2720 
2721  /* This is ugly -- lack of "reporting back" from mutt_protect(). */
2722 
2723  if (clear_content && (e_templ->body != clear_content) &&
2724  (e_templ->body->parts != clear_content))
2725  free_clear_content = true;
2726  }
2727 
2728  if (!OptNoCurses)
2729  mutt_message(_("Sending message..."));
2730 
2731  mutt_prepare_envelope(e_templ->env, true, sub);
2732 
2733  const bool c_fcc_before_send = cs_subset_bool(sub, "fcc_before_send");
2734  if (c_fcc_before_send)
2735  save_fcc(e_templ, &fcc, clear_content, pgpkeylist, flags, &finalpath, sub);
2736 
2737  i = invoke_mta(e_templ, sub);
2738  if (i < 0)
2739  {
2740  if (!(flags & SEND_BATCH))
2741  {
2742  if (!WithCrypto)
2743  ; // do nothing
2744  else if ((e_templ->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)) ||
2745  ((e_templ->security & SEC_SIGN) && (e_templ->body->type == TYPE_APPLICATION)))
2746  {
2747  if (e_templ->body != clear_content)
2748  {
2749  mutt_body_free(&e_templ->body); /* destroy PGP data */
2750  e_templ->body = clear_content; /* restore clear text. */
2751  }
2752  }
2753  else if ((e_templ->security & SEC_SIGN) && (e_templ->body->type == TYPE_MULTIPART))
2754  {
2755  mutt_body_free(&e_templ->body->parts->next); /* destroy sig */
2756  e_templ->body = mutt_remove_multipart(e_templ->body);
2757  }
2758 
2759  FREE(&pgpkeylist);
2760  mutt_env_free(&e_templ->body->mime_headers); /* protected headers */
2761  e_templ->body = mutt_remove_multipart(e_templ->body);
2762  decode_descriptions(e_templ->body);
2763  mutt_unprepare_envelope(e_templ->env);
2764  FREE(&finalpath);
2765  goto main_loop;
2766  }
2767  else
2768  {
2769  puts(_("Could not send the message"));
2770  goto cleanup;
2771  }
2772  }
2773 
2774  if (!c_fcc_before_send)
2775  save_fcc(e_templ, &fcc, clear_content, pgpkeylist, flags, &finalpath, sub);
2776 
2777  if (!OptNoCurses)
2778  {
2779  mutt_message((i != 0) ? _("Sending in background") :
2780  (flags & SEND_NEWS) ? _("Article posted") : /* USE_NNTP */
2781  _("Mail sent"));
2782 #ifdef USE_NOTMUCH
2783  const bool c_nm_record = cs_subset_bool(sub, "nm_record");
2784  if (c_nm_record)
2785  nm_record_message(mailbox, finalpath, e_cur);
2786 #endif
2787  mutt_sleep(0);
2788  }
2789 
2790  if (WithCrypto)
2791  FREE(&pgpkeylist);
2792 
2793  if ((WithCrypto != 0) && free_clear_content)
2794  mutt_body_free(&clear_content);
2795 
2796  /* set 'replied' flag only if the user didn't change/remove
2797  * In-Reply-To: and References: headers during edit */
2798  if (flags & SEND_REPLY)
2799  {
2800  if (!(flags & SEND_POSTPONED) && mailbox)
2801  {
2802  STAILQ_FOREACH(en, el, entries)
2803  {
2804  mutt_set_flag(mailbox, en->email, MUTT_REPLIED, is_reply(en->email, e_templ));
2805  }
2806  }
2807  }
2808 
2809  rc = 0;
2810 
2811 cleanup:
2812  mutt_buffer_dealloc(&fcc);
2813 
2814  if (flags & SEND_POSTPONED)
2815  {
2816  if (WithCrypto & APPLICATION_PGP)
2817  {
2818  cs_subset_str_string_set(sub, "pgp_sign_as", pgp_sign_as, NULL);
2819  }
2820  if (WithCrypto & APPLICATION_SMIME)
2821  {
2822  cs_subset_str_string_set(sub, "smime_sign_as", smime_sign_as, NULL);
2823  }
2824  }
2825 
2826  mutt_file_fclose(&fp_tmp);
2827  if (!(flags & SEND_NO_FREE_HEADER))
2828  email_free(&e_templ);
2829 
2830  FREE(&finalpath);
2831  return rc;
2832 }
#define MUTT_SEND_HOOK
send-hook: when composing a new email
Definition: hook.h:47
int nm_record_message(struct Mailbox *m, char *path, struct Email *e)
Add a message to the Notmuch database.
Definition: notmuch.c:2076
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:67
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:69
#define WithCrypto
Definition: lib.h:123
#define SEND_POSTPONED_FCC
Used by mutt_get_postponed() to signal that the x-mutt-fcc header field was present.
Definition: send.h:49
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:52
The envelope/body of an email.
Definition: email.h:37
#define TAILQ_FIRST(head)
Definition: queue.h:716
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:43
#define mutt_perror(...)
Definition: logging.h:85
static void fix_end_of_file(const char *data)
Ensure a file ends with a linefeed.
Definition: send.c:1486
void mutt_update_encoding(struct Body *a, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:905
struct Body * body
List of MIME parts.
Definition: email.h:91
&#39;NNTP&#39; (Usenet) Mailbox type
Definition: mailbox.h:52
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:84
#define mutt_message(...)
Definition: logging.h:83
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:1468
#define SEND_DRAFT_FILE
Used by the -H flag.
Definition: send.h:51
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:1821
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:85
void mutt_expand_aliases_env(struct Envelope *env)
Expand aliases in all the fields of an Envelope.
Definition: alias.c:308
static void process_user_header(struct Envelope *env)
Process the user headers.
Definition: send.c:353
#define SEND_FORWARD
Forward email.
Definition: send.h: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
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
static int invoke_mta(struct Email *e, struct ConfigSubset *sub)
Send an email.
Definition: send.c:1360
int mutt_edit_attachment(struct Body *a)
Edit an attachment.
Definition: mutt_attach.c:259
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:92
struct Body * next
next attachment in the list
Definition: body.h:53
An email address.
Definition: address.h:34
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:48
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:94
int crypt_get_keys(struct Email *e, char **keylist, bool oppenc_mode)
Check we have all the keys we need.
Definition: crypt.c:943
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
#define SEND_POSTPONED
Recall a postponed email.
Definition: send.h:45
void mutt_buffer_pretty_mailbox(struct Buffer *buf)
Shorten a mailbox path using &#39;~&#39; or &#39;=&#39;.
Definition: muttlib.c:599
Messages that have been replied to.
Definition: mutt.h:95
The body of an email.
Definition: body.h:34
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:67
#define SEC_INLINE
Email has an inline signature.
Definition: lib.h:92
struct Email * email_new(void)
Create a new Email.
Definition: email.c:72
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:1086
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:395
void mutt_sleep(short s)
Sleep for a while.
Definition: muttlib.c:1447
struct Mailbox * mailbox
Definition: context.h:50
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:1238
bool mutt_parse_mailto(struct Envelope *e, char **body, const char *src)
Parse a mailto:// url.
Definition: parse.c:1591
#define MUTT_COMPOSE_NOFREEHEADER
Definition: lib.h:43
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:326
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:1469
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
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:43
static bool is_reply(struct Email *reply, struct Email *orig)
Is one email a reply to another?
Definition: send.c:1560
User aborted the question (with Ctrl-G)
Definition: quad.h:38
static bool is_text_plain(const struct Body *b)
is a Body a text/plain MIME part?
Definition: send.c:1933
void * mdata
Driver specific data.
Definition: mailbox.h:136
struct Envelope * mutt_env_new(void)
Create a new Envelope.
Definition: envelope.c:42
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:47
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:98
#define SEND_RESEND
Reply using the current email as a template.
Definition: send.h:48
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:1277
#define mutt_mktemp(buf, buflen)
Definition: muttlib.h:74
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:97
A mailbox.
Definition: mailbox.h:81
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default &#39;from&#39; Address.
Definition: send.c:1328
void mutt_fix_reply_recipients(struct Envelope *env, struct ConfigSubset *sub)
Remove duplicate recipients.
Definition: send.c:877
void mutt_select_fcc(struct Buffer *path, struct Email *e)
Select the FCC path for an email.
Definition: hook.c:692
#define SEC_AUTOCRYPT_OVERRIDE
(Autocrypt) Indicates manual set/unset of encryption
Definition: lib.h:95
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
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:1276
int mutt_protect(struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
Definition: crypt.c:159
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
static int save_fcc(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:1625
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:241
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:54
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
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:41
NNTP-specific Mailbox data -.
Definition: lib.h:138
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:93
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:154
#define SEND_NO_FREE_HEADER
Used by the -E flag.
Definition: send.h:50
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:86
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:167
char * personal
Real name of address.
Definition: address.h:36
uint8_t flags
e.g. MB_NORMAL
Definition: mailbox.h:134
int mutt_num_postponed(struct Mailbox *m, bool force)
Return the number of postponed messages.
Definition: postpone.c:89
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:517
void mutt_parse_content_type(const char *s, struct Body *ct)
Parse a content type.
Definition: parse.c:425
void mutt_env_to_local(struct Envelope *env)
Convert an Envelope&#39;s Address fields to local format.
Definition: envelope.c:271
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:167
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1021
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:202
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:56
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:127
#define mutt_error(...)
Definition: logging.h:84
bool mutt_needs_mailcap(struct Body *m)
Does this type need a mailcap entry do display.
Definition: muttlib.c:405
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:479
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:963
#define MUTT_REPLY_HOOK
reply-hook: when replying to an email
Definition: hook.h:55
#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:1944
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
struct AddressList to
Email&#39;s &#39;To&#39; list.
Definition: envelope.h:58
List of Emails.
Definition: email.h:125
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:573
#define TAILQ_EMPTY(head)
Definition: queue.h:714
WHERE bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: options.h:46
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:347
void mutt_edit_file(const char *editor, const char *file)
Let the user edit a file.
Definition: curs_lib.c:355
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
rfc2047 encode the content-descriptions
Definition: send.c:1451
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:1014
int mutt_get_postponed(struct Context *ctx, struct Email *hdr, struct Email **cur, struct Buffer *fcc)
Recall a postponed message.
Definition: postpone.c:316
Type: &#39;application/*&#39;.
Definition: mime.h:33
int mutt_compose_menu(struct Email *e, struct Buffer *fcc, struct Email *e_cur, uint8_t flags, struct ConfigSubset *sub)
Allow the user to edit the message envelope.
Definition: compose.c:1472
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:46
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1488
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
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: