NeoMutt  2023-03-22-27-g3cb248
Teaching an old dog new tricks
DOXYGEN
send.c File Reference

Prepare and send an email. More...

#include "config.h"
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.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 "attach/lib.h"
#include "browser/lib.h"
#include "compose/lib.h"
#include "enter/lib.h"
#include "ncrypt/lib.h"
#include "pager/lib.h"
#include "parse/lib.h"
#include "pattern/lib.h"
#include "postpone/lib.h"
#include "question/lib.h"
#include "copy.h"
#include "format_flags.h"
#include "globals.h"
#include "handler.h"
#include "hdrline.h"
#include "hook.h"
#include "maillist.h"
#include "mutt_body.h"
#include "mutt_header.h"
#include "mutt_logging.h"
#include "muttlib.h"
#include "protos.h"
#include "rfc3676.h"
#include "sort.h"
#include "mx.h"
#include "nntp/mdata.h"
#include "mixmaster/lib.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 Email *e, FILE *fp, struct ConfigSubset *sub)
 Add the "start of forwarded message" text. More...
 
void mutt_forward_trailer (struct Email *e, FILE *fp, struct ConfigSubset *sub)
 Add a "end of forwarded message" text. More...
 
static int include_forward (struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Write out a forwarded message. More...
 
static int inline_forward_attachments (struct Mailbox *m, struct Email *e, struct Body ***plast, enum QuadOption *forwardq, struct ConfigSubset *sub)
 Add attachments to an email, inline. More...
 
static void format_attribution (const char *s, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Format an attribution prefix/suffix. More...
 
void mutt_make_attribution_intro (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add "on DATE, PERSON wrote" header. More...
 
void mutt_make_attribution_trailer (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add suffix to replied email text. More...
 
static const char * greeting_format_str (char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
 Format a greetings string - Implements format_t -. More...
 
static void mutt_make_greeting (struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Add greetings string. More...
 
static int include_reply (struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
 Generate the reply text for an email. More...
 
static const struct AddressList * choose_default_to (const struct Address *from, const struct Envelope *env, struct ConfigSubset *sub)
 Pick the best 'to:' value. More...
 
static int default_to (struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
 Generate default email addresses. More...
 
int mutt_fetch_recips (struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
 Generate recpients for a reply email. More...
 
static void add_references (struct ListHead *head, struct Envelope *env)
 Add the email's references to a list. More...
 
static void add_message_id (struct ListHead *head, struct Envelope *env)
 Add the email's message ID to a list. More...
 
void mutt_fix_reply_recipients (struct Envelope *env, struct ConfigSubset *sub)
 Remove duplicate recipients. More...
 
void mutt_make_forward_subject (struct Envelope *env, struct Email *e, struct ConfigSubset *sub)
 Create a subject for a forwarded email. More...
 
void mutt_make_misc_reply_headers (struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
 Set subject for a reply. More...
 
void mutt_add_to_reference_headers (struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
 Generate references for a reply email. More...
 
static void make_reference_headers (struct EmailList *el, struct Envelope *env, struct ConfigSubset *sub)
 Generate reference headers for an email. More...
 
static int envelope_defaults (struct Envelope *env, struct EmailList *el, SendFlags flags, struct ConfigSubset *sub)
 Fill in some defaults for a new email. More...
 
static int generate_body (FILE *fp_tmp, struct Email *e, SendFlags flags, struct Mailbox *m, struct EmailList *el, struct ConfigSubset *sub)
 Create a new email body. More...
 
void mutt_set_followup_to (struct Envelope *env, struct ConfigSubset *sub)
 Set followup-to field. More...
 
static void set_reverse_name (struct AddressList *al, struct Envelope *env, struct ConfigSubset *sub)
 Try to set the 'from' field from the recipients. More...
 
struct Addressmutt_default_from (struct ConfigSubset *sub)
 Get a default 'from' Address. More...
 
static int invoke_mta (struct Mailbox *m, struct Email *e, struct ConfigSubset *sub)
 Send an email. More...
 
void mutt_encode_descriptions (struct Body *b, bool recurse, struct ConfigSubset *sub)
 RFC2047 encode the content-descriptions. More...
 
static void decode_descriptions (struct Body *b)
 RFC2047 decode them in case of an error. More...
 
static void fix_end_of_file (const char *data)
 Ensure a file ends with a linefeed. More...
 
int mutt_resend_message (FILE *fp, struct Mailbox *m, struct Email *e_cur, struct ConfigSubset *sub)
 Resend an email. More...
 
static bool is_reply (struct Email *reply, struct Email *orig)
 Is one email a reply to another? More...
 
static bool search_attach_keyword (char *filename, struct ConfigSubset *sub)
 Search an email for 'attachment' keywords. More...
 
static int save_fcc (struct Mailbox *m, struct Email *e, struct Buffer *fcc, struct Body *clear_content, char *pgpkeylist, SendFlags flags, char **finalpath, struct ConfigSubset *sub)
 Save an Email to a 'sent mail' folder. More...
 
static int postpone_message (struct Email *e_post, struct Email *e_cur, const char *fcc, SendFlags flags, struct ConfigSubset *sub)
 Save an Email for another day. More...
 
static bool is_text_plain (const struct Body *b)
 Is a Body a text/plain MIME part? More...
 
static bool abort_for_missing_attachments (const struct Body *b, struct ConfigSubset *sub)
 Should we abort sending because of missing attachments? More...
 
int mutt_send_message (SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailList *el, struct ConfigSubset *sub)
 Send an email. More...
 
static bool send_simple_email (struct Mailbox *m, struct EmailList *el, const char *mailto, const char *subj, const char *body)
 Compose an email given a few basic ingredients. More...
 
bool mutt_send_list_subscribe (struct Mailbox *m, struct Email *e)
 Send a mailing-list subscription email. More...
 
bool mutt_send_list_unsubscribe (struct Mailbox *m, struct Email *e)
 Send a mailing-list unsubscription 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 95 of file send.c.

96{
97 const char *const c_signature = cs_subset_path(sub, "signature");
98 if (!c_signature)
99 return;
100
101 // If the user hasn't set $signature, don't warn them if it doesn't exist
102 struct Buffer *def_sig = mutt_buffer_pool_get();
103 cs_str_initial_get(sub->cs, "signature", def_sig);
104 mutt_path_canon(def_sig->data, def_sig->dsize, HomeDir, false);
105 bool notify_missing = !mutt_str_equal(c_signature, mutt_buffer_string(def_sig));
106 mutt_buffer_pool_release(&def_sig);
107
108 pid_t pid = 0;
109 FILE *fp_tmp = mutt_open_read(c_signature, &pid);
110 if (!fp_tmp)
111 {
112 if (notify_missing)
113 mutt_perror(c_signature);
114 return;
115 }
116
117 const bool c_sig_dashes = cs_subset_bool(sub, "sig_dashes");
118 if (c_sig_dashes)
119 fputs("\n-- \n", fp);
120 mutt_file_copy_stream(fp_tmp, fp);
121 mutt_file_fclose(&fp_tmp);
122 if (pid != -1)
123 filter_wait(pid);
124}
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:78
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
char * HomeDir
User's home directory.
Definition: globals.c:38
int cs_str_initial_get(const struct ConfigSet *cs, const char *name, struct Buffer *result)
Get the initial, or parent, value of a config item.
Definition: set.c:520
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:259
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
#define mutt_perror(...)
Definition: logging.h:88
bool mutt_path_canon(char *buf, size_t buflen, const char *homedir, bool is_dir)
Create the canonical version of a path.
Definition: path.c:285
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:807
FILE * mutt_open_read(const char *path, pid_t *thepid)
Run a command to read from.
Definition: muttlib.c:1264
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
String manipulation buffer.
Definition: buffer.h:34
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
+ 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 132 of file send.c.

133{
134 struct Address *a = NULL, *tmp = NULL;
135 TAILQ_FOREACH_SAFE(a, al, entries, tmp)
136 {
137 if (mutt_addr_is_user(a) && (!leave_only || TAILQ_NEXT(a, entries)))
138 {
139 TAILQ_REMOVE(al, a, entries);
140 mutt_addr_free(&a);
141 }
142 }
143}
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:444
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:574
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:735
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:841
#define TAILQ_NEXT(elm, field)
Definition: queue.h:832
An email address.
Definition: address.h:36
+ 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 151 of file send.c.

153{
154 const struct AddressList *const als[] = { t, c };
155
156 for (size_t i = 0; i < mutt_array_size(als); ++i)
157 {
158 const struct AddressList *al = als[i];
159 struct Address *a = NULL;
160 TAILQ_FOREACH(a, al, entries)
161 {
162 if (!a->group && mutt_is_mail_list(a))
163 {
165 }
166 }
167 }
168}
void mutt_addrlist_append(struct AddressList *al, struct Address *a)
Append an Address to an AddressList.
Definition: address.c:1463
struct Address * mutt_addr_copy(const struct Address *addr)
Copy the real address.
Definition: address.c:724
bool mutt_is_mail_list(const struct Address *addr)
Is this the email address of a mailing list? - Implements addr_predicate_t -.
Definition: maillist.c:44
#define mutt_array_size(x)
Definition: memory.h:36
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
bool group
Group mailbox?
Definition: address.h:39
+ 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 178 of file send.c.

179{
180 int rc = 0;
181 struct Buffer *buf = mutt_buffer_pool_get();
182 mutt_buffer_alloc(buf, 8192);
183 char *err = NULL;
184 int idna_ok = 0;
185
186 do
187 {
190 mutt_addrlist_write(al, buf, false);
191 if (mutt_buffer_get_field(field, buf, MUTT_COMP_ALIAS, false, NULL, NULL, NULL) != 0)
192 {
193 rc = -1;
194 goto done;
195 }
198 if (expand_aliases)
200 idna_ok = mutt_addrlist_to_intl(al, &err);
201 if (idna_ok != 0)
202 {
203 mutt_error(_("Bad IDN: '%s'"), err);
204 FREE(&err);
205 }
206 } while (idna_ok != 0);
207
208done:
210 return rc;
211}
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1443
int mutt_addrlist_to_local(struct AddressList *al)
Convert an Address list from Punycode.
Definition: address.c:1361
size_t mutt_addrlist_write(const struct AddressList *al, struct Buffer *buf, bool display)
Write an Address to a buffer.
Definition: address.c:1192
int mutt_addrlist_parse2(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:620
int mutt_addrlist_to_intl(struct AddressList *al, char **err)
Convert an Address list to Punycode.
Definition: address.c:1278
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:298
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:313
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
#define mutt_error(...)
Definition: logging.h:87
#define FREE(x)
Definition: memory.h:43
#define _(a)
Definition: message.h:28
#define MUTT_COMP_ALIAS
Alias completion (in alias dialog)
Definition: mutt.h:56
+ 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 221 of file send.c.

222{
223 int rc = -1;
224 struct Buffer *buf = mutt_buffer_pool_get();
225 mutt_buffer_alloc(buf, 8192);
226
227#ifdef USE_NNTP
228 if (OptNewsSend)
229 {
230 if (en->newsgroups)
232 else
234
235 if (mutt_buffer_get_field("Newsgroups: ", buf, MUTT_COMP_NO_FLAGS, false,
236 NULL, NULL, NULL) != 0)
237 {
238 goto done;
239 }
241
242 if (en->followup_to)
244 else
246
247 const bool c_ask_followup_to = cs_subset_bool(sub, "ask_followup_to");
248 if (c_ask_followup_to && (mutt_buffer_get_field("Followup-To: ", buf, MUTT_COMP_NO_FLAGS,
249 false, NULL, NULL, NULL) != 0))
250 {
251 goto done;
252 }
254
255 if (en->x_comment_to)
257 else
259
260 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
261 const bool c_ask_x_comment_to = cs_subset_bool(sub, "ask_x_comment_to");
262 if (c_x_comment_to && c_ask_x_comment_to &&
263 (mutt_buffer_get_field("X-Comment-To: ", buf, MUTT_COMP_NO_FLAGS, false,
264 NULL, NULL, NULL) != 0))
265 {
266 goto done;
267 }
269 }
270 else
271#endif
272 {
273 const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
274 if (TAILQ_EMPTY(&en->to) || !c_fast_reply || (flags & SEND_REVIEW_TO))
275 {
276 if ((mutt_edit_address(&en->to, _("To: "), true) == -1))
277 goto done;
278 }
279
280 const bool c_ask_cc = cs_subset_bool(sub, "ask_cc");
281 if (TAILQ_EMPTY(&en->cc) || !c_fast_reply)
282 {
283 if (c_ask_cc && (mutt_edit_address(&en->cc, _("Cc: "), true) == -1))
284 goto done;
285 }
286
287 const bool c_ask_bcc = cs_subset_bool(sub, "ask_bcc");
288 if (TAILQ_EMPTY(&en->bcc) || !c_fast_reply)
289 {
290 if (c_ask_bcc && (mutt_edit_address(&en->bcc, _("Bcc: "), true) == -1))
291 goto done;
292 }
293
294 if (TAILQ_EMPTY(&en->to) && TAILQ_EMPTY(&en->cc) && TAILQ_EMPTY(&en->bcc))
295 {
296 mutt_warning(_("No recipients specified"));
297 goto done;
298 }
299
300 const bool c_reply_with_xorig = cs_subset_bool(sub, "reply_with_xorig");
301 if (c_reply_with_xorig && (flags & (SEND_REPLY | SEND_LIST_REPLY | SEND_GROUP_REPLY)) &&
302 (mutt_edit_address(&en->from, "From: ", true) == -1))
303 {
304 goto done;
305 }
306 }
307
308 if (en->subject)
309 {
310 const bool c_fast_reply = cs_subset_bool(sub, "fast_reply");
311 if (c_fast_reply)
312 {
313 rc = 0;
314 goto done;
315 }
316 mutt_buffer_strcpy(buf, en->subject);
317 }
318 else
319 {
320 const char *p = NULL;
321
323 struct ListNode *uh = NULL;
324 STAILQ_FOREACH(uh, &UserHeader, entries)
325 {
326 size_t plen = mutt_istr_startswith(uh->data, "subject:");
327 if (plen)
328 {
330 mutt_buffer_strcpy(buf, p);
331 }
332 }
333 }
334
335 const enum QuadOption c_abort_nosubject = cs_subset_quad(sub, "abort_nosubject");
336 if ((mutt_buffer_get_field(_("Subject: "), buf, MUTT_COMP_NO_FLAGS, false,
337 NULL, NULL, NULL) != 0) ||
338 (mutt_buffer_is_empty(buf) &&
339 (query_quadoption(c_abort_nosubject, _("No subject, abort?")) != MUTT_NO)))
340 {
341 mutt_message(_("No subject, aborting"));
342 goto done;
343 }
345 rc = 0;
346
347done:
349 return rc;
350}
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:298
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:365
enum QuadOption cs_subset_quad(const struct ConfigSubset *sub, const char *name)
Get a quad-value config item by name.
Definition: helpers.c:218
struct ListHead UserHeader
List of custom headers to add to outgoing emails.
Definition: globals.c:54
bool OptNewsSend
(pseudo) used to change behavior when posting
Definition: globals.c:79
#define mutt_warning(...)
Definition: logging.h:85
#define mutt_message(...)
Definition: logging.h:86
char * mutt_str_skip_email_wsp(const char *s)
Skip over whitespace as defined by RFC5322.
Definition: string.c:679
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:239
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:326
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:55
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: question.c:386
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:352
#define TAILQ_EMPTY(head)
Definition: queue.h:721
int mutt_edit_address(struct AddressList *al, const char *field, bool expand_aliases)
Edit an email address.
Definition: send.c:178
#define SEND_GROUP_REPLY
Reply to all.
Definition: send.h:41
#define SEND_LIST_REPLY
Reply to mailing list.
Definition: send.h:42
#define SEND_REPLY
Reply to sender.
Definition: send.h:40
#define SEND_REVIEW_TO
Allow the user to edit the To field.
Definition: send.h:54
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
char * followup_to
List of 'followup-to' fields.
Definition: envelope.h:81
char * x_comment_to
List of 'X-comment-to' fields.
Definition: envelope.h:82
char * newsgroups
List of newsgroups.
Definition: envelope.h:79
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
char * subject
Email's subject.
Definition: envelope.h:70
struct AddressList bcc
Email's 'Bcc' list.
Definition: envelope.h:62
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
A List node for strings.
Definition: list.h:35
char * data
String.
Definition: list.h:36
+ 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 360 of file send.c.

361{
362 SKIPWS(s);
363 return mutt_str_dup(s);
364}
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
#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 371 of file send.c.

372{
373 struct ListNode *uh = NULL;
374 STAILQ_FOREACH(uh, &UserHeader, entries)
375 {
376 size_t plen;
377 if ((plen = mutt_istr_startswith(uh->data, "to:")))
378 mutt_addrlist_parse(&env->to, uh->data + plen);
379 else if ((plen = mutt_istr_startswith(uh->data, "cc:")))
380 mutt_addrlist_parse(&env->cc, uh->data + plen);
381 else if ((plen = mutt_istr_startswith(uh->data, "bcc:")))
382 mutt_addrlist_parse(&env->bcc, uh->data + plen);
383#ifdef USE_NNTP
384 else if ((plen = mutt_istr_startswith(uh->data, "newsgroups:")))
385 env->newsgroups = nntp_get_header(uh->data + plen);
386 else if ((plen = mutt_istr_startswith(uh->data, "followup-to:")))
387 env->followup_to = nntp_get_header(uh->data + plen);
388 else if ((plen = mutt_istr_startswith(uh->data, "x-comment-to:")))
390#endif
391 }
392}
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:462
static char * nntp_get_header(const char *s)
Get the trimmed header.
Definition: send.c:360
+ 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 398 of file send.c.

399{
400 struct ListNode *uh = NULL;
401 STAILQ_FOREACH(uh, &UserHeader, entries)
402 {
403 size_t plen;
404 if ((plen = mutt_istr_startswith(uh->data, "from:")))
405 {
406 /* User has specified a default From: address. Remove default address */
408 mutt_addrlist_parse(&env->from, uh->data + plen);
409 }
410 else if ((plen = mutt_istr_startswith(uh->data, "reply-to:")))
411 {
414 }
415 else if ((plen = mutt_istr_startswith(uh->data, "message-id:")))
416 {
417 char *tmp = mutt_extract_message_id(uh->data + plen, NULL);
418 if (mutt_addr_valid_msgid(tmp))
419 {
420 FREE(&env->message_id);
421 env->message_id = tmp;
422 }
423 else
424 {
425 FREE(&tmp);
426 }
427 }
428 else if (!mutt_istr_startswith(uh->data, "to:") &&
429 !mutt_istr_startswith(uh->data, "cc:") &&
430 !mutt_istr_startswith(uh->data, "bcc:") &&
431#ifdef USE_NNTP
432 !mutt_istr_startswith(uh->data, "newsgroups:") &&
433 !mutt_istr_startswith(uh->data, "followup-to:") &&
434 !mutt_istr_startswith(uh->data, "x-comment-to:") &&
435#endif
436 !mutt_istr_startswith(uh->data, "supersedes:") &&
437 !mutt_istr_startswith(uh->data, "subject:") &&
438 !mutt_istr_startswith(uh->data, "return-path:"))
439 {
441 }
442 }
443}
bool mutt_addr_valid_msgid(const char *msgid)
Is this a valid Message ID?
Definition: address.c:772
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:362
struct ListHead userhdrs
user defined headers
Definition: envelope.h:87
struct AddressList reply_to
Email's 'reply-to'.
Definition: envelope.h:64
char * message_id
Message ID.
Definition: envelope.h:73
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_forward_intro()

void mutt_forward_intro ( struct Email e,
FILE *  fp,
struct ConfigSubset sub 
)

Add the "start of forwarded message" text.

Parameters
eEmail
subConfig Subset
fpFile to write to

Definition at line 451 of file send.c.

452{
453 const char *const c_forward_attribution_intro = cs_subset_string(sub, "forward_attribution_intro");
454 if (!c_forward_attribution_intro || !fp)
455 return;
456
457 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
458
459 char buf[1024] = { 0 };
460 setlocale(LC_TIME, NONULL(c_attribution_locale));
461 mutt_make_string(buf, sizeof(buf), 0, c_forward_attribution_intro, NULL, -1,
462 e, MUTT_FORMAT_NO_FLAGS, NULL);
463 setlocale(LC_TIME, "");
464 fputs(buf, fp);
465 fputs("\n\n", fp);
466}
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
void mutt_make_string(char *buf, size_t buflen, int cols, const char *s, struct Mailbox *m, int inpgr, struct Email *e, MuttFormatFlags flags, const char *progress)
Create formatted strings using mailbox expandos.
Definition: hdrline.c:1443
#define NONULL(x)
Definition: string2.h:37
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_forward_trailer()

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

Add a "end of forwarded message" text.

Parameters
eEmail
subConfig Subset
fpFile to write to

Definition at line 474 of file send.c.

475{
476 const char *const c_forward_attribution_trailer = cs_subset_string(sub, "forward_attribution_trailer");
477 if (!c_forward_attribution_trailer || !fp)
478 return;
479
480 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
481
482 char buf[1024] = { 0 };
483 setlocale(LC_TIME, NONULL(c_attribution_locale));
484 mutt_make_string(buf, sizeof(buf), 0, c_forward_attribution_trailer, NULL, -1,
485 e, MUTT_FORMAT_NO_FLAGS, NULL);
486 setlocale(LC_TIME, "");
487 fputc('\n', fp);
488 fputs(buf, fp);
489 fputc('\n', fp);
490}
+ 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 501 of file send.c.

503{
504 CopyHeaderFlags chflags = CH_DECODE;
506
507 struct Message *msg = mx_msg_open(m, e->msgno);
508 if (!msg)
509 {
510 return -1;
511 }
514
515 const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
516 if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT) && c_forward_decode)
517 {
518 /* make sure we have the user's passphrase before proceeding... */
520 {
521 mx_msg_close(m, &msg);
522 return -1;
523 }
524 }
525
526 mutt_forward_intro(e, fp_out, sub);
527
528 if (c_forward_decode)
529 {
530 cmflags |= MUTT_CM_DECODE | MUTT_CM_CHARCONV;
531
532 const bool c_weed = cs_subset_bool(sub, "weed");
533 if (c_weed)
534 {
535 chflags |= CH_WEED | CH_REORDER;
536 cmflags |= MUTT_CM_WEED;
537 }
538 }
539
540 const bool c_forward_quote = cs_subset_bool(sub, "forward_quote");
541 if (c_forward_quote)
542 cmflags |= MUTT_CM_PREFIX;
543
544 mutt_copy_message(fp_out, e, msg, cmflags, chflags, 0);
545 mx_msg_close(m, &msg);
546 mutt_forward_trailer(e, fp_out, sub);
547 return 0;
548}
void mutt_parse_mime_message(struct Email *e, FILE *fp)
Parse a MIME email.
Definition: attachments.c:592
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:875
#define CH_DECODE
Do RFC2047 header decoding.
Definition: copy.h:54
#define MUTT_CM_WEED
Weed message/rfc822 attachment headers.
Definition: copy.h:41
#define MUTT_CM_PREFIX
Quote the header and body.
Definition: copy.h:37
#define MUTT_CM_DECODE
Decode the message body into text/plain.
Definition: copy.h:38
#define CH_WEED
Weed the headers?
Definition: copy.h:53
#define CH_REORDER
Re-order output of headers (specified by 'hdr_order')
Definition: copy.h:59
#define MUTT_CM_CHARCONV
Perform character set conversions.
Definition: copy.h:42
uint32_t CopyHeaderFlags
Flags for mutt_copy_header(), e.g. CH_UPDATE.
Definition: copy.h:50
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
uint16_t CopyMessageFlags
Flags for mutt_copy_message(), e.g. MUTT_CM_NOHEADER.
Definition: copy.h:34
bool crypt_valid_passphrase(SecurityFlags flags)
Check that we have a usable passphrase, ask if not.
Definition: crypt.c:133
void mutt_message_hook(struct Mailbox *m, struct Email *e, HookFlags type)
Perform a message hook.
Definition: hook.c:656
#define MUTT_MESSAGE_HOOK
message-hook: run before displaying a message
Definition: hook.h:45
int mx_msg_close(struct Mailbox *m, struct Message **msg)
Close a message.
Definition: mx.c:1200
struct Message * mx_msg_open(struct Mailbox *m, int msgno)
Return a stream pointer for a message.
Definition: mx.c:1154
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:116
void mutt_forward_intro(struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add the "start of forwarded message" text.
Definition: send.c:451
void mutt_forward_trailer(struct Email *e, FILE *fp, struct ConfigSubset *sub)
Add a "end of forwarded message" text.
Definition: send.c:474
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
int msgno
Number displayed to the user.
Definition: email.h:110
A local copy of an email.
Definition: mxapi.h:43
FILE * fp
pointer to the message data
Definition: mxapi.h:44
+ 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 560 of file send.c.

563{
564 struct Body **last = *plast;
565 struct Body *body = NULL;
566 struct AttachCtx *actx = NULL;
567 int rc = 0, i;
568
569 struct Message *msg = mx_msg_open(m, e->msgno);
570 if (!msg)
571 {
572 return -1;
573 }
574
577
578 actx = mutt_mem_calloc(1, sizeof(*actx));
579 actx->email = e;
580 actx->fp_root = msg->fp;
581
582 mutt_generate_recvattach_list(actx, actx->email, actx->email->body,
583 actx->fp_root, -1, 0, 0);
584
585 for (i = 0; i < actx->idxlen; i++)
586 {
587 body = actx->idx[i]->body;
588 if ((body->type != TYPE_MULTIPART) && mutt_prefer_as_attachment(body) &&
589 !((body->type == TYPE_APPLICATION) &&
590 (mutt_istr_equal(body->subtype, "pgp-signature") ||
591 mutt_istr_equal(body->subtype, "x-pkcs7-signature") ||
592 mutt_istr_equal(body->subtype, "pkcs7-signature"))))
593 {
594 /* Ask the quadoption only once */
595 if (*forwardq == MUTT_ABORT)
596 {
597 const enum QuadOption c_forward_attachments = cs_subset_quad(sub, "forward_attachments");
598 *forwardq = query_quadoption(c_forward_attachments,
599 /* L10N: This is the prompt for $forward_attachments.
600 When inline forwarding ($mime_forward answered "no"), this prompts
601 whether to add non-decodable attachments from the original email.
602 Text/plain parts and the like will already be included in the
603 message contents, but other attachment, such as PDF files, will also
604 be added as attachments to the new mail, if this is answered yes. */
605 _("Forward attachments?"));
606 if (*forwardq != MUTT_YES)
607 {
608 if (*forwardq == -1)
609 rc = -1;
610 goto cleanup;
611 }
612 }
613 if (mutt_body_copy(actx->idx[i]->fp, last, body) == -1)
614 {
615 rc = -1;
616 goto cleanup;
617 }
618 last = &((*last)->next);
619 }
620 }
621
622cleanup:
623 *plast = last;
624 mx_msg_close(m, &msg);
625 mutt_actx_free(&actx);
626 return rc;
627}
void mutt_actx_free(struct AttachCtx **ptr)
Free an Attachment Context.
Definition: attach.c:198
bool mutt_prefer_as_attachment(struct Body *b)
Do we want this part as an attachment?
Definition: handler.c:1833
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:819
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
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
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:1082
A set of attachments.
Definition: attach.h:51
FILE * fp_root
Used by recvattach for updating.
Definition: attach.h:53
struct Email * email
Used by recvattach for updating.
Definition: attach.h:52
struct AttachPtr ** idx
Array of attachments.
Definition: attach.h:55
short idxlen
Number of attachmentes.
Definition: attach.h:56
struct Body * body
Attachment.
Definition: attach.h:36
FILE * fp
Used in the recvattach menu.
Definition: attach.h:37
The body of an email.
Definition: body.h:36
char * subtype
content-type subtype
Definition: body.h:60
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
struct Body * body
List of MIME parts.
Definition: email.h:67
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ format_attribution()

static void format_attribution ( const char *  s,
struct Email e,
FILE *  fp_out,
struct ConfigSubset sub 
)
static

Format an attribution prefix/suffix.

Parameters
sString to format
eEmail
fp_outFile to write to
subConfig Subset

Definition at line 636 of file send.c.

638{
639 if (!s || !fp_out)
640 return;
641
642 const char *const c_attribution_locale = cs_subset_string(sub, "attribution_locale");
643
644 char buf[1024] = { 0 };
645 setlocale(LC_TIME, NONULL(c_attribution_locale));
646 mutt_make_string(buf, sizeof(buf), 0, s, NULL, -1, e, MUTT_FORMAT_NO_FLAGS, NULL);
647 setlocale(LC_TIME, "");
648 fputs(buf, fp_out);
649 fputc('\n', fp_out);
650}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_attribution_intro()

void mutt_make_attribution_intro ( struct Email e,
FILE *  fp_out,
struct ConfigSubset sub 
)

Add "on DATE, PERSON wrote" header.

Parameters
eEmail
fp_outFile to write to
subConfig Subset

Definition at line 658 of file send.c.

659{
660 format_attribution(cs_subset_string(sub, "attribution_intro"), e, fp_out, sub);
661}
static void format_attribution(const char *s, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Format an attribution prefix/suffix.
Definition: send.c:636
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_attribution_trailer()

void mutt_make_attribution_trailer ( struct Email e,
FILE *  fp_out,
struct ConfigSubset sub 
)

Add suffix to replied email text.

Parameters
eEmail
fp_outFile to write to
subConfig Subset

Definition at line 669 of file send.c.

670{
671 format_attribution(cs_subset_string(sub, "attribution_trailer"), e, fp_out, sub);
672}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_greeting()

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

Add greetings string.

Parameters
eEmail
fp_outFile to write to
subConfig Subset
See also
$greeting, greeting_format_str()

Definition at line 747 of file send.c.

748{
749 const char *const c_greeting = cs_subset_string(sub, "greeting");
750 if (!c_greeting || !fp_out)
751 return;
752
753 char buf[1024] = { 0 };
754
755 mutt_expando_format(buf, sizeof(buf), 0, 0, c_greeting, greeting_format_str,
756 (intptr_t) e, TOKEN_NO_FLAGS);
757
758 fputs(buf, fp_out);
759 fputc('\n', fp_out);
760}
#define TOKEN_NO_FLAGS
No flags are set.
Definition: extract.h:33
static const char * greeting_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, intptr_t data, MuttFormatFlags flags)
Format a greetings string - Implements format_t -.
Definition: send.c:683
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t callback, intptr_t data, MuttFormatFlags flags)
Expand expandos (x) in a string -.
Definition: muttlib.c:726
+ 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 771 of file send.c.

773{
775 CopyHeaderFlags chflags = CH_DECODE;
776
777 if ((WithCrypto != 0) && (e->security & SEC_ENCRYPT))
778 {
779 /* make sure we have the user's passphrase before proceeding... */
781 return -1;
782 }
783
784 struct Message *msg = mx_msg_open(m, e->msgno);
785 if (!msg)
786 {
787 return -1;
788 }
791
792 mutt_make_attribution_intro(e, fp_out, sub);
793
794 const bool c_header = cs_subset_bool(sub, "header");
795 if (!c_header)
796 cmflags |= MUTT_CM_NOHEADER;
797
798 const bool c_weed = cs_subset_bool(sub, "weed");
799 if (c_weed)
800 {
801 chflags |= CH_WEED | CH_REORDER;
802 cmflags |= MUTT_CM_WEED;
803 }
804
805 mutt_copy_message(fp_out, e, msg, cmflags, chflags, 0);
806 mx_msg_close(m, &msg);
807
808 mutt_make_attribution_trailer(e, fp_out, sub);
809
810 return 0;
811}
#define MUTT_CM_REPLYING
Replying the message.
Definition: copy.h:44
#define MUTT_CM_NOHEADER
Don't copy the message header.
Definition: copy.h:36
void mutt_make_attribution_intro(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add "on DATE, PERSON wrote" header.
Definition: send.c:658
void mutt_make_attribution_trailer(struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Add suffix to replied email text.
Definition: send.c:669
+ 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 820 of file send.c.

823{
824 const bool c_reply_self = cs_subset_bool(sub, "reply_self");
825 if (!c_reply_self && mutt_addr_is_user(from))
826 {
827 /* mail is from the user, assume replying to recipients */
828 return &env->to;
829 }
830 else
831 {
832 return &env->from;
833 }
834}
+ 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 846 of file send.c.

848{
849 const struct Address *from = TAILQ_FIRST(&env->from);
850 const struct Address *reply_to = TAILQ_FIRST(&env->reply_to);
851
852 if (flags && !TAILQ_EMPTY(&env->mail_followup_to) && (hmfupto == MUTT_YES))
853 {
854 mutt_addrlist_copy(to, &env->mail_followup_to, true);
855 return 0;
856 }
857
858 /* Exit now if we're setting up the default Cc list for list-reply
859 * (only set if Mail-Followup-To is present and honoured). */
860 if (flags & SEND_LIST_REPLY)
861 return 0;
862
863 const struct AddressList *default_to = choose_default_to(from, env, sub);
864
865 if (reply_to)
866 {
867 const bool from_is_reply_to = mutt_addr_cmp(from, reply_to);
868 const bool multiple_reply_to = reply_to &&
869 TAILQ_NEXT(TAILQ_FIRST(&env->reply_to), entries);
870
871 const bool c_ignore_list_reply_to = cs_subset_bool(sub, "ignore_list_reply_to");
872 const enum QuadOption c_reply_to = cs_subset_quad(sub, "reply_to");
873 if ((from_is_reply_to && !multiple_reply_to && !reply_to->personal) ||
874 (c_ignore_list_reply_to && mutt_is_mail_list(reply_to) &&
875 (mutt_addrlist_search(&env->to, reply_to) || mutt_addrlist_search(&env->cc, reply_to))))
876 {
877 /* If the Reply-To: address is a mailing list, assume that it was
878 * put there by the mailing list, and use the From: address
879 *
880 * We also take the from header if our correspondent has a reply-to
881 * header which is identical to the electronic mail address given
882 * in his From header, and the reply-to has no display-name. */
883 mutt_addrlist_copy(to, &env->from, false);
884 }
885 else if (!(from_is_reply_to && !multiple_reply_to) && (c_reply_to != MUTT_YES))
886 {
887 char prompt[256] = { 0 };
888 /* There are quite a few mailing lists which set the Reply-To:
889 * header field to the list address, which makes it quite impossible
890 * to send a message to only the sender of the message. This
891 * provides a way to do that. */
892 /* L10N: Asks whether the user respects the reply-to header.
893 If she says no, neomutt will reply to the from header's address instead. */
894 snprintf(prompt, sizeof(prompt), _("Reply to %s%s?"), reply_to->mailbox,
895 multiple_reply_to ? ",..." : "");
896 switch (query_quadoption(c_reply_to, prompt))
897 {
898 case MUTT_YES:
899 mutt_addrlist_copy(to, &env->reply_to, false);
900 break;
901
902 case MUTT_NO:
903 mutt_addrlist_copy(to, default_to, false);
904 break;
905
906 default:
907 return -1; /* abort */
908 }
909 }
910 else
911 {
912 mutt_addrlist_copy(to, &env->reply_to, false);
913 }
914 }
915 else
916 {
917 mutt_addrlist_copy(to, default_to, false);
918 }
919
920 return 0;
921}
void mutt_addrlist_copy(struct AddressList *dst, const struct AddressList *src, bool prune)
Copy a list of addresses into another list.
Definition: address.c:745
bool mutt_addr_cmp(const struct Address *a, const struct Address *b)
Compare two e-mail addresses.
Definition: address.c:872
bool mutt_addrlist_search(const struct AddressList *haystack, const struct Address *needle)
Search for an e-mail address in a list.
Definition: address.c:889
#define TAILQ_FIRST(head)
Definition: queue.h:723
static const struct AddressList * choose_default_to(const struct Address *from, const struct Envelope *env, struct ConfigSubset *sub)
Pick the best 'to:' value.
Definition: send.c:820
static int default_to(struct AddressList *to, struct Envelope *env, SendFlags flags, int hmfupto, struct ConfigSubset *sub)
Generate default email addresses.
Definition: send.c:846
char * mailbox
Mailbox and host address.
Definition: address.h:38
char * personal
Real name of address.
Definition: address.h:37
struct AddressList mail_followup_to
Email's 'mail-followup-to'.
Definition: envelope.h:65
+ 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 932 of file send.c.

934{
935 enum QuadOption hmfupto = MUTT_ABORT;
936 const struct Address *followup_to = TAILQ_FIRST(&in->mail_followup_to);
937
938 if ((flags & (SEND_LIST_REPLY | SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) && followup_to)
939 {
940 char prompt[256] = { 0 };
941 snprintf(prompt, sizeof(prompt), _("Follow-up to %s%s?"), followup_to->mailbox,
942 TAILQ_NEXT(TAILQ_FIRST(&in->mail_followup_to), entries) ? ",..." : "");
943
944 const enum QuadOption c_honor_followup_to = cs_subset_quad(sub, "honor_followup_to");
945 hmfupto = query_quadoption(c_honor_followup_to, prompt);
946 if (hmfupto == MUTT_ABORT)
947 return -1;
948 }
949
950 if (flags & SEND_LIST_REPLY)
951 {
952 add_mailing_lists(&out->to, &in->to, &in->cc);
953
954 if (followup_to && (hmfupto == MUTT_YES) &&
955 (default_to(&out->cc, in, flags & SEND_LIST_REPLY, (hmfupto == MUTT_YES), sub) == MUTT_ABORT))
956 {
957 return -1; /* abort */
958 }
959 }
960 else if (flags & SEND_TO_SENDER)
961 {
962 mutt_addrlist_copy(&out->to, &in->from, false);
963 }
964 else
965 {
966 if (default_to(&out->to, in, flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY),
967 (hmfupto == MUTT_YES), sub) == -1)
968 {
969 return -1; /* abort */
970 }
971
972 if ((flags & (SEND_GROUP_REPLY | SEND_GROUP_CHAT_REPLY)) &&
973 (!followup_to || (hmfupto != MUTT_YES)))
974 {
975 /* if(!mutt_addr_is_user(in->to)) */
976 if (flags & SEND_GROUP_REPLY)
977 mutt_addrlist_copy(&out->cc, &in->to, true);
978 else
979 mutt_addrlist_copy(&out->to, &in->to, true);
980 mutt_addrlist_copy(&out->cc, &in->cc, true);
981 }
982 }
983 return 0;
984}
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:151
#define SEND_GROUP_CHAT_REPLY
Reply to all recipients preserving To/Cc.
Definition: send.h:52
#define SEND_TO_SENDER
Compose new email to sender.
Definition: send.h:51
+ 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 991 of file send.c.

992{
993 struct ListNode *np = NULL;
994
995 struct ListHead *src = STAILQ_EMPTY(&env->references) ? &env->in_reply_to : &env->references;
996 STAILQ_FOREACH(np, src, entries)
997 {
999 }
1000}
#define STAILQ_EMPTY(head)
Definition: queue.h:348
struct ListHead references
message references (in reverse order)
Definition: envelope.h:85
struct ListHead in_reply_to
in-reply-to header content
Definition: envelope.h:86
+ 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 1007 of file send.c.

1008{
1009 if (env->message_id)
1010 {
1012 }
1013}
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 1020 of file send.c.

1021{
1022 const bool c_me_too = cs_subset_bool(sub, "me_too");
1023 if (!c_me_too)
1024 {
1025 const bool c_reply_self = cs_subset_bool(sub, "reply_self");
1026
1027 /* the order is important here. do the CC: first so that if the
1028 * the user is the only recipient, it ends up on the TO: field */
1029 remove_user(&env->cc, TAILQ_EMPTY(&env->to));
1030 remove_user(&env->to, TAILQ_EMPTY(&env->cc) || c_reply_self);
1031 }
1032
1033 /* the CC field can get cluttered, especially with lists */
1034 mutt_addrlist_dedupe(&env->to);
1035 mutt_addrlist_dedupe(&env->cc);
1036 mutt_addrlist_remove_xrefs(&env->to, &env->cc);
1037
1038 if (!TAILQ_EMPTY(&env->cc) && TAILQ_EMPTY(&env->to))
1039 {
1040 TAILQ_SWAP(&env->to, &env->cc, Address, entries);
1041 }
1042}
void mutt_addrlist_remove_xrefs(const struct AddressList *a, struct AddressList *b)
Remove cross-references.
Definition: address.c:1416
void mutt_addrlist_dedupe(struct AddressList *al)
Remove duplicate addresses.
Definition: address.c:1380
#define TAILQ_SWAP(head1, head2, type, field)
Definition: queue.h:859
static void remove_user(struct AddressList *al, bool leave_only)
Remove any address which matches the current user.
Definition: send.c:132
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_make_forward_subject()

void mutt_make_forward_subject ( struct Envelope env,
struct Email e,
struct ConfigSubset sub 
)

Create a subject for a forwarded email.

Parameters
envEnvelope for result
eEmail
subConfig Subset

Definition at line 1050 of file send.c.

1051{
1052 if (!env)
1053 return;
1054
1055 const char *const c_forward_format = cs_subset_string(sub, "forward_format");
1056
1057 char buf[256] = { 0 };
1058 /* set the default subject for the message. */
1059 mutt_make_string(buf, sizeof(buf), 0, NONULL(c_forward_format), NULL, -1, e,
1060 MUTT_FORMAT_NO_FLAGS, NULL);
1061 mutt_str_replace(&env->subject, buf);
1062}
+ 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 1070 of file send.c.

1072{
1073 if (!env || !curenv)
1074 return;
1075
1076 /* This takes precedence over a subject that might have
1077 * been taken from a List-Post header. Is that correct? */
1078 if (curenv->real_subj)
1079 {
1080 FREE(&env->subject);
1081 env->subject = mutt_mem_malloc(mutt_str_len(curenv->real_subj) + 5);
1082 sprintf(env->subject, "Re: %s", curenv->real_subj);
1083 }
1084 else if (!env->subject)
1085 {
1086 const char *const c_empty_subject = cs_subset_string(sub, "empty_subject");
1087 env->subject = mutt_str_dup(c_empty_subject);
1088 }
1089}
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:567
char * real_subj
Offset of the real subject.
Definition: envelope.h:71
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_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 1097 of file send.c.

1099{
1100 add_references(&env->references, curenv);
1101 add_message_id(&env->references, curenv);
1102 add_message_id(&env->in_reply_to, curenv);
1103
1104#ifdef USE_NNTP
1105 const bool c_x_comment_to = cs_subset_bool(sub, "x_comment_to");
1106 if (OptNewsSend && c_x_comment_to && !TAILQ_EMPTY(&curenv->from))
1108#endif
1109}
static void add_message_id(struct ListHead *head, struct Envelope *env)
Add the email's message ID to a list.
Definition: send.c:1007
static void add_references(struct ListHead *head, struct Envelope *env)
Add the email's references to a list.
Definition: send.c:991
const char * mutt_get_name(const struct Address *a)
Pick the best name to display from an address.
Definition: sort.c:136
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ make_reference_headers()

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

Generate reference headers for an email.

Parameters
elList of source Emails
envEnvelope for result
subConfig Subset

Definition at line 1117 of file send.c.

1119{
1120 if (!el || !env || STAILQ_EMPTY(el))
1121 return;
1122
1123 struct EmailNode *en = STAILQ_FIRST(el);
1124 bool single = !STAILQ_NEXT(en, entries);
1125
1126 if (!single)
1127 {
1128 STAILQ_FOREACH(en, el, entries)
1129 {
1130 mutt_add_to_reference_headers(env, en->email->env, sub);
1131 }
1132 }
1133 else
1134 {
1135 mutt_add_to_reference_headers(env, en->email->env, sub);
1136 }
1137
1138 /* if there's more than entry in In-Reply-To (i.e. message has multiple
1139 * parents), don't generate a References: header as it's discouraged by
1140 * RFC2822, sect. 3.6.4 */
1141 if (!single && !STAILQ_EMPTY(&env->in_reply_to) &&
1142 STAILQ_NEXT(STAILQ_FIRST(&env->in_reply_to), entries))
1143 {
1145 }
1146}
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:122
#define STAILQ_FIRST(head)
Definition: queue.h:350
#define STAILQ_NEXT(elm, field)
Definition: queue.h:400
void mutt_add_to_reference_headers(struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
Generate references for a reply email.
Definition: send.c:1097
List of Emails.
Definition: email.h:131
struct Email * email
Email in the list.
Definition: email.h:132
struct Envelope * env
Envelope information.
Definition: email.h:66
+ 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 EmailList *  el,
SendFlags  flags,
struct ConfigSubset sub 
)
static

Fill in some defaults for a new email.

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

Definition at line 1157 of file send.c.

1159{
1160 if (!el || STAILQ_EMPTY(el))
1161 return -1;
1162
1163 struct EmailNode *en = STAILQ_FIRST(el);
1164 bool single = !STAILQ_NEXT(en, entries);
1165
1166 struct Envelope *curenv = en->email->env;
1167 if (!curenv)
1168 return -1;
1169
1170 if (flags & (SEND_REPLY | SEND_TO_SENDER))
1171 {
1172#ifdef USE_NNTP
1173 if ((flags & SEND_NEWS))
1174 {
1175 /* in case followup set Newsgroups: with Followup-To: if it present */
1176 if (!env->newsgroups && !mutt_istr_equal(curenv->followup_to, "poster"))
1177 {
1178 env->newsgroups = mutt_str_dup(curenv->followup_to);
1179 }
1180 }
1181 else
1182#endif
1183 if (!single)
1184 {
1185 STAILQ_FOREACH(en, el, entries)
1186 {
1187 if (mutt_fetch_recips(env, en->email->env, flags, sub) == -1)
1188 return -1;
1189 }
1190 }
1191 else if (mutt_fetch_recips(env, curenv, flags, sub) == -1)
1192 return -1;
1193
1194 if ((flags & SEND_LIST_REPLY) && TAILQ_EMPTY(&env->to))
1195 {
1196 mutt_error(_("No mailing lists found"));
1197 return -1;
1198 }
1199
1200 if (flags & SEND_REPLY)
1201 {
1202 mutt_make_misc_reply_headers(env, curenv, sub);
1203 make_reference_headers(el, env, sub);
1204 }
1205 }
1206 else if (flags & SEND_FORWARD)
1207 {
1208 mutt_make_forward_subject(env, en->email, sub);
1209
1210 const bool c_forward_references = cs_subset_bool(sub, "forward_references");
1211 if (c_forward_references)
1212 make_reference_headers(el, env, sub);
1213 }
1214
1215 return 0;
1216}
void mutt_make_misc_reply_headers(struct Envelope *env, struct Envelope *curenv, struct ConfigSubset *sub)
Set subject for a reply.
Definition: send.c:1070
void mutt_make_forward_subject(struct Envelope *env, struct Email *e, struct ConfigSubset *sub)
Create a subject for a forwarded email.
Definition: send.c:1050
int mutt_fetch_recips(struct Envelope *out, struct Envelope *in, SendFlags flags, struct ConfigSubset *sub)
Generate recpients for a reply email.
Definition: send.c:932
static void make_reference_headers(struct EmailList *el, struct Envelope *env, struct ConfigSubset *sub)
Generate reference headers for an email.
Definition: send.c:1117
#define SEND_NEWS
Reply to a news article.
Definition: send.h:53
#define SEND_FORWARD
Forward email.
Definition: send.h:43
The header of an Email.
Definition: envelope.h:57
+ 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 1229 of file send.c.

1231{
1232 /* An EmailList is required for replying and forwarding */
1233 if (!el && (flags & (SEND_REPLY | SEND_FORWARD)))
1234 return -1;
1235
1236 if (flags & SEND_REPLY)
1237 {
1238 const enum QuadOption c_include = cs_subset_quad(sub, "include");
1239 enum QuadOption ans = query_quadoption(c_include, _("Include message in reply?"));
1240 if (ans == MUTT_ABORT)
1241 return -1;
1242
1243 if (ans == MUTT_YES)
1244 {
1245 mutt_message(_("Including quoted message..."));
1246 struct EmailNode *en = NULL;
1247 STAILQ_FOREACH(en, el, entries)
1248 {
1249 if (include_reply(m, en->email, fp_tmp, sub) == -1)
1250 {
1251 mutt_error(_("Could not include all requested messages"));
1252 return -1;
1253 }
1254 if (STAILQ_NEXT(en, entries) != NULL)
1255 {
1256 fputc('\n', fp_tmp);
1257 }
1258 }
1259 }
1260 }
1261 else if (flags & SEND_FORWARD)
1262 {
1263 const enum QuadOption c_mime_forward = cs_subset_quad(sub, "mime_forward");
1264 enum QuadOption ans = query_quadoption(c_mime_forward, _("Forward as attachment?"));
1265 if (ans == MUTT_YES)
1266 {
1267 struct Body *last = e->body;
1268
1269 mutt_message(_("Preparing forwarded message..."));
1270
1271 while (last && last->next)
1272 last = last->next;
1273
1274 struct EmailNode *en = NULL;
1275 STAILQ_FOREACH(en, el, entries)
1276 {
1277 struct Body *tmp = mutt_make_message_attach(m, en->email, false, sub);
1278 if (last)
1279 {
1280 last->next = tmp;
1281 last = tmp;
1282 }
1283 else
1284 {
1285 last = tmp;
1286 e->body = tmp;
1287 }
1288 }
1289 }
1290 else if (ans != MUTT_ABORT)
1291 {
1292 enum QuadOption forwardq = MUTT_ABORT;
1293 struct Body **last = NULL;
1294 struct EmailNode *en = NULL;
1295
1296 const bool c_forward_decode = cs_subset_bool(sub, "forward_decode");
1297 const enum QuadOption c_forward_attachments = cs_subset_quad(sub, "forward_attachments");
1298 if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1299 {
1300 last = &e->body;
1301 while (*last)
1302 last = &((*last)->next);
1303 }
1304
1305 STAILQ_FOREACH(en, el, entries)
1306 {
1307 struct Email *e_cur = en->email;
1308 include_forward(m, e_cur, fp_tmp, sub);
1309 if (c_forward_decode && (c_forward_attachments != MUTT_NO))
1310 {
1311 if (inline_forward_attachments(m, e_cur, &last, &forwardq, sub) != 0)
1312 return -1;
1313 }
1314 }
1315 }
1316 else
1317 {
1318 return -1;
1319 }
1320 }
1321 /* if (WithCrypto && (flags & SEND_KEY)) */
1322 else if (((WithCrypto & APPLICATION_PGP) != 0) && (flags & SEND_KEY))
1323 {
1324 struct Body *b = NULL;
1325
1326 if (((WithCrypto & APPLICATION_PGP) != 0) && !(b = crypt_pgp_make_key_attachment()))
1327 {
1328 return -1;
1329 }
1330
1331 b->next = e->body;
1332 e->body = b;
1333 }
1334
1336
1337 return 0;
1338}
struct Body * crypt_pgp_make_key_attachment(void)
Wrapper for CryptModuleSpecs::pgp_make_key_attachment()
Definition: cryptglue.c:305
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:73
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:90
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:771
static int include_forward(struct Mailbox *m, struct Email *e, FILE *fp_out, struct ConfigSubset *sub)
Write out a forwarded message.
Definition: send.c:501
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:560
#define SEND_KEY
Mail a PGP public key.
Definition: send.h:46
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:447
struct Body * next
next attachment in the list
Definition: body.h:71
The envelope/body of an email.
Definition: email.h:37
+ 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 1345 of file send.c.

1346{
1347 /* Only generate the Mail-Followup-To if the user has requested it, and
1348 * it hasn't already been set */
1349
1350 const bool c_followup_to = cs_subset_bool(sub, "followup_to");
1351 if (!c_followup_to)
1352 return;
1353#ifdef USE_NNTP
1354 if (OptNewsSend)
1355 {
1356 if (!env->followup_to && env->newsgroups && (strrchr(env->newsgroups, ',')))
1357 env->followup_to = mutt_str_dup(env->newsgroups);
1358 return;
1359 }
1360#endif
1361
1362 if (TAILQ_EMPTY(&env->mail_followup_to))
1363 {
1364 if (mutt_is_list_recipient(false, env))
1365 {
1366 /* this message goes to known mailing lists, so create a proper
1367 * mail-followup-to header */
1368
1369 mutt_addrlist_copy(&env->mail_followup_to, &env->to, false);
1370 mutt_addrlist_copy(&env->mail_followup_to, &env->cc, true);
1371 }
1372
1373 /* remove ourselves from the mail-followup-to header */
1374 remove_user(&env->mail_followup_to, false);
1375
1376 /* If we are not subscribed to any of the lists in question, re-add
1377 * ourselves to the mail-followup-to header. The mail-followup-to header
1378 * generated is a no-op with group-reply, but makes sure list-reply has the
1379 * desired effect. */
1380
1381 if (!TAILQ_EMPTY(&env->mail_followup_to) &&
1383 {
1384 struct AddressList *al = NULL;
1385 if (!TAILQ_EMPTY(&env->reply_to))
1386 al = &env->reply_to;
1387 else if (!TAILQ_EMPTY(&env->from))
1388 al = &env->from;
1389
1390 if (al)
1391 {
1392 struct Address *a = NULL;
1393 TAILQ_FOREACH_REVERSE(a, al, AddressList, entries)
1394 {
1396 }
1397 }
1398 else
1399 {
1401 }
1402 }
1403
1405 }
1406}
void mutt_addrlist_prepend(struct AddressList *al, struct Address *a)
Prepend an Address to an AddressList.
Definition: address.c:1474
bool mutt_is_subscribed_list_recipient(bool all_addr, struct Envelope *env)
Matches subscribed mailing lists.
Definition: exec.c:458
bool mutt_is_list_recipient(bool all_addr, struct Envelope *env)
Matches known mailing lists.
Definition: exec.c:471
#define TAILQ_FOREACH_REVERSE(var, head, headname, field)
Definition: queue.h:745
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1470
+ 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 1418 of file send.c.

1420{
1421 struct Address *a = NULL;
1422 if (TAILQ_EMPTY(al))
1423 {
1424 TAILQ_FOREACH(a, &env->to, entries)
1425 {
1426 if (mutt_addr_is_user(a))
1427 {
1429 break;
1430 }
1431 }
1432 }
1433
1434 if (TAILQ_EMPTY(al))
1435 {
1436 TAILQ_FOREACH(a, &env->cc, entries)
1437 {
1438 if (mutt_addr_is_user(a))
1439 {
1441 break;
1442 }
1443 }
1444 }
1445
1446 if (TAILQ_EMPTY(al))
1447 {
1448 struct Address *from = TAILQ_FIRST(&env->from);
1449 if (from && mutt_addr_is_user(from))
1450 {
1452 }
1453 }
1454
1455 if (!TAILQ_EMPTY(al))
1456 {
1457 /* when $reverse_real_name is not set, clear the personal name so that it
1458 * may be set via a reply- or send-hook. */
1459
1460 const bool c_reverse_real_name = cs_subset_bool(sub, "reverse_real_name");
1461 if (!c_reverse_real_name)
1462 FREE(&TAILQ_FIRST(al)->personal);
1463 }
1464}
+ 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 1470 of file send.c.

1471{
1472 /* Note: We let $from override $real_name here.
1473 * Is this the right thing to do?
1474 */
1475
1476 const struct Address *c_from = cs_subset_address(sub, "from");
1477 const bool c_use_domain = cs_subset_bool(sub, "use_domain");
1478 if (c_from)
1479 {
1480 return mutt_addr_copy(c_from);
1481 }
1482 else if (c_use_domain)
1483 {
1484 struct Address *addr = mutt_addr_new();
1485 mutt_str_asprintf(&addr->mailbox, "%s@%s", NONULL(Username),
1486 NONULL(mutt_fqdn(true, sub)));
1487 return addr;
1488 }
1489 else
1490 {
1491 return mutt_addr_create(NULL, Username);
1492 }
1493}
struct Address * mutt_addr_create(const char *personal, const char *mailbox)
Create and populate a new Address.
Definition: address.c:402
struct Address * mutt_addr_new(void)
Create a new Address.
Definition: address.c:389
const struct Address * cs_subset_address(const struct ConfigSubset *sub, const char *name)
Get an Address config item by name.
Definition: helpers.c:49
char * Username
User's login name.
Definition: globals.c:41
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition: string.c:1031
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:700
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ invoke_mta()

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

Send an email.

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

Definition at line 1503 of file send.c.

1504{
1505 struct Buffer *tempfile = NULL;
1506 int rc = -1;
1507
1508 /* Write out the message in MIME form. */
1509 tempfile = mutt_buffer_pool_get();
1510 mutt_buffer_mktemp(tempfile);
1511 FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfile), "w");
1512 if (!fp_tmp)
1513 goto cleanup;
1514
1515#ifdef USE_SMTP
1516 const bool c_write_bcc = cs_subset_bool(sub, "write_bcc");
1517 const char *const c_smtp_url = cs_subset_string(sub, "smtp_url");
1518 if (c_smtp_url)
1519 cs_subset_str_native_set(sub, "write_bcc", false, NULL);
1520#endif
1521#ifdef MIXMASTER
1523 !STAILQ_EMPTY(&e->chain),
1525#endif
1526#ifndef MIXMASTER
1528 false, mutt_should_hide_protected_subject(e), sub);
1529#endif
1530#ifdef USE_SMTP
1531 cs_subset_str_native_set(sub, "write_bcc", c_write_bcc, NULL);
1532#endif
1533
1534 fputc('\n', fp_tmp); /* tie off the header. */
1535
1536 if ((mutt_write_mime_body(e->body, fp_tmp, sub) == -1))
1537 goto cleanup;
1538
1539 if (mutt_file_fclose(&fp_tmp) != 0)
1540 {
1542 unlink(mutt_buffer_string(tempfile));
1543 goto cleanup;
1544 }
1545
1546#ifdef MIXMASTER
1547 if (!STAILQ_EMPTY(&e->chain))
1548 {
1549 rc = mix_send_message(&e->chain, mutt_buffer_string(tempfile));
1550 goto cleanup;
1551 }
1552#endif
1553
1554#ifdef USE_NNTP
1555 if (OptNewsSend)
1556 goto sendmail;
1557#endif
1558
1559#ifdef USE_SMTP
1560 if (c_smtp_url)
1561 {
1562 rc = mutt_smtp_send(&e->env->from, &e->env->to, &e->env->cc, &e->env->bcc,
1563 mutt_buffer_string(tempfile),
1564 (e->body->encoding == ENC_8BIT), sub);
1565 goto cleanup;
1566 }
1567#endif
1568
1569sendmail:
1570 rc = mutt_invoke_sendmail(m, &e->env->from, &e->env->to, &e->env->cc,
1571 &e->env->bcc, mutt_buffer_string(tempfile),
1572 (e->body->encoding == ENC_8BIT), sub);
1573cleanup:
1574 if (fp_tmp)
1575 {
1576 mutt_file_fclose(&fp_tmp);
1577 unlink(mutt_buffer_string(tempfile));
1578 }
1579 mutt_buffer_pool_release(&tempfile);
1580 return rc;
1581}
bool mutt_should_hide_protected_subject(struct Email *e)
Should NeoMutt hide the protected subject?
Definition: crypt.c:1079
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:634
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:571
@ MUTT_WRITE_HEADER_NORMAL
A normal Email, write full header + MIME headers.
Definition: header.h:40
@ ENC_8BIT
8-bit text
Definition: mime.h:50
int mix_send_message(struct ListHead *chain, const char *tempfile)
Send an email via Mixmaster.
Definition: mixmaster.c:102
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:318
int mutt_invoke_sendmail(struct Mailbox *m, struct AddressList *from, struct AddressList *to, struct AddressList *cc, struct AddressList *bcc, const char *msg, bool eightbit, struct ConfigSubset *sub)
Run sendmail.
Definition: sendmail.c:296
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:1096
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
struct ListHead chain
Mixmaster chain.
Definition: email.h:89
int cs_subset_str_native_set(const struct ConfigSubset *sub, const char *name, intptr_t value, struct Buffer *err)
Natively set the value of a string config item.
Definition: subset.c:305
#define mutt_buffer_mktemp(buf)
Definition: tmp.h:37
+ 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 1589 of file send.c.

1590{
1591 for (struct Body *t = b; t; t = t->next)
1592 {
1593 if (t->description)
1594 {
1595 const struct Slist *const c_send_charset = cs_subset_slist(sub, "send_charset");
1596 rfc2047_encode(&t->description, NULL, sizeof("Content-Description:"), c_send_charset);
1597 }
1598 if (recurse && t->parts)
1599 mutt_encode_descriptions(t->parts, recurse, sub);
1600 }
1601}
const struct Slist * cs_subset_slist(const struct ConfigSubset *sub, const char *name)
Get a string-list config item by name.
Definition: helpers.c:268
void rfc2047_encode(char **pd, const char *specials, int col, const struct Slist *charsets)
RFC-2047-encode a string.
Definition: rfc2047.c:625
void mutt_encode_descriptions(struct Body *b, bool recurse, struct ConfigSubset *sub)
RFC2047 encode the content-descriptions.
Definition: send.c:1589
String list.
Definition: slist.h:47
+ 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 1607 of file send.c.

1608{
1609 for (struct Body *t = b; t; t = t->next)
1610 {
1611 if (t->description)
1612 {
1613 rfc2047_decode(&t->description);
1614 }
1615 if (t->parts)
1616 decode_descriptions(t->parts);
1617 }
1618}
void rfc2047_decode(char **pd)
Decode any RFC2047-encoded header fields.
Definition: rfc2047.c:655
static void decode_descriptions(struct Body *b)
RFC2047 decode them in case of an error.
Definition: send.c:1607
+ 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 1624 of file send.c.

1625{
1626 FILE *fp = mutt_file_fopen(data, "a+");
1627 if (!fp)
1628 return;
1629
1630 if ((mutt_file_get_size_fp(fp) > 0) && mutt_file_seek(fp, -1, SEEK_END))
1631 {
1632 int c = fgetc(fp);
1633 if (c != '\n')
1634 fputc('\n', fp);
1635 }
1636 mutt_file_fclose(&fp);
1637}
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1556
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:708
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_resend_message()

int mutt_resend_message ( FILE *  fp,
struct Mailbox m,
struct Email e_cur,
struct ConfigSubset sub 
)

Resend an email.

Parameters
fpFile containing email
mMailbox
e_curEmail to resend
subConfig Subset
Return values
0Message was successfully sent
-1Message was aborted or an error occurred
1Message was postponed

Definition at line 1649 of file send.c.

1651{
1652 struct Email *e_new = email_new();
1653
1654 if (mutt_prepare_template(fp, m, e_new, e_cur, true) < 0)
1655 {
1656 email_free(&e_new);
1657 return -1;
1658 }
1659
1660 if (WithCrypto)
1661 {
1662 /* mutt_prepare_template doesn't always flip on an application bit.
1663 * so fix that here */
1664 if (!(e_new->security & (APPLICATION_SMIME | APPLICATION_PGP)))
1665 {
1666 const bool c_smime_is_default = cs_subset_bool(sub, "smime_is_default");
1667 if (((WithCrypto & APPLICATION_SMIME) != 0) && c_smime_is_default)
1668 e_new->security |= APPLICATION_SMIME;
1669 else if (WithCrypto & APPLICATION_PGP)
1670 e_new->security |= APPLICATION_PGP;
1671 else
1672 e_new->security |= APPLICATION_SMIME;
1673 }
1674
1675 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(sub, "crypt_opportunistic_encrypt");
1676 if (c_crypt_opportunistic_encrypt)
1677 {
1678 e_new->security |= SEC_OPPENCRYPT;
1680 }
1681 }
1682
1683 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
1684 emaillist_add_email(&el, e_cur);
1685 int rc = mutt_send_message(SEND_RESEND, e_new, NULL, m, &el, sub);
1686 emaillist_clear(&el);
1687
1688 return rc;
1689}
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1024
int emaillist_add_email(struct EmailList *el, struct Email *e)
Add an Email to a list.
Definition: email.c:159
struct Email * email_new(void)
Create a new Email.
Definition: email.c:78
void email_free(struct Email **ptr)
Free an Email.
Definition: email.c:44
void emaillist_clear(struct EmailList *el)
Drop a private list of Emails.
Definition: email.c:138
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
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:491
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
int mutt_send_message(SendFlags flags, struct Email *e_templ, const char *tempfile, struct Mailbox *m, struct EmailList *el, struct ConfigSubset *sub)
Send an email.
Definition: send.c:2137
#define SEND_RESEND
Reply using the current email as a template.
Definition: send.h:47
+ 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 1698 of file send.c.

1699{
1700 if (!reply || !reply->env || !orig || !orig->env)
1701 return false;
1702 return mutt_list_find(&orig->env->references, reply->env->message_id) ||
1703 mutt_list_find(&orig->env->in_reply_to, reply->env->message_id);
1704}
struct ListNode * mutt_list_find(const struct ListHead *h, const char *data)
Find a string in a List.
Definition: list.c:102
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ search_attach_keyword()

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

Search an email for 'attachment' keywords.

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

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

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

Definition at line 1717 of file send.c.

1718{
1719 const struct Regex *c_abort_noattach_regex = cs_subset_regex(sub, "abort_noattach_regex");
1720 const struct Regex *c_quote_regex = cs_subset_regex(sub, "quote_regex");
1721
1722 /* Search for the regex in `$abort_noattach_regex` within a file */
1723 if (!c_abort_noattach_regex || !c_abort_noattach_regex->regex ||
1724 !c_quote_regex || !c_quote_regex->regex)
1725 {
1726 return false;
1727 }
1728
1729 FILE *fp_att = mutt_file_fopen(filename, "r");
1730 if (!fp_att)
1731 return false;
1732
1733 char *inputline = mutt_mem_malloc(1024);
1734 bool found = false;
1735 while (!feof(fp_att))
1736 {
1737 fgets(inputline, 1024, fp_att);
1738 if (!mutt_is_quote_line(inputline, NULL) &&
1739 mutt_regex_match(c_abort_noattach_regex, inputline))
1740 {
1741 found = true;
1742 break;
1743 }
1744 }
1745 FREE(&inputline);
1746 mutt_file_fclose(&fp_att);
1747 return found;
1748}
const struct Regex * cs_subset_regex(const struct ConfigSubset *sub, const char *name)
Get a regex config item by name.
Definition: helpers.c:243
bool mutt_is_quote_line(char *line, regmatch_t *pmatch)
Is a line of message text a quote?
Definition: display.c:311
bool mutt_regex_match(const struct Regex *regex, const char *str)
Shorthand to mutt_regex_capture()
Definition: regex.c:635
Cached regular expression.
Definition: regex3.h:89
regex_t * regex
compiled expression
Definition: regex3.h:91
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ save_fcc()

static int save_fcc ( struct Mailbox m,
struct Email e,
struct Buffer fcc,
struct Body clear_content,
char *  pgpkeylist,
SendFlags  flags,
char **  finalpath,
struct ConfigSubset sub 
)
static

Save an Email to a 'sent mail' folder.

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

Definition at line 1763 of file send.c.

1766{
1767 int rc = 0;
1768 struct Body *save_content = NULL;
1769
1771
1772 /* Don't save a copy when we are in batch-mode, and the FCC
1773 * folder is on an IMAP server: This would involve possibly lots
1774 * of user interaction, which is not available in batch mode.
1775 *
1776 * Note: A patch to fix the problems with the use of IMAP servers
1777 * from non-curses mode is available from Brendan Cully. However,
1778 * I'd like to think a bit more about this before including it. */
1779
1780#ifdef USE_IMAP
1781 if ((flags & SEND_BATCH) && !mutt_buffer_is_empty(fcc) &&
1783 {
1784 mutt_error(_("Warning: Fcc to an IMAP mailbox is not supported in batch mode"));
1785 /* L10N: Printed after the "Fcc to an IMAP mailbox is not supported" message.
1786 To make it clearer that the message doesn't mean NeoMutt is aborting
1787 sending the mail too.
1788 %s is the full mailbox URL, including imap(s)://
1789 */
1790 mutt_error(_("Skipping Fcc to %s"), mutt_buffer_string(fcc));
1791 mutt_buffer_reset(fcc);
1792 return rc;
1793 }
1794#endif
1795
1796 if (mutt_buffer_is_empty(fcc) || mutt_str_equal("/dev/null", mutt_buffer_string(fcc)))
1797 return rc;
1798
1799 struct Body *tmpbody = e->body;
1800 struct Body *save_sig = NULL;
1801 struct Body *save_parts = NULL;
1802
1803 const bool c_fcc_before_send = cs_subset_bool(sub, "fcc_before_send");
1804 /* Before sending, we don't allow message manipulation because it
1805 * will break message signatures. This is especially complicated by
1806 * Protected Headers. */
1807 if (!c_fcc_before_send)
1808 {
1809 const bool c_fcc_clear = cs_subset_bool(sub, "fcc_clear");
1810 if ((WithCrypto != 0) &&
1811 (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) && c_fcc_clear)
1812 {
1813 e->body = clear_content;
1816 mutt_param_delete(&e->body->parameter, "protected-headers");
1817 }
1818
1819 const enum QuadOption c_fcc_attach = cs_subset_quad(sub, "fcc_attach");
1820
1821 /* check to see if the user wants copies of all attachments */
1822 bool save_atts = true;
1823 if (e->body->type == TYPE_MULTIPART)
1824 {
1825 /* In batch mode, save attachments if the quadoption is yes or ask-yes */
1826 if (flags & SEND_BATCH)
1827 {
1828 if ((c_fcc_attach == MUTT_NO) || (c_fcc_attach == MUTT_ASKNO))
1829 save_atts = false;
1830 }
1831 else if (query_quadoption(c_fcc_attach, _("Save attachments in Fcc?")) != MUTT_YES)
1832 save_atts = false;
1833 }
1834 if (!save_atts)
1835 {
1836 if ((WithCrypto != 0) && (e->security & (SEC_ENCRYPT | SEC_SIGN | SEC_AUTOCRYPT)) &&
1837 (mutt_str_equal(e->body->subtype, "encrypted") ||
1838 mutt_str_equal(e->body->subtype, "signed")))
1839 {
1840 if ((clear_content->type == TYPE_MULTIPART) &&
1841 (query_quadoption(c_fcc_attach, _("Save attachments in Fcc?")) != MUTT_YES))
1842 {
1843 if (!(e->security & SEC_ENCRYPT) && (e->security & SEC_SIGN))
1844 {
1845 /* save initial signature and attachments */
1846 save_sig = e->body->parts->next;
1847 save_parts = clear_content->parts->next;
1848 }
1849
1850 /* this means writing only the main part */
1851 e->body = clear_content->parts;
1852
1853 if (mutt_protect(e, pgpkeylist, false) == -1)
1854 {
1855 /* we can't do much about it at this point, so
1856 * fallback to saving the whole thing to fcc */
1857 e->body = tmpbody;
1858 save_sig = NULL;
1859 goto full_fcc;
1860 }
1861
1862 save_content = e->body;
1863 }
1864 }
1865 else
1866 {
1867 if (query_quadoption(c_fcc_attach, _("Save attachments in Fcc?")) != MUTT_YES)
1868 e->body = e->body->parts;
1869 }
1870 }
1871 }
1872
1873full_fcc:
1874 if (e->body)
1875 {
1876 /* update received time so that when storing to a mbox-style folder
1877 * the From_ line contains the current time instead of when the
1878 * message was first postponed. */
1879 e->received = mutt_date_now();
1880 rc = mutt_write_multiple_fcc(mutt_buffer_string(fcc), e, NULL, false, NULL,
1881 finalpath, sub);
1882 while (rc && !(flags & SEND_BATCH))
1883 {
1885 int choice = mutt_multi_choice(
1886 /* L10N: Called when saving to $record or Fcc failed after sending.
1887 (r)etry tries the same mailbox again.
1888 alternate (m)ailbox prompts for a different mailbox to try.
1889 (s)kip aborts saving. */
1890 _("Fcc failed. (r)etry, alternate (m)ailbox, or (s)kip?"),
1891 /* L10N: These correspond to the "Fcc failed" multi-choice prompt
1892 (r)etry, alternate (m)ailbox, or (s)kip.
1893 Any similarity to famous leaders of the FSF is coincidental. */
1894 _("rms"));
1895 switch (choice)
1896 {
1897 case 2: /* alternate (m)ailbox */
1898 /* L10N: This is the prompt to enter an "alternate (m)ailbox" when the
1899 initial Fcc fails. */
1900 rc = mutt_buffer_enter_fname(_("Fcc mailbox"), fcc, true, m, false,
1901 NULL, NULL, MUTT_SEL_NO_FLAGS);
1902 if ((rc == -1) || mutt_buffer_is_empty(fcc))
1903 {
1904 rc = 0;
1905 break;
1906 }
1907 /* fall through */
1908
1909 case 1: /* (r)etry */
1910 rc = mutt_write_multiple_fcc(mutt_buffer_string(fcc), e, NULL, false,
1911 NULL, finalpath, sub);
1912 break;
1913
1914 case -1: /* abort */
1915 case 3: /* (s)kip */
1916 rc = 0;
1917 break;
1918 }
1919 }
1920 }
1921
1922 if (!c_fcc_before_send)
1923 {
1924 e->body = tmpbody;
1925
1926 if ((WithCrypto != 0) && save_sig)
1927 {
1928 /* cleanup the second signature structures */
1929 if (save_content->parts)
1930 {
1931 mutt_body_free(&save_content->parts->next);
1932 save_content->parts = NULL;
1933 }
1934 mutt_body_free(&save_content);
1935
1936 /* restore old signature and attachments */
1937 e->body->parts->next = save_sig;
1938 e->body->parts->parts->next = save_parts;
1939 }
1940 else if ((WithCrypto != 0) && save_content)
1941 {
1942 /* destroy the new encrypted body. */
1943 mutt_body_free(&save_content);
1944 }
1945 }
1946
1947 return 0;
1948}
#define MUTT_SEL_NO_FLAGS
No flags are set.
Definition: lib.h:55
int mutt_protect(struct Email *e, char *keylist, bool postpone)
Encrypt and/or sign a message.
Definition: crypt.c:158
int mutt_buffer_enter_fname(const char *prompt, struct Buffer *fname, bool mailbox, struct Mailbox *m, bool multiple, char ***files, int *numfiles, SelectFileFlags flags)
Ask the user to select a file.
Definition: curs_lib.c:444
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:432
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2425
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:325
#define SEC_AUTOCRYPT
(Autocrypt) Message will be, or was Autocrypt encrypt+signed
Definition: lib.h:87
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
void mutt_param_delete(struct ParameterList *pl, const char *attribute)
Delete a matching Parameter.
Definition: parameter.c:142
@ MUTT_ASKNO
Ask the user, defaulting to 'No'.
Definition: quad.h:40
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:54
#define SEND_BATCH
Send email in batch mode (without user interaction)
Definition: send.h:45
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:1002
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:75
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
time_t received
Time when the message was placed in the mailbox.
Definition: email.h:59
+ 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 1960 of file send.c.

1962{
1963 char *pgpkeylist = NULL;
1964 const char *encrypt_as = NULL;
1965 struct Body *clear_content = NULL;
1966
1967 const char *const c_postponed = cs_subset_string(sub, "postponed");
1968 if (!c_postponed)
1969 {
1970 mutt_error(_("Can't postpone. $postponed is unset"));
1971 return -1;
1972 }
1973
1974 if (e_post->body->next)
1975 e_post->body = mutt_make_multipart(e_post->body);
1976
1977 mutt_encode_descriptions(e_post->body, true, sub);
1978
1979 const bool c_postpone_encrypt = cs_subset_bool(sub, "postpone_encrypt");
1980 if ((WithCrypto != 0) && c_postpone_encrypt &&
1981 (e_post->security & (SEC_ENCRYPT | SEC_AUTOCRYPT)))
1982 {
1983 if (((WithCrypto & APPLICATION_PGP) != 0) && (e_post->security & APPLICATION_PGP))
1984 {
1985 const char *const c_pgp_default_key = cs_subset_string(sub, "pgp_default_key");
1986 encrypt_as = c_pgp_default_key;
1987 }
1988 else if (((WithCrypto & APPLICATION_SMIME) != 0) && (e_post->security & APPLICATION_SMIME))
1989 {
1990 const char *const c_smime_default_key = cs_subset_string(sub, "smime_default_key");
1991 encrypt_as = c_smime_default_key;
1992 }
1993 if (!encrypt_as)
1994 {
1995 const char *const c_postpone_encrypt_as = cs_subset_string(sub, "postpone_encrypt_as");
1996 encrypt_as = c_postpone_encrypt_as;
1997 }
1998
1999#ifdef USE_AUTOCRYPT
2000 if (e_post->security & SEC_AUTOCRYPT)
2001 {
2003 {
2004 if (mutt_istr_equal(e_post->body->subtype, "mixed"))
2005 e_post->body = mutt_remove_multipart(e_post->body);
2006 decode_descriptions(e_post->body);
2007 mutt_error(_("Error encrypting message. Check your crypt settings."));
2008 return -1;
2009 }
2010 encrypt_as = AutocryptDefaultKey;
2011 }
2012#endif
2013
2014 if (encrypt_as)
2015 {
2016 pgpkeylist = mutt_str_dup(encrypt_as);
2017 clear_content = e_post->body;
2018 if (mutt_protect(e_post, pgpkeylist, true) == -1)
2019 {
2020 FREE(&pgpkeylist);
2021 if (mutt_istr_equal(e_post->body->subtype, "mixed"))
2022 e_post->body = mutt_remove_multipart(e_post->body);
2023 decode_descriptions(e_post->body);
2024 mutt_error(_("Error encrypting message. Check your crypt settings."));
2025 return -1;
2026 }
2027
2028 FREE(&pgpkeylist);
2029
2030 mutt_encode_descriptions(e_post->body, false, sub);
2031 }
2032 }
2033
2034 /* make sure the message is written to the right part of a maildir
2035 * postponed folder. */
2036 e_post->read = false;
2037 e_post->old = false;
2038
2039 mutt_prepare_envelope(e_post->env, false, sub);
2040 mutt_env_to_intl(e_post->env, NULL, NULL); /* Handle bad IDNAs the next time. */
2041
2042 if (mutt_write_fcc(NONULL(c_postponed), e_post,
2043 (e_cur && (flags & SEND_REPLY)) ? e_cur->env->message_id : NULL,
2044 true, fcc, NULL, sub) < 0)
2045 {
2046 if (clear_content)
2047 {
2048 mutt_body_free(&e_post->body);
2049 e_post->body = clear_content;
2050 }
2051 mutt_env_free(&e_post->body->mime_headers); /* protected headers */
2052 mutt_param_delete(&e_post->body->parameter, "protected-headers");
2053 if (mutt_istr_equal(e_post->body->subtype, "mixed"))
2054 e_post->body = mutt_remove_multipart(e_post->body);
2055 decode_descriptions(e_post->body);
2057 return -1;
2058 }
2059
2061
2062 if (clear_content)
2063 mutt_body_free(&clear_content);
2064
2065 return 0;
2066}
char * AutocryptDefaultKey
Autocrypt default key id (used for postponing messages)
Definition: config.c:36
int mutt_autocrypt_set_sign_as_default_key(struct Email *e)
Set the Autocrypt default key for signing.
Definition: autocrypt.c:704
int mutt_env_to_intl(struct Envelope *env, const char **tag, char **err)
Convert an Envelope's Address fields to Punycode format.
Definition: envelope.c:328
struct Body * mutt_remove_multipart(struct Body *b)
Extract the multipart body if it exists.
Definition: multipart.c:126
struct Body * mutt_make_multipart(struct Body *b)
Create a multipart email.
Definition: multipart.c:100
void mutt_update_num_postponed(void)
Force the update of the number of postponed messages.
Definition: postpone.c:185
void mutt_unprepare_envelope(struct Envelope *env)
Undo the encodings of mutt_prepare_envelope()
Definition: sendlib.c:812
void mutt_prepare_envelope(struct Envelope *env, bool final, struct ConfigSubset *sub)
Prepare an email header.
Definition: sendlib.c:773
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:1050
bool read
Email is read.
Definition: email.h:48
bool old
Email is seen, but unread.
Definition: email.h:47
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ is_text_plain()

static bool is_text_plain ( const struct Body b)
static

Is a Body a text/plain MIME part?

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

Definition at line 2074 of file send.c.

2075{
2076 return (b->type == TYPE_TEXT) && mutt_istr_equal(b->subtype, "plain");
2077}
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ abort_for_missing_attachments()

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

Should we abort sending because of missing attachments?

Parameters
bBody
subConfig Subset
Return values
Abortbecause of missing attachments

Definition at line 2085 of file send.c.

2086{
2087 const enum QuadOption c_abort_noattach = cs_subset_quad(sub, "abort_noattach");
2088
2089 if (c_abort_noattach == MUTT_NO)
2090 return false;
2091
2092 if (b->next)
2093 return false;
2094
2095 bool has_keyword = false;
2096
2097 /* search text/plain parts, whether they are main or alternative parts */
2098 if (is_text_plain(b))
2099 {
2100 has_keyword |= search_attach_keyword(b->filename, sub);
2101 }
2102 else
2103 {
2104 for (b = b->parts; b; b = b->next)
2105 {
2106 if (is_text_plain(b))
2107 {
2108 has_keyword |= search_attach_keyword(b->filename, sub);
2109 }
2110 }
2111 }
2112
2113 if (!has_keyword)
2114 return false;
2115
2116 if (c_abort_noattach == MUTT_YES)
2117 {
2118 mutt_error(_("Message contains text matching \"$abort_noattach_regex\". Not sending."));
2119 return true;
2120 }
2121
2122 return query_quadoption(c_abort_noattach, _("No attachments, cancel sending?")) != MUTT_NO;
2123}
static bool search_attach_keyword(char *filename, struct ConfigSubset *sub)
Search an email for 'attachment' keywords.
Definition: send.c:1717
static bool is_text_plain(const struct Body *b)
Is a Body a text/plain MIME part?
Definition: send.c:2074
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_send_message()

int mutt_send_message ( SendFlags  flags,
struct Email e_templ,
const char *  tempfile,
struct Mailbox m,
struct EmailList *  el,
struct ConfigSubset sub 
)

Send an email.

Parameters
flagsSend mode, see SendFlags
e_templTemplate to use for new message
tempfileFile specified by -i or -H
mCurrent mailbox
elList of Emails to send
subConfig Subset
Return values
0Message was successfully sent
-1Message was aborted or an error occurred
1Message was postponed

Definition at line 2137 of file send.c.

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

◆ send_simple_email()

static bool send_simple_email ( struct Mailbox m,
struct EmailList *  el,
const char *  mailto,
const char *  subj,
const char *  body 
)
static

Compose an email given a few basic ingredients.

Parameters
mMailbox
elList of source Emails
mailtomailto address to parse (can include fields such as subject)
subjSubject, if not overridden by mailto
bodytext/plain body
Return values
trueSuccess
falseFailure

Definition at line 3002 of file send.c.

3004{
3005 struct Email *e = email_new();
3006
3007 /* envelope */
3008 e->env = mutt_env_new();
3009 mutt_parse_mailto(e->env, NULL, mailto);
3010 if (!e->env->subject)
3011 {
3012 e->env->subject = mutt_str_dup(subj);
3013 }
3014 if (TAILQ_EMPTY(&e->env->to) && !mutt_addrlist_parse(&e->env->to, NULL))
3015 {
3016 mutt_warning(_("No recipient specified"));
3017 }
3018
3019 /* body */
3020 e->body = mutt_body_new();
3021 char ctype[] = "text/plain";
3022 mutt_parse_content_type(ctype, e->body);
3023
3024 char tempfile[PATH_MAX] = { 0 };
3025 mutt_mktemp(tempfile, sizeof(tempfile));
3026 if (body)
3027 {
3028 FILE *fp = mutt_file_fopen(tempfile, "w+");
3029 if (!fp)
3030 {
3031 email_free(&e);
3032 return false;
3033 }
3034 fprintf(fp, "%s\n", body);
3035 mutt_file_fclose(&fp);
3036 }
3037 e->body->filename = mutt_str_dup(tempfile);
3038 e->body->unlink = true;
3039
3040 const int rc = mutt_send_message(SEND_DRAFT_FILE, e, NULL, m, el, NeoMutt->sub);
3041 return rc >= 0;
3042}
#define PATH_MAX
Definition: mutt.h:41
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_send_list_subscribe()

bool mutt_send_list_subscribe ( struct Mailbox m,
struct Email e 
)

Send a mailing-list subscription email.

Parameters
mMailbox
eEmail carrying mailing-list subscription headers
Return values
trueSuccess
falseFailure

Definition at line 3051 of file send.c.

3052{
3053 if (!e || !e->env)
3054 {
3055 return false;
3056 }
3057
3058 const char *mailto = e->env->list_subscribe;
3059 if (!mailto)
3060 {
3061 mutt_warning(_("No List-Subscribe header found"));
3062 return false;
3063 }
3064
3065 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3066 emaillist_add_email(&el, e);
3067 bool rc = send_simple_email(m, &el, mailto, "Subscribe", "subscribe");
3068 emaillist_clear(&el);
3069
3070 return rc;
3071}
static bool send_simple_email(struct Mailbox *m, struct EmailList *el, const char *mailto, const char *subj, const char *body)
Compose an email given a few basic ingredients.
Definition: send.c:3002
char * list_subscribe
This stores a mailto URL, or nothing.
Definition: envelope.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_send_list_unsubscribe()

bool mutt_send_list_unsubscribe ( struct Mailbox m,
struct Email e 
)

Send a mailing-list unsubscription email.

Parameters
mMailbox
eEmail carrying mailing-list unsubscription headers
Return values
trueSuccess
falseFailure

Definition at line 3080 of file send.c.

3081{
3082 if (!e || !e->env)
3083 {
3084 return false;
3085 }
3086
3087 const char *mailto = e->env->list_unsubscribe;
3088 if (!mailto)
3089 {
3090 mutt_warning(_("No List-Unsubscribe header found"));
3091 return false;
3092 }
3093
3094 struct EmailList el = STAILQ_HEAD_INITIALIZER(el);
3095 emaillist_add_email(&el, e);
3096 bool rc = send_simple_email(m, &el, mailto, "Unsubscribe", "unsubscribe");
3097 emaillist_clear(&el);
3098
3099 return rc;
3100}
char * list_unsubscribe
This stores a mailto URL, or nothing.
Definition: envelope.h:69
+ Here is the call graph for this function:
+ Here is the caller graph for this function: