NeoMutt  2020-06-26-89-g172cd3
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.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 "pattern.h"
#include "protos.h"
#include "recvattach.h"
#include "rfc3676.h"
#include "sort.h"
#include "ncrypt/lib.h"
#include "mx.h"
#include "nntp/lib.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...
 
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  FILE *fp_tmp = NULL;
95  pid_t pid;
96 
97  const char *c_signature = cs_subset_path(sub, "signature");
98  if (c_signature && (fp_tmp = mutt_open_read(c_signature, &pid)))
99  {
100  const bool c_sig_dashes = cs_subset_bool(sub, "sig_dashes");
101  if (c_sig_dashes)
102  fputs("\n-- \n", fp);
103  mutt_file_copy_stream(fp_tmp, fp);
104  mutt_file_fclose(&fp_tmp);
105  if (pid != -1)
106  filter_wait(pid);
107  }
108 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:68
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:132
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:1304
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 116 of file send.c.

117 {
118  struct Address *a = NULL, *tmp = NULL;
119  TAILQ_FOREACH_SAFE(a, al, entries, tmp)
120  {
121  if (mutt_addr_is_user(a) && (!leave_only || TAILQ_NEXT(a, entries)))
122  {
123  TAILQ_REMOVE(al, a, entries);
124  mutt_addr_free(&a);
125  }
126  }
127 }
#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:545
#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 135 of file send.c.

137 {
138  const struct AddressList *const als[] = { t, c };
139 
140  for (size_t i = 0; i < mutt_array_size(als); ++i)
141  {
142  const struct AddressList *al = als[i];
143  struct Address *a = NULL;
144  TAILQ_FOREACH(a, al, entries)
145  {
146  if (!a->group && mutt_is_mail_list(a))
147  {
149  }
150  }
151  }
152 }
#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:1481
+ 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 162 of file send.c.

163 {
164  char buf[8192];
165  char *err = NULL;
166  int idna_ok = 0;
167 
168  do
169  {
170  buf[0] = '\0';
172  mutt_addrlist_write(al, buf, sizeof(buf), false);
173  if (mutt_get_field(field, buf, sizeof(buf), MUTT_ALIAS) != 0)
174  return -1;
176  mutt_addrlist_parse2(al, buf);
177  if (expand_aliases)
179  idna_ok = mutt_addrlist_to_intl(al, &err);
180  if (idna_ok != 0)
181  {
182  mutt_error(_("Bad IDN: '%s'"), err);
183  FREE(&err);
184  }
185  } while (idna_ok != 0);
186  return 0;
187 }
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:295
#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:1379
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1461
#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:1297
#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:1147
+ 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 197 of file send.c.

198 {
199  char buf[8192];
200 
201 #ifdef USE_NNTP
202  if (OptNewsSend)
203  {
204  if (en->newsgroups)
205  mutt_str_copy(buf, en->newsgroups, sizeof(buf));
206  else
207  buf[0] = '\0';
208  if (mutt_get_field("Newsgroups: ", buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0)
209  return -1;
210  FREE(&en->newsgroups);
211  en->newsgroups = mutt_str_dup(buf);
212 
213  if (en->followup_to)
214  mutt_str_copy(buf, en->followup_to, sizeof(buf));
215  else
216  buf[0] = '\0';
217 
218  const bool c_ask_follow_up = cs_subset_bool(sub, "ask_follow_up");
219  if (c_ask_follow_up &&
220  (mutt_get_field("Followup-To: ", buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0))
221  {
222  return -1;
223  }
224  FREE(&en->followup_to);
225  en->followup_to = mutt_str_dup(buf);
226 
227  if (en->x_comment_to)
228  mutt_str_copy(buf, en->x_comment_to, sizeof(buf));
229  else
230  buf[0] = '\0';
231 
232  const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
233  const bool c_ask_x_comment_to = cs_subset_bool(sub, "ask_x_comment_to");
234  if (c_x_comment_to && c_ask_x_comment_to &&
235  (mutt_get_field("X-Comment-To: ", buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0))
236  {
237  return -1;
238  }
239  FREE(&en->x_comment_to);
240  en->x_comment_to = mutt_str_dup(buf);
241  }
242  else
243 #endif
244  {
245  if ((mutt_edit_address(&en->to, _("To: "), true) == -1) || TAILQ_EMPTY(&en->to))
246  return -1;
247 
248  const bool c_askcc = cs_subset_bool(sub, "askcc");
249  if (c_askcc && (mutt_edit_address(&en->cc, _("Cc: "), true) == -1))
250  return -1;
251 
252  const bool c_askbcc = cs_subset_bool(sub, "askbcc");
253  if (c_askbcc && (mutt_edit_address(&en->bcc, _("Bcc: "), true) == -1))
254  return -1;
255 
256  const bool c_reply_with_xorig = cs_subset_bool(sub, "reply_with_xorig");
257  if (c_reply_with_xorig && (flags & (SEND_REPLY | SEND_LIST_REPLY | SEND_GROUP_REPLY)) &&
258  (mutt_edit_address(&en->from, "From: ", true) == -1))
259  {
260  return -1;
261  }
262  }
263 
264  if (en->subject)
265  {
266  const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
267  if (c_fast_reply)
268  return 0;
269  mutt_str_copy(buf, en->subject, sizeof(buf));
270  }
271  else
272  {
273  const char *p = NULL;
274 
275  buf[0] = '\0';
276  struct ListNode *uh = NULL;
277  STAILQ_FOREACH(uh, &UserHeader, entries)
278  {
279  size_t plen = mutt_istr_startswith(uh->data, "subject:");
280  if (plen)
281  {
282  p = mutt_str_skip_email_wsp(uh->data + plen);
283  mutt_str_copy(buf, p, sizeof(buf));
284  }
285  }
286  }
287 
288  const enum QuadOption c_abort_nosubject =
289  cs_subset_quad(sub, "abort_nosubject");
290  if ((mutt_get_field(_("Subject: "), buf, sizeof(buf), MUTT_COMP_NO_FLAGS) != 0) ||
291  ((buf[0] == '\0') &&
292  (query_quadoption(c_abort_nosubject, _("No subject, abort?")) != MUTT_NO)))
293  {
294  mutt_message(_("No subject, aborting"));
295  return -1;
296  }
297  mutt_str_replace(&en->subject, buf);
298 
299  return 0;
300 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:68
#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:375
#define _(a)
Definition: message.h:28
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:91
#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
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:748
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
#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:153
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:515
#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:721
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:451
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
#define FREE(x)
Definition: memory.h:40
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
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
int mutt_edit_address(struct AddressList *al, const char *field, bool expand_aliases)
Edit an email address.
Definition: send.c:162
+ 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 310 of file send.c.

311 {
312  SKIPWS(s);
313  return mutt_str_dup(s);
314 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
#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 321 of file send.c.

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

349 {
350  struct ListNode *uh = NULL;
351  STAILQ_FOREACH(uh, &UserHeader, entries)
352  {
353  size_t plen;
354  if ((plen = mutt_istr_startswith(uh->data, "from:")))
355  {
356  /* User has specified a default From: address. Remove default address */
357  mutt_addrlist_clear(&env->from);
358  mutt_addrlist_parse(&env->from, uh->data + plen);
359  }
360  else if ((plen = mutt_istr_startswith(uh->data, "reply-to:")))
361  {
363  mutt_addrlist_parse(&env->reply_to, uh->data + plen);
364  }
365  else if ((plen = mutt_istr_startswith(uh->data, "message-id:")))
366  {
367  char *tmp = mutt_extract_message_id(uh->data + plen, NULL);
368  if (mutt_addr_valid_msgid(tmp))
369  {
370  FREE(&env->message_id);
371  env->message_id = tmp;
372  }
373  else
374  FREE(&tmp);
375  }
376  else if (!mutt_istr_startswith(uh->data, "to:") &&
377  !mutt_istr_startswith(uh->data, "cc:") &&
378  !mutt_istr_startswith(uh->data, "bcc:") &&
379 #ifdef USE_NNTP
380  !mutt_istr_startswith(uh->data, "newsgroups:") &&
381  !mutt_istr_startswith(uh->data, "followup-to:") &&
382  !mutt_istr_startswith(uh->data, "x-comment-to:") &&
383 #endif
384  !mutt_istr_startswith(uh->data, "supersedes:") &&
385  !mutt_istr_startswith(uh->data, "subject:") &&
386  !mutt_istr_startswith(uh->data, "return-path:"))
387  {
389  }
390  }
391 }
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:1461
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:375
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:356
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:177
#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 400 of file send.c.

401 {
402  const char *c_forward_attribution_intro =
403  cs_subset_string(sub, "forward_attribution_intro");
404  if (!c_forward_attribution_intro || !fp)
405  return;
406 
407  const char *c_attribution_locale =
408  cs_subset_string(sub, "attribution_locale");
409 
410  char buf[1024];
411  setlocale(LC_TIME, NONULL(c_attribution_locale));
412  mutt_make_string(buf, sizeof(buf), 0, c_forward_attribution_intro, NULL, m, e);
413  setlocale(LC_TIME, "");
414  fputs(buf, fp);
415  fputs("\n\n", fp);
416 }
#define NONULL(x)
Definition: string2.h:37
#define mutt_make_string(BUF, BUFLEN, COLS, S, CTX, M, E)
Definition: hdrline.h:59
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:219
+ 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 425 of file send.c.

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

456 {
457  CopyHeaderFlags chflags = CH_DECODE;
459 
462 
463  const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
464  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) && c_forward_decode)
465  {
466  /* make sure we have the user's passphrase before proceeding... */
468  return -1;
469  }
470 
471  mutt_forward_intro(m, e, fp_out, sub);
472 
473  if (c_forward_decode)
474  {
475  cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
476 
477  const bool c_weed = cs_subset_bool(sub, "weed");
478  if (c_weed)
479  {
480  chflags |= CH_WEED | CH_REORDER;
481  cmflags |= MUTT_CM_WEED;
482  }
483  }
484 
485  const bool c_forward_quote = cs_subset_bool(sub, "forward_quote");
486  if (c_forward_quote)
487  cmflags |= MUTT_CM_PREFIX;
488 
489  mutt_copy_message(fp_out, m, e, cmflags, chflags, 0);
490  mutt_forward_trailer(m, e, fp_out, sub);
491  return 0;
492 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:68
#define WithCrypto
Definition: lib.h:118
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:80
#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:48
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:821
#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:400
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:425
+ 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 504 of file send.c.

507 {
508  struct Body **last = *plast;
509  struct Body *body = NULL;
510  struct Message *msg = NULL;
511  struct AttachCtx *actx = NULL;
512  int rc = 0, i;
513 
516 
517  msg = mx_msg_open(m, e->msgno);
518  if (!msg)
519  return -1;
520 
521  actx = mutt_mem_calloc(1, sizeof(*actx));
522  actx->email = e;
523  actx->fp_root = msg->fp;
524 
525  mutt_generate_recvattach_list(actx, actx->email, actx->email->content,
526  actx->fp_root, -1, 0, 0);
527 
528  for (i = 0; i < actx->idxlen; i++)
529  {
530  body = actx->idx[i]->content;
531  if ((body->type != TYPE_MULTIPART) && !mutt_can_decode(body) &&
532  !((body->type == TYPE_APPLICATION) &&
533  (mutt_istr_equal(body->subtype, "pgp-signature") ||
534  mutt_istr_equal(body->subtype, "x-pkcs7-signature") ||
535  mutt_istr_equal(body->subtype, "pkcs7-signature"))))
536  {
537  /* Ask the quadoption only once */
538  if (*forwardq == MUTT_ABORT)
539  {
540  const enum QuadOption c_forward_attachments =
541  cs_subset_quad(sub, "forward_attachments");
542  *forwardq = query_quadoption(c_forward_attachments,
543  /* L10N: This is the prompt for $forward_attachments.
544  When inline forwarding ($mime_forward answered "no"), this prompts
545  whether to add non-decodable attachments from the original email.
546  Text/plain parts and the like will already be included in the
547  message contents, but other attachment, such as PDF files, will also
548  be added as attachments to the new mail, if this is answered yes. */
549  _("Forward attachments?"));
550  if (*forwardq != MUTT_YES)
551  {
552  if (*forwardq == -1)
553  rc = -1;
554  goto cleanup;
555  }
556  }
557  if (mutt_body_copy(actx->idx[i]->fp, last, body) == -1)
558  {
559  rc = -1;
560  goto cleanup;
561  }
562  last = &((*last)->next);
563  }
564  }
565 
566 cleanup:
567  *plast = last;
568  mx_msg_close(m, &msg);
569  mutt_actx_free(&actx);
570  return rc;
571 }
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
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:1228
User aborted the question (with Ctrl-G)
Definition: quad.h:38
struct Email * email
Used by recvattach for updating.
Definition: attach.h:51
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
struct Body * content
List of MIME parts.
Definition: email.h:90
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:48
#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
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1180
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
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:888
char * subtype
content-type subtype
Definition: body.h:37
A local copy of an email.
Definition: mx.h:83
bool mutt_can_decode(struct Body *a)
Will decoding the attachment produce any output.
Definition: handler.c:1795
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:153
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:515
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
struct Body * content
Attachment.
Definition: attach.h:36
FILE * fp
pointer to the message data
Definition: mx.h:85
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:1132
Type: &#39;application/*&#39;.
Definition: mime.h:33
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
int msgno
Number displayed to the user.
Definition: email.h:86
+ 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 580 of file send.c.

582 {
583  const char *c_attribution = cs_subset_string(sub, "attribution");
584  if (!c_attribution || !fp_out)
585  return;
586 
587  const char *c_attribution_locale =
588  cs_subset_string(sub, "attribution_locale");
589 
590  char buf[1024];
591  setlocale(LC_TIME, NONULL(c_attribution_locale));
592  mutt_make_string(buf, sizeof(buf), 0, c_attribution, NULL, m, e);
593  setlocale(LC_TIME, "");
594  fputs(buf, fp_out);
595  fputc('\n', fp_out);
596 }
#define NONULL(x)
Definition: string2.h:37
#define mutt_make_string(BUF, BUFLEN, COLS, S, CTX, M, E)
Definition: hdrline.h:59
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:219
+ 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 605 of file send.c.

607 {
608  const char *c_post_indent_string =
609  cs_subset_string(sub, "post_indent_string");
610  if (!c_post_indent_string || !fp_out)
611  return;
612 
613  char buf[256];
614  mutt_make_string(buf, sizeof(buf), 0, c_post_indent_string, NULL, m, e);
615  fputs(buf, fp_out);
616  fputc('\n', fp_out);
617 }
#define mutt_make_string(BUF, BUFLEN, COLS, S, CTX, M, E)
Definition: hdrline.h:59
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:219
+ 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 628 of file send.c.

630 {
631  CopyMessageFlags cmflags =
633  CopyHeaderFlags chflags = CH_DECODE;
634 
635  if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
636  {
637  /* make sure we have the user's passphrase before proceeding... */
639  return -1;
640  }
641 
644 
645  mutt_make_attribution(m, e, fp_out, sub);
646 
647  const bool c_header = cs_subset_bool(sub, "header");
648  if (!c_header)
649  cmflags |= MUTT_CM_NOHEADER;
650 
651  const bool c_weed = cs_subset_bool(sub, "weed");
652  if (c_weed)
653  {
654  chflags |= CH_WEED | CH_REORDER;
655  cmflags |= MUTT_CM_WEED;
656  }
657 
658  mutt_copy_message(fp_out, m, e, cmflags, chflags, 0);
659 
660  mutt_make_post_indent(m, e, fp_out, sub);
661 
662  return 0;
663 }
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:580
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:68
#define WithCrypto
Definition: lib.h:118
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:80
#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:48
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:821
#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:605
+ 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 672 of file send.c.

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

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

787 {
788  enum QuadOption hmfupto = MUTT_ABORT;
789  const struct Address *followup_to = TAILQ_FIRST(&in->mail_followup_to);
790 
791  if ((flags & (SEND_LIST_REPLY | SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) && followup_to)
792  {
793  char prompt[256];
794  snprintf(prompt, sizeof(prompt), _("Follow-up to %s%s?"), followup_to->mailbox,
795  TAILQ_NEXT(TAILQ_FIRST(&in->mail_followup_to), entries) ? ",..." : "");
796 
797  const enum QuadOption c_honor_followup_to =
798  cs_subset_quad(sub, "honor_followup_to");
799  hmfupto = query_quadoption(c_honor_followup_to, prompt);
800  if (hmfupto == MUTT_ABORT)
801  return -1;
802  }
803 
804  if (flags & SEND_LIST_REPLY)
805  {
806  add_mailing_lists(&out->to, &in->to, &in->cc);
807 
808  if (followup_to && (hmfupto == MUTT_YES) &&
809  (default_to(&out->cc, in, flags & SEND_LIST_REPLY, (hmfupto == MUTT_YES), sub) == MUTT_ABORT))
810  {
811  return -1; /* abort */
812  }
813  }
814  else if (flags & SEND_TO_SENDER)
815  {
816  mutt_addrlist_copy(&out->to, &in->from, false);
817  }
818  else
819  {
820  if (default_to(&out->to, in, flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY),
821  (hmfupto == MUTT_YES), sub) == -1)
822  return -1; /* abort */
823 
824  if ((flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) &&
825  (!followup_to || (hmfupto != MUTT_YES)))
826  {
827  /* if(!mutt_addr_is_user(in->to)) */
828  if (flags & SEND_GROUP_REPLY)
829  mutt_addrlist_copy(&out->cc, &in->to, true);
830  else
831  mutt_addrlist_copy(&out->to, &in->cc, true);
832  mutt_addrlist_copy(&out->cc, &in->cc, true);
833  }
834  }
835  return 0;
836 }
#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
User aborted the question (with Ctrl-G)
Definition: quad.h:38
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
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
static int default_to(struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
Generate default email addresses.
Definition: send.c:698
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
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:153
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:515
#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:135
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
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
+ 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 843 of file send.c.

844 {
845  struct ListNode *np = NULL;
846 
847  struct ListHead *src = STAILQ_EMPTY(&env->references) ? &env->in_reply_to : &env->references;
848  STAILQ_FOREACH(np, src, entries)
849  {
851  }
852 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
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 859 of file send.c.

860 {
861  if (env->message_id)
862  {
864  }
865 }
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
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 872 of file send.c.

873 {
874  const bool c_metoo = cs_subset_bool(sub, "metoo");
875  if (!c_metoo)
876  {
877  const bool c_reply_self = cs_subset_bool(sub, "reply_self");
878 
879  /* the order is important here. do the CC: first so that if the
880  * the user is the only recipient, it ends up on the TO: field */
881  remove_user(&env->cc, TAILQ_EMPTY(&env->to));
882  remove_user(&env->to, TAILQ_EMPTY(&env->cc) || c_reply_self);
883  }
884 
885  /* the CC field can get cluttered, especially with lists */
886  mutt_addrlist_dedupe(&env->to);
887  mutt_addrlist_dedupe(&env->cc);
888  mutt_addrlist_remove_xrefs(&env->to, &env->cc);
889 
890  if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
891  {
892  TAILQ_SWAP(&env->to, &env->cc, Address, entries);
893  }
894 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:68
An email address.
Definition: address.h:34
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1398
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:1434
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:116
#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 903 of file send.c.

905 {
906  if (!env)
907  return;
908 
909  const char *c_forward_format = cs_subset_string(sub, "forward_format");
910 
911  char buf[256];
912  /* set the default subject for the message. */
913  mutt_make_string(buf, sizeof(buf), 0, NONULL(c_forward_format), NULL, m, e);
914  mutt_str_replace(&env->subject, buf);
915 }
#define NONULL(x)
Definition: string2.h:37
#define mutt_make_string(BUF, BUFLEN, COLS, S, CTX, M, E)
Definition: hdrline.h:59
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:219
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:451
+ 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 923 of file send.c.

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

952 {
953  add_references(&env->references, curenv);
954  add_message_id(&env->references, curenv);
955  add_message_id(&env->in_reply_to, curenv);
956 
957 #ifdef USE_NNTP
958  const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
959  if (OptNewsSend && c_x_comment_to && !TAILQ_EMPTY(&curenv->from))
961 #endif
962 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:68
#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:843
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
static void add_message_id(struct ListHead *head, struct Envelope *env)
Add the email&#39;s message ID to a list.
Definition: send.c:859
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:157
+ 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 970 of file send.c.

972 {
973  if (!el || !env || STAILQ_EMPTY(el))
974  return;
975 
976  struct EmailNode *en = STAILQ_FIRST(el);
977  bool single = !STAILQ_NEXT(en, entries);
978 
979  if (!single)
980  {
981  STAILQ_FOREACH(en, el, entries)
982  {
983  mutt_add_to_reference_headers(env, en->email->env, sub);
984  }
985  }
986  else
987  mutt_add_to_reference_headers(env, en->email->env, sub);
988 
989  /* if there's more than entry in In-Reply-To (i.e. message has multiple
990  * parents), don't generate a References: header as it's discouraged by
991  * RFC2822, sect. 3.6.4 */
992  if (!single && !STAILQ_EMPTY(&env->in_reply_to) &&
993  STAILQ_NEXT(STAILQ_FIRST(&env->in_reply_to), entries))
994  {
995  mutt_list_free(&env->references);
996  }
997 }
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:89
#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:116
#define STAILQ_EMPTY(head)
Definition: queue.h:345
List of Emails.
Definition: email.h:114
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:950
+ 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 1009 of file send.c.

1011 {
1012  if (!el || STAILQ_EMPTY(el))
1013  return -1;
1014 
1015  struct EmailNode *en = STAILQ_FIRST(el);
1016  bool single = !STAILQ_NEXT(en, entries);
1017 
1018  struct Envelope *curenv = en->email->env;
1019  if (!curenv)
1020  return -1;
1021 
1022  if (flags & (SEND_REPLY | SEND_TO_SENDER))
1023  {
1024 #ifdef USE_NNTP
1025  if ((flags & SEND_NEWS))
1026  {
1027  /* in case followup set Newsgroups: with Followup-To: if it present */
1028  if (!env->newsgroups && !mutt_istr_equal(curenv->followup_to, "poster"))
1029  {
1030  env->newsgroups = mutt_str_dup(curenv->followup_to);
1031  }
1032  }
1033  else
1034 #endif
1035  if (!single)
1036  {
1037  STAILQ_FOREACH(en, el, entries)
1038  {
1039  if (mutt_fetch_recips(env, en->email->env, flags, sub) == -1)
1040  return -1;
1041  }
1042  }
1043  else if (mutt_fetch_recips(env, curenv, flags, sub) == -1)
1044  return -1;
1045 
1046  if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
1047  {
1048  mutt_error(_("No mailing lists found"));
1049  return -1;
1050  }
1051 
1052  if (flags & SEND_REPLY)
1053  {
1054  mutt_make_misc_reply_headers(env, curenv, sub);
1055  make_reference_headers(el, env, sub);
1056  }
1057  }
1058  else if (flags & SEND_FORWARD)
1059  {
1060  mutt_make_forward_subject(env, m, en->email, sub);
1061 
1062  const bool c_forward_references = cs_subset_bool(sub, "forward_references");
1063  if (c_forward_references)
1064  make_reference_headers(el, env, sub);
1065  }
1066 
1067  return 0;
1068 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:68
#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:375
#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:970
struct Envelope * env
Envelope information.
Definition: email.h:89
#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:888
#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:785
#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:116
#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:114
void mutt_make_misc_reply_headers(struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
Set subject for a reply.
Definition: send.c:923
#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:903
+ 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 1081 of file send.c.

1083 {
1084  /* An EmailList is required for replying and forwarding */
1085  if (!el && (flags & (SEND_REPLY | SEND_FORWARD)))
1086  return -1;
1087 
1088  if (flags & SEND_REPLY)
1089  {
1090  const enum QuadOption c_include = cs_subset_quad(sub, "include");
1091  enum QuadOption ans =
1092  query_quadoption(c_include, _("Include message in reply?"));
1093  if (ans == MUTT_ABORT)
1094  return -1;
1095 
1096  if (ans == MUTT_YES)
1097  {
1098  mutt_message(_("Including quoted message..."));
1099  struct EmailNode *en = NULL;
1100  STAILQ_FOREACH(en, el, entries)
1101  {
1102  if (include_reply(m, en->email, fp_tmp, sub) == -1)
1103  {
1104  mutt_error(_("Could not include all requested messages"));
1105  return -1;
1106  }
1107  if (STAILQ_NEXT(en, entries) != NULL)
1108  {
1109  fputc('\n', fp_tmp);
1110  }
1111  }
1112  }
1113  }
1114  else if (flags & SEND_FORWARD)
1115  {
1116  const enum QuadOption c_mime_forward = cs_subset_quad(sub, "mime_forward");
1117  enum QuadOption ans =
1118  query_quadoption(c_mime_forward, _("Forward as attachment?"));
1119  if (ans == MUTT_YES)
1120  {
1121  struct Body *last = e->content;
1122 
1123  mutt_message(_("Preparing forwarded message..."));
1124 
1125  while (last && last->next)
1126  last = last->next;
1127 
1128  struct EmailNode *en = NULL;
1129  STAILQ_FOREACH(en, el, entries)
1130  {
1131  struct Body *tmp = mutt_make_message_attach(m, en->email, false, sub);
1132  if (last)
1133  {
1134  last->next = tmp;
1135  last = tmp;
1136  }
1137  else
1138  {
1139  last = tmp;
1140  e->content = tmp;
1141  }
1142  }
1143  }
1144  else if (ans != MUTT_ABORT)
1145  {
1146  enum QuadOption forwardq = MUTT_ABORT;
1147  struct Body **last = NULL;
1148  struct EmailNode *en = NULL;
1149 
1150  const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
1151  const enum QuadOption c_forward_attachments =
1152  cs_subset_quad(sub, "forward_attachments");
1153  if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1154  {
1155  last = &e->content;
1156  while (*last)
1157  last = &((*last)->next);
1158  }
1159 
1160  STAILQ_FOREACH(en, el, entries)
1161  {
1162  struct Email *e_cur = en->email;
1163  include_forward(m, e_cur, fp_tmp, sub);
1164  if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1165  {
1166  if (inline_forward_attachments(m, e_cur, &last, &forwardq, sub) != 0)
1167  return -1;
1168  }
1169  }
1170  }
1171  else
1172  return -1;
1173  }
1174  /* if (WithCrypto && (flags & SEND_KEY)) */
1175  else if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY))
1176  {
1177  struct Body *b = NULL;
1178 
1179  if (((WithCrypto & APPLICATION_PGP) != 0) && !(b = crypt_pgp_make_key_attachment()))
1180  {
1181  return -1;
1182  }
1183 
1184  b->next = e->content;
1185  e->content = b;
1186  }
1187 
1188  mutt_clear_error();
1189 
1190  return 0;
1191 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:68
#define WithCrypto
Definition: lib.h:118
The envelope/body of an email.
Definition: email.h:37
static int include_forward(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Write out a forwarded message.
Definition: send.c:454
User aborted the question (with Ctrl-G)
Definition: quad.h:38
#define mutt_message(...)
Definition: logging.h:83
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
#define SEND_FORWARD
Forward email.
Definition: send.h:44
struct Body * content
List of MIME parts.
Definition: email.h:90
#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
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
#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:504
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:92
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
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:933
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:628
#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:153
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: curs_lib.c:515
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:116
#define mutt_error(...)
Definition: logging.h:84
List of Emails.
Definition: email.h:114
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
+ 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 1198 of file send.c.

1199 {
1200  /* Only generate the Mail-Followup-To if the user has requested it, and
1201  * it hasn't already been set */
1202 
1203  const bool c_followup_to = cs_subset_bool(sub, "followup_to");
1204  if (!c_followup_to)
1205  return;
1206 #ifdef USE_NNTP
1207  if (OptNewsSend)
1208  {
1209  if (!env->followup_to && env->newsgroups && (strrchr(env->newsgroups, ',')))
1210  env->followup_to = mutt_str_dup(env->newsgroups);
1211  return;
1212  }
1213 #endif
1214 
1215  if (TAILQ_EMPTY(&env->mail_followup_to))
1216  {
1217  if (mutt_is_list_recipient(false, env))
1218  {
1219  /* this message goes to known mailing lists, so create a proper
1220  * mail-followup-to header */
1221 
1222  mutt_addrlist_copy(&env->mail_followup_to, &env->to, false);
1223  mutt_addrlist_copy(&env->mail_followup_to, &env->cc, true);
1224  }
1225 
1226  /* remove ourselves from the mail-followup-to header */
1227  remove_user(&env->mail_followup_to, false);
1228 
1229  /* If we are not subscribed to any of the lists in question, re-add
1230  * ourselves to the mail-followup-to header. The mail-followup-to header
1231  * generated is a no-op with group-reply, but makes sure list-reply has the
1232  * desired effect. */
1233 
1234  if (!TAILQ_EMPTY(&env->mail_followup_to) &&
1235  !mutt_is_subscribed_list_recipient(false, env))
1236  {
1237  struct AddressList *al = NULL;
1238  if (!TAILQ_EMPTY(&env->reply_to))
1239  al = &env->reply_to;
1240  else if (!TAILQ_EMPTY(&env->from))
1241  al = &env->from;
1242 
1243  if (al)
1244  {
1245  struct Address *a = NULL;
1246  TAILQ_FOREACH_REVERSE(a, al, AddressList, entries)
1247  {
1249  }
1250  }
1251  else
1252  {
1254  }
1255  }
1256 
1258  }
1259 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:68
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:375
An email address.
Definition: address.h:34
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:716
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1398
#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
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default &#39;from&#39; Address.
Definition: send.c:1323
void mutt_addrlist_prepend(struct AddressList *al, struct Address *a)
Prepend an Address to an AddressList.
Definition: address.c:1492
char * newsgroups
List of newsgroups.
Definition: envelope.h:75
char * followup_to
List of &#39;followup-to&#39; fields.
Definition: envelope.h:77
int mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *e)
Matches subscribed mailing lists.
Definition: pattern.c:1818
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:116
int mutt_is_list_recipient(bool all_addr, struct Envelope *e)
Matches known mailing lists.
Definition: pattern.c:1831
+ 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 1271 of file send.c.

1273 {
1274  struct Address *a = NULL;
1275  if (TAILQ_EMPTY(al))
1276  {
1277  TAILQ_FOREACH(a, &env->to, entries)
1278  {
1279  if (mutt_addr_is_user(a))
1280  {
1282  break;
1283  }
1284  }
1285  }
1286 
1287  if (TAILQ_EMPTY(al))
1288  {
1289  TAILQ_FOREACH(a, &env->cc, entries)
1290  {
1291  if (mutt_addr_is_user(a))
1292  {
1294  break;
1295  }
1296  }
1297  }
1298 
1299  if (TAILQ_EMPTY(al))
1300  {
1301  struct Address *from = TAILQ_FIRST(&env->from);
1302  if (from && mutt_addr_is_user(from))
1303  {
1305  }
1306  }
1307 
1308  if (!TAILQ_EMPTY(al))
1309  {
1310  /* when $reverse_realname is not set, clear the personal name so that it
1311  * may be set via a reply- or send-hook. */
1312 
1313  const bool c_reverse_realname = cs_subset_bool(sub, "reverse_realname");
1314  if (!c_reverse_realname)
1315  FREE(&TAILQ_FIRST(al)->personal);
1316  }
1317 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:68
#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:545
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:1481
+ 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 1323 of file send.c.

1324 {
1325  /* Note: We let $from override $realname here.
1326  * Is this the right thing to do?
1327  */
1328 
1329  const struct Address *c_from = cs_subset_address(sub, "from");
1330  const bool c_use_domain = cs_subset_bool(sub, "use_domain");
1331  if (c_from)
1332  {
1333  return mutt_addr_copy(c_from);
1334  }
1335  else if (c_use_domain)
1336  {
1337  struct Address *addr = mutt_addr_new();
1338  mutt_str_asprintf(&addr->mailbox, "%s@%s", NONULL(Username),
1339  NONULL(mutt_fqdn(true, sub)));
1340  return addr;
1341  }
1342  else
1343  {
1344  return mutt_addr_create(NULL, Username);
1345  }
1346 }
#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:68
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:47
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:53
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:1179
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1100
+ 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 1355 of file send.c.

1356 {
1357  struct Buffer *tempfile = NULL;
1358  int rc = -1;
1359 #ifdef USE_SMTP
1360  short old_write_bcc;
1361 #endif
1362 
1363  /* Write out the message in MIME form. */
1364  tempfile = mutt_buffer_pool_get();
1365  mutt_buffer_mktemp(tempfile);
1366  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tempfile), "w");
1367  if (!fp_tmp)
1368  goto cleanup;
1369 
1370 #ifdef USE_SMTP
1371  const bool c_write_bcc = cs_subset_bool(sub, "write_bcc");
1372  const char *c_smtp_url = cs_subset_string(sub, "smtp_url");
1373  old_write_bcc = c_write_bcc;
1374  if (c_smtp_url)
1375  cs_subset_str_native_set(sub, "write_bcc", false, NULL);
1376 #endif
1377 #ifdef MIXMASTER
1379  !STAILQ_EMPTY(&e->chain),
1381 #endif
1382 #ifndef MIXMASTER
1384  false, mutt_should_hide_protected_subject(e), sub);
1385 #endif
1386 #ifdef USE_SMTP
1387  if (old_write_bcc)
1388  cs_subset_str_native_set(sub, "write_bcc", true, NULL);
1389 #endif
1390 
1391  fputc('\n', fp_tmp); /* tie off the header. */
1392 
1393  if ((mutt_write_mime_body(e->content, fp_tmp, sub) == -1))
1394  goto cleanup;
1395 
1396  if (mutt_file_fclose(&fp_tmp) != 0)
1397  {
1398  mutt_perror(mutt_b2s(tempfile));
1399  unlink(mutt_b2s(tempfile));
1400  goto cleanup;
1401  }
1402 
1403 #ifdef MIXMASTER
1404  if (!STAILQ_EMPTY(&e->chain))
1405  {
1406  rc = mix_send_message(&e->chain, mutt_b2s(tempfile));
1407  goto cleanup;
1408  }
1409 #endif
1410 
1411 #ifdef USE_NNTP
1412  if (OptNewsSend)
1413  goto sendmail;
1414 #endif
1415 
1416 #ifdef USE_SMTP
1417  if (c_smtp_url)
1418  {
1419  rc = mutt_smtp_send(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1420  mutt_b2s(tempfile), (e->content->encoding == ENC_8BIT), sub);
1421  goto cleanup;
1422  }
1423 #endif
1424 
1425 sendmail:
1426  rc = mutt_invoke_sendmail(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1427  mutt_b2s(tempfile), (e->content->encoding == ENC_8BIT), sub);
1428 cleanup:
1429  if (fp_tmp)
1430  {
1431  mutt_file_fclose(&fp_tmp);
1432  unlink(mutt_b2s(tempfile));
1433  }
1434  mutt_buffer_pool_release(&tempfile);
1435  return rc;
1436 }
#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:68
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 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:1071
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Body * content
List of MIME parts.
Definition: email.h:90
String manipulation buffer.
Definition: buffer.h:33
8-bit text
Definition: mime.h:50
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:89
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
#define mutt_b2s(buf)
Definition: buffer.h:41
struct ListHead chain
Mixmaster chain.
Definition: email.h:99
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:219
int mix_send_message(struct ListHead *chain, const char *tempfile)
Send an email via Mixmaster.
Definition: remailer.c:903
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:753
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:315
#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:588
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 1444 of file send.c.

1445 {
1446  for (struct Body *t = b; t; t = t->next)
1447  {
1448  if (t->description)
1449  {
1450  const char *c_send_charset = cs_subset_string(sub, "send_charset");
1451  rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), c_send_charset);
1452  }
1453  if (recurse && t->parts)
1454  mutt_encode_descriptions(t->parts, recurse, sub);
1455  }
1456 }
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:219
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:1444
+ 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 1462 of file send.c.

1463 {
1464  for (struct Body *t = b; t; t = t->next)
1465  {
1466  if (t->description)
1467  {
1468  rfc2047_decode(&t->description);
1469  }
1470  if (t->parts)
1471  decode_descriptions(t->parts);
1472  }
1473 }
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:1462
+ 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 1479 of file send.c.

1480 {
1481  FILE *fp = mutt_file_fopen(data, "a+");
1482  if (!fp)
1483  return;
1484  if (fseek(fp, -1, SEEK_END) >= 0)
1485  {
1486  int c = fgetc(fp);
1487  if (c != '\n')
1488  fputc('\n', fp);
1489  }
1490  mutt_file_fclose(&fp);
1491 }
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:588
+ 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 1503 of file send.c.

1505 {
1506  struct Email *e_new = email_new();
1507 
1508  if (mutt_prepare_template(fp, ctx->mailbox, e_new, e_cur, true) < 0)
1509  {
1510  email_free(&e_new);
1511  return -1;
1512  }
1513 
1514  if (WithCrypto)
1515  {
1516  /* mutt_prepare_template doesn't always flip on an application bit.
1517  * so fix that here */
1518  if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1519  {
1520  const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
1521  if (((WithCrypto & APPLICATION_SMIME) != 0) && c_smime_is_default)
1522  e_new->security |= APPLICATION_SMIME;
1523  else if (WithCrypto & APPLICATION_PGP)
1524  e_new->security |= APPLICATION_PGP;
1525  else
1526  e_new->security |= APPLICATION_SMIME;
1527  }
1528 
1529  const bool c_crypt_opportunistic_encrypt =
1530  cs_subset_bool(sub, "crypt_opportunistic_encrypt");
1531  if (c_crypt_opportunistic_encrypt)
1532  {
1533  e_new->security |= SEC_OPPENCRYPT;
1535  }
1536  }
1537 
1538  struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1539  emaillist_add_email(&el, e_cur);
1540  int rc = mutt_send_message(SEND_RESEND, e_new, NULL, ctx, &el, sub);
1541  emaillist_clear(&el);
1542 
1543  return rc;
1544 }
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:68
#define WithCrypto
Definition: lib.h:118
The envelope/body of an email.
Definition: email.h:37
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:144
struct Mailbox * mailbox
Definition: context.h:50
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:93
#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:92
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:88
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1019
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:123
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:1923
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
struct Email * email_new(void)
Create a new Email.
Definition: email.c:68
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:41
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:652
+ 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 1553 of file send.c.

1554 {
1555  if (!reply || !reply->env || !orig || !orig->env)
1556  return false;
1557  return mutt_list_find(&orig->env->references, reply->env->message_id) ||
1558  mutt_list_find(&orig->env->in_reply_to, reply->env->message_id);
1559 }
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:89
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 1572 of file send.c.

1573 {
1574  const struct Regex *c_abort_noattach_regex =
1575  cs_subset_regex(sub, "abort_noattach_regex");
1576  const struct Regex *c_quote_regex = cs_subset_regex(sub, "quote_regex");
1577 
1578  /* Search for the regex in `$abort_noattach_regex` within a file */
1579  if (!c_abort_noattach_regex || !c_abort_noattach_regex->regex ||
1580  !c_quote_regex || !c_quote_regex->regex)
1581  {
1582  return false;
1583  }
1584 
1585  FILE *fp_att = mutt_file_fopen(filename, "r");
1586  if (!fp_att)
1587  return false;
1588 
1589  char *inputline = mutt_mem_malloc(1024);
1590  bool found = false;
1591  while (!feof(fp_att))
1592  {
1593  fgets(inputline, 1024, fp_att);
1594  if (!mutt_is_quote_line(inputline, NULL) &&
1595  mutt_regex_match(c_abort_noattach_regex, inputline))
1596  {
1597  found = true;
1598  break;
1599  }
1600  }
1601  FREE(&inputline);
1602  mutt_file_fclose(&fp_att);
1603  return found;
1604 }
regex_t * regex
compiled expression
Definition: regex3.h:91
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:175
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:88
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:609
#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:937
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:588
+ 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 1618 of file send.c.

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

1807 {
1808  char *pgpkeylist = NULL;
1809  const char *encrypt_as = NULL;
1810  struct Body *clear_content = NULL;
1811 
1812  const char *c_postponed = cs_subset_string(sub, "postponed");
1813  if (!c_postponed)
1814  {
1815  mutt_error(_("Can't postpone. $postponed is unset"));
1816  return -1;
1817  }
1818 
1819  if (e_post->content->next)
1820  e_post->content = mutt_make_multipart(e_post->content);
1821 
1822  mutt_encode_descriptions(e_post->content, true, sub);
1823 
1824  const bool c_postpone_encrypt = cs_subset_bool(sub, "postpone_encrypt");
1825  if ((WithCrypto != 0) && c_postpone_encrypt &&
1826  (e_post->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
1827  {
1828  if (((WithCrypto & APPLICATION_PGP) != 0) && (e_post->security & APPLICATION_PGP))
1829  {
1830  const char *c_pgp_default_key = cs_subset_string(sub, "pgp_default_key");
1831  encrypt_as = c_pgp_default_key;
1832  }
1833  else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e_post->security & APPLICATION_SMIME))
1834  {
1835  const char *c_smime_default_key =
1836  cs_subset_string(sub, "smime_default_key");
1837  encrypt_as = c_smime_default_key;
1838  }
1839  if (!encrypt_as)
1840  {
1841  const char *c_postpone_encrypt_as =
1842  cs_subset_string(sub, "postpone_encrypt_as");
1843  encrypt_as = c_postpone_encrypt_as;
1844  }
1845 
1846 #ifdef USE_AUTOCRYPT
1847  if (e_post->security & SEC_AUTOCRYPT)
1848  {
1850  {
1851  e_post->content = mutt_remove_multipart(e_post->content);
1852  decode_descriptions(e_post->content);
1853  mutt_error(_("Error encrypting message. Check your crypt settings."));
1854  return -1;
1855  }
1856  encrypt_as = AutocryptDefaultKey;
1857  }
1858 #endif
1859 
1860  if (encrypt_as)
1861  {
1862  pgpkeylist = mutt_str_dup(encrypt_as);
1863  clear_content = e_post->content;
1864  if (mutt_protect(e_post, pgpkeylist, true) == -1)
1865  {
1866  FREE(&pgpkeylist);
1867  e_post->content = mutt_remove_multipart(e_post->content);
1868  decode_descriptions(e_post->content);
1869  mutt_error(_("Error encrypting message. Check your crypt settings."));
1870  return -1;
1871  }
1872 
1873  FREE(&pgpkeylist);
1874 
1875  mutt_encode_descriptions(e_post->content, false, sub);
1876  }
1877  }
1878 
1879  /* make sure the message is written to the right part of a maildir
1880  * postponed folder. */
1881  e_post->read = false;
1882  e_post->old = false;
1883 
1884  mutt_prepare_envelope(e_post->env, false, sub);
1885  mutt_env_to_intl(e_post->env, NULL, NULL); /* Handle bad IDNAs the next time. */
1886 
1887  if (mutt_write_fcc(NONULL(c_postponed), e_post,
1888  (e_cur && (flags & SEND_REPLY)) ? e_cur->env->message_id : NULL,
1889  true, fcc, NULL, sub) < 0)
1890  {
1891  if (clear_content)
1892  {
1893  mutt_body_free(&e_post->content);
1894  e_post->content = clear_content;
1895  }
1896  mutt_env_free(&e_post->content->mime_headers); /* protected headers */
1897  e_post->content = mutt_remove_multipart(e_post->content);
1898  decode_descriptions(e_post->content);
1899  mutt_unprepare_envelope(e_post->env);
1900  return -1;
1901  }
1902 
1904 
1905  if (clear_content)
1906  mutt_body_free(&clear_content);
1907 
1908  return 0;
1909 }
#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:68
#define WithCrypto
Definition: lib.h:118
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:80
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:1501
struct Body * content
List of MIME parts.
Definition: email.h:90
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:375
#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:89
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:1235
bool old
Email is seen, but unread.
Definition: email.h:50
struct Envelope * env
Envelope information.
Definition: email.h:89
static void decode_descriptions(struct Body *b)
rfc2047 decode them in case of an error
Definition: send.c:1462
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: multipart.c:99
int mutt_autocrypt_set_sign_as_default_key(struct Email *e)
Set the Autocrypt default key for signing.
Definition: autocrypt.c:661
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:93
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:1274
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition: multipart.c:125
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:92
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:219
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:198
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:1444
+ 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 1923 of file send.c.

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